001: /*
002: * Copyright (c) 2001 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: * @Author: Silvere Martin-Michiellot
032: *
033: */
034:
035: package com.db.server;
036:
037: import javax.jdo.*;
038: import java.util.HashSet;
039: import javax.media.j3d.*;
040: import java.util.*;
041:
042: import com.db.hanim.*;
043:
044: /**
045: */
046:
047: public abstract class Skin extends ObjectWorld {
048:
049: //please use the fields from this class and not the fields from objectWorld when a duplicate exists
050:
051: //copied from objectWorld: Start
052:
053: //Lords and self are always allowed full rights
054:
055: public final static int NO_CAPABILITY = 0;
056:
057: public final static int SALABLE = 1;
058: public final static int RESHAPEABLE = 2;
059: public final static int SOUNDALTERABLE = 4;
060: public final static int VISIBLE = 8;
061: public final static int SONORE = 16;
062: public final static int MOVABLE = 32;
063: public final static int COLLIDABLE = 64;
064: public final static int INVENTORIZABLE = 128;
065: public final static int ACCESSORY = 256;
066: public final static int CUTABLE = 512;
067: public final static int GLUABLE = 1024;
068: public final static int DUPLICABLE = 2048;
069:
070: //copied from objectWorld: End
071:
072: public static final int HANDS = 4096;
073:
074: //copied from objectWorld: Start
075:
076: private static int LAST_CAPABILITY = (Skin.HANDS * 2) - 1;
077:
078: public static int DEFAULT_DESIGNER_CAPABILITIES = Skin.LAST_CAPABILITY;
079:
080: /**
081: * "Geometry description": (subclass of 3D Object)
082: * owner's current position and orientation
083: * skin (joint and segments replicating the H-Anim specification)
084: * accessories (visible and audible tools worn on the body but accessible from the inventory) and their relative positions and orientations on the skin.
085: * verbals (words that can be pronounced by the avatar's skin mouth as skin deformation and sound emission)
086: * movements (overall body movements)
087: * gestures (particular joint and segment combination movements without global movement)
088: * Sound description (sounds that correspond to movements or sound of voice) (sounds from accessories are managed by the accessory itself) (subclass of 3D Object)
089: * Capabilities (4 booleans grant access for invited lords, peers, peers vassals and vassals) (ancestors of a user can always collide, see and hear a user if they have requested so):
090: * collidable
091: * visible
092: * sonore
093: * hands (automatically accept to shake hands, but still requires that another user that wants to shake bounces into the avatar)
094: */
095:
096: private Humanoid humanoid;
097: //movements are treated as gestures
098: //in fact it is exactly the opposite (a gesture is a 0 movement of the root joint)
099: private HashSet gestures;
100: private HashSet accessories;
101: private HashSet verbals;
102:
103: //accepted call but nearly meaningless unless inheriting class defines the humanoid and the gestures
104: //(recommended practice) (concordance between humanoid and gestures is not checked)
105: public Skin(UniverseServer universeServer, Avatar userOwner) {
106:
107: super (universeServer, userOwner);
108:
109: }
110:
111: //owner is the owner of this Skin
112: //the owner may not wear this Skin however
113: //see addGesture about conditions on gestures
114: public Skin(UniverseServer universeServer, Avatar userOwner,
115: Humanoid humanoid, HashSet gestures) {
116:
117: super (universeServer, userOwner);
118: this .setHumanoid(humanoid);
119: this .setGestures(gestures);
120: this .verbals = null;
121:
122: }
123:
124: //status of skin is different from avatar status
125:
126: private Switch animationSwitch;
127: private BranchGroup verbalsBranchGroup;
128:
129: public final void setGeometryDescription(Node object) {
130:
131: BranchGroup branchGroup;
132: Switch animationSwitch;
133: BranchGroup verbalsBranchGroup;
134: Iterator iterator;
135:
136: branchGroup = new BranchGroup();
137:
138: if (this .getHumanoid() != null) {
139:
140: branchGroup
141: .setCapability(javax.media.j3d.Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
142: branchGroup
143: .setCapability(javax.media.j3d.Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
144: branchGroup
145: .setCapability(javax.media.j3d.Node.ALLOW_BOUNDS_READ);
146: branchGroup
147: .setCapability(javax.media.j3d.Node.ALLOW_BOUNDS_WRITE);
148: branchGroup
149: .setCapability(javax.media.j3d.Node.ALLOW_COLLIDABLE_READ);
150: branchGroup
151: .setCapability(javax.media.j3d.Node.ALLOW_COLLIDABLE_WRITE);
152: branchGroup
153: .setCapability(javax.media.j3d.Node.ALLOW_LOCAL_TO_VWORLD_READ);
154: branchGroup
155: .setCapability(javax.media.j3d.Node.ALLOW_PICKABLE_READ);
156: branchGroup
157: .setCapability(javax.media.j3d.Node.ALLOW_PICKABLE_WRITE);
158: branchGroup
159: .setCapability(javax.media.j3d.Node.ENABLE_COLLISION_REPORTING);
160: branchGroup
161: .setCapability(javax.media.j3d.Node.ENABLE_PICK_REPORTING);
162: branchGroup
163: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_EXTEND);
164: branchGroup
165: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_READ);
166: branchGroup
167: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_WRITE);
168: branchGroup
169: .setCapability(javax.media.j3d.Group.ALLOW_COLLISION_BOUNDS_READ);
170: branchGroup
171: .setCapability(javax.media.j3d.Group.ALLOW_COLLISION_BOUNDS_WRITE);
172: branchGroup
173: .setCapability(javax.media.j3d.BranchGroup.ALLOW_DETACH);
174:
175: animationSwitch = new Switch(0);
176:
177: animationSwitch
178: .setCapability(javax.media.j3d.Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
179: animationSwitch
180: .setCapability(javax.media.j3d.Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
181: animationSwitch
182: .setCapability(javax.media.j3d.Node.ALLOW_BOUNDS_READ);
183: animationSwitch
184: .setCapability(javax.media.j3d.Node.ALLOW_BOUNDS_WRITE);
185: animationSwitch
186: .setCapability(javax.media.j3d.Node.ALLOW_COLLIDABLE_READ);
187: animationSwitch
188: .setCapability(javax.media.j3d.Node.ALLOW_COLLIDABLE_WRITE);
189: animationSwitch
190: .setCapability(javax.media.j3d.Node.ALLOW_LOCAL_TO_VWORLD_READ);
191: animationSwitch
192: .setCapability(javax.media.j3d.Node.ALLOW_PICKABLE_READ);
193: animationSwitch
194: .setCapability(javax.media.j3d.Node.ALLOW_PICKABLE_WRITE);
195: animationSwitch
196: .setCapability(javax.media.j3d.Node.ENABLE_COLLISION_REPORTING);
197: animationSwitch
198: .setCapability(javax.media.j3d.Node.ENABLE_PICK_REPORTING);
199: animationSwitch
200: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_EXTEND);
201: animationSwitch
202: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_READ);
203: animationSwitch
204: .setCapability(javax.media.j3d.Group.ALLOW_CHILDREN_WRITE);
205: animationSwitch
206: .setCapability(javax.media.j3d.Group.ALLOW_COLLISION_BOUNDS_READ);
207: animationSwitch
208: .setCapability(javax.media.j3d.Group.ALLOW_COLLISION_BOUNDS_WRITE);
209: animationSwitch
210: .setCapability(javax.media.j3d.Switch.ALLOW_SWITCH_READ);
211: animationSwitch
212: .setCapability(javax.media.j3d.Switch.ALLOW_SWITCH_WRITE);
213:
214: iterator = gestures.iterator();
215: while (iterator.hasNext()) {
216: animationSwitch.addChild(((Gesture) iterator.next())
217: .getBranchGroup());
218: }
219:
220: //branchgroup is extracted from a cache in the humanoid
221: branchGroup.addChild(this .getHumanoid().getBranchGroup());
222: //Displacement duration set to 1000ms
223: verbalsBranchGroup = new Displacement(this .humanoid, 1000,
224: -1).getDisplacements();
225: branchGroup.addChild(verbalsBranchGroup);
226: branchGroup.addChild(animationSwitch);
227: }
228:
229: super .setGeometryDescription(branchGroup);
230:
231: }
232:
233: //position of geometry corresponds to root joint position
234: public final Humanoid getHumanoid() {
235:
236: return this .humanoid;
237:
238: }
239:
240: //this actually reset gestures and verbals (which are bound to humanoid)
241: //capabilities ObjectWorld.RESHAPEABLE
242: public final void setHumanoid(Humanoid humanoid) {
243:
244: if (this .checkWritable(ObjectWorld.RESHAPEABLE)) {
245:
246: this .humanoid = humanoid;
247: this .gestures = null;
248: this .verbals = null;
249:
250: }
251:
252: }
253:
254: public final void setTransform3D(Transform3D transform3D) {
255:
256: Transform3D currentTransform3D;
257: Iterator iterator;
258: ObjectWorld objectWorld;
259: Avatar wearer;
260: Transform3D partialTransform3D;
261:
262: if (this .checkWritable(ObjectWorld.MOVABLE)) {
263:
264: currentTransform3D = new Transform3D(this .getTransform3D());
265:
266: super .setTransform3D(transform3D);
267:
268: //wearer = this.getWearer(); useless since weare is always owner
269: wearer = this .getUserOwner();
270:
271: if (this .getTransform3D() != currentTransform3D) {
272: //also move objects in inventory and accessories
273: iterator = this .getAccessories().iterator();
274: while (iterator.hasNext()) {
275: objectWorld = (ObjectWorld) iterator.next();
276: partialTransform3D = new Transform3D();
277: partialTransform3D.sub(this .getTransform3D(),
278: currentTransform3D);
279: partialTransform3D
280: .add(objectWorld.getTransform3D());
281: objectWorld.setTransform3D(partialTransform3D);
282: }
283:
284: iterator = wearer.getInventory().iterator();
285: while (iterator.hasNext()) {
286: objectWorld = (ObjectWorld) iterator.next();
287: partialTransform3D = new Transform3D();
288: partialTransform3D.sub(this .getTransform3D(),
289: currentTransform3D);
290: partialTransform3D
291: .add(objectWorld.getTransform3D());
292: objectWorld.setTransform3D(partialTransform3D);
293: }
294:
295: }
296:
297: if (this .checkWritable(Skin.HANDS)) {
298:
299: //do shake hands
300: Transaction transaction;
301: Extent extent;
302: Query query;
303: String filter;
304: Collection collection;
305: Collection collection1;
306: Collection collection2;
307: IDCard iDCard1;
308: IDCard iDCard2;
309: //Iterator iterator;
310: //ObjectWorld objectWorld;
311:
312: try {
313: transaction = this .getPersistenceManager()
314: .currentTransaction();
315: transaction.begin();
316:
317: extent = this .getPersistenceManager().getExtent(
318: ObjectWorld.class, true);
319: filter = new String(
320: "SELECT * FROM ObjectWorld o WHERE o.getGeometryBounds().intersects(this.getGeometryBounds())");
321: query = this .getPersistenceManager().newQuery(
322: ObjectWorld.class, extent, filter);
323: collection = (Collection) query.execute();
324:
325: transaction.commit();
326:
327: iterator = collection.iterator();
328:
329: while (iterator.hasNext()) {
330: objectWorld = (ObjectWorld) iterator.next();
331:
332: //good for Skin.HANDS for this and ObjectWorld
333:
334: if (objectWorld instanceof Skin) {
335:
336: try {
337: transaction = this
338: .getPersistenceManager()
339: .currentTransaction();
340: transaction.begin();
341:
342: extent = this .getPersistenceManager()
343: .getExtent(ObjectWorld.class,
344: true);
345: filter = new String(
346: "SELECT ObjectWorld FROM ObjectWorld o WHERE o.getClass()==IDCard.class AND o.getUserOwner()==wearer");
347: query = this .getPersistenceManager()
348: .newQuery(ObjectWorld.class,
349: extent, filter);
350: collection1 = (Collection) query
351: .execute();
352:
353: transaction.commit();
354:
355: //find the first wallet
356: if (collection1.size() > 0) {
357: iDCard1 = (IDCard) collection1
358: .iterator().next();
359: iDCard1.addEntry(objectWorld
360: .getUserOwner());
361: //we should may be call for a database refresh
362: } else {
363: iDCard1 = new IDCard(this
364: .getUniverseServer(), this
365: .getUserOwner());
366: iDCard1.addEntry(objectWorld
367: .getUserOwner());
368: try {
369: transaction = this
370: .getPersistenceManager()
371: .currentTransaction();
372: transaction.begin();
373:
374: this
375: .getPersistenceManager()
376: .makePersistent(iDCard1);
377:
378: transaction.commit();
379: } catch (Exception exception) {
380: }
381: wearer.addInventoryEntry(iDCard1);
382: //we should may be call for a database refresh
383: }
384:
385: } catch (Exception exception) {
386: }
387:
388: try {
389: transaction = this
390: .getPersistenceManager()
391: .currentTransaction();
392: transaction.begin();
393:
394: extent = this .getPersistenceManager()
395: .getExtent(ObjectWorld.class,
396: true);
397: filter = new String(
398: "SELECT ObjectWorld FROM ObjectWorld o WHERE o.getClass()==IDCard.class AND o.getUserOwner()==objectWorld.getUserOwner()");
399: query = this .getPersistenceManager()
400: .newQuery(ObjectWorld.class,
401: extent, filter);
402: collection2 = (Collection) query
403: .execute();
404:
405: transaction.commit();
406:
407: //find the other wallet
408: if (collection2.size() > 0) {
409: iDCard2 = (IDCard) collection2
410: .iterator().next();
411: iDCard2.addEntry(wearer);
412: //we should may be call for a database refresh
413: } else {
414: iDCard2 = new IDCard(this
415: .getUniverseServer(),
416: objectWorld.getUserOwner());
417: iDCard2.addEntry(wearer);
418: try {
419: transaction = this
420: .getPersistenceManager()
421: .currentTransaction();
422: transaction.begin();
423:
424: this
425: .getPersistenceManager()
426: .makePersistent(iDCard2);
427:
428: transaction.commit();
429: } catch (Exception exception) {
430: }
431: objectWorld.getUserOwner()
432: .addInventoryEntry(iDCard2);
433: //we should may be call for a database refresh
434: }
435:
436: } catch (Exception exception) {
437: }
438:
439: this .doShakeHands(objectWorld
440: .getUserOwner());
441: }
442:
443: }
444:
445: } catch (Exception exception) {
446: }
447:
448: }
449:
450: }
451:
452: }
453:
454: //should always return this.getUserOwner();
455: private Avatar getWearer() {
456:
457: Transaction transaction;
458: Extent extent;
459: Query query;
460: String filter;
461: Collection collection;
462:
463: try {
464: transaction = this .getPersistenceManager()
465: .currentTransaction();
466: transaction.begin();
467:
468: // Execute a query
469: extent = this .getPersistenceManager().getExtent(
470: Avatar.class, true);
471: filter = new String(
472: "SELECT Avatar FROM Avatar a WHERE a.getSkin()==this");
473: query = this .getPersistenceManager().newQuery(Avatar.class,
474: extent, filter);
475: collection = (Collection) query.execute();
476:
477: transaction.commit();
478:
479: return (Avatar) (collection.iterator().next());
480:
481: } catch (Exception exception) {
482:
483: return null;
484:
485: }
486:
487: }
488:
489: public final HashSet getGestures() {
490:
491: return this .gestures;
492:
493: }
494:
495: //each gesture must be using humanoid
496: //removes preceding gestures
497: public final void setGestures(HashSet gestures) {
498:
499: Iterator iterator;
500: boolean found;
501: Object object;
502:
503: iterator = gestures.iterator();
504: found = true;
505:
506: while ((iterator.hasNext()) && (found)) {
507: object = iterator.next();
508: if (object instanceof Gesture) {
509: found = (((Gesture) iterator.next()).getHumanoid() == this .humanoid);
510: } else {
511: found = false;
512: }
513: }
514:
515: if (!found) {
516: this .gestures = gestures;
517: this .setDirty();
518: this .doGesturesChanged();
519: }
520:
521: }
522:
523: //gesture must be using humanoid
524: public final void addGesture(Gesture gesture) {
525:
526: if (gesture != null) {
527: if (gesture.getHumanoid() == this .humanoid) {
528: this .gestures.add(gesture);
529: this .setDirty();
530: this .doGesturesChanged();
531: }
532: }
533:
534: }
535:
536: public final void removeGesture(Gesture gesture) {
537:
538: this .gestures.remove(gesture);
539: this .setDirty();
540: this .doGesturesChanged();
541:
542: }
543:
544: //convenience method since verbals are incoded as Displacer in the humanoid hierarchy
545: //verbals are locally cached for better performance
546: public final HashSet getVerbals() {
547:
548: if (this .verbals == null) {
549: verbals = this .humanoid.getDisplacers();
550: }
551:
552: return verbals;
553:
554: }
555:
556: public final HashSet getAccessories() {
557:
558: return this .accessories;
559:
560: }
561:
562: //can be added only if out of an inventory
563: //capabilities must be set to ObjectWorld.MOVABLE
564: //capabilities of ObjectWorld must be set to ObjectWorld.ACCESSORY (system wide check)
565: public final void addAccessory(ObjectWorld objectWorld) {
566:
567: Transaction transaction;
568: Extent extent;
569: Query query;
570: String filter;
571: Collection collection;
572:
573: if (objectWorld != null) {
574:
575: objectWorld.setCaller(this .getCaller());
576:
577: if (objectWorld.checkWritable(ObjectWorld.ACCESSORY
578: + ObjectWorld.MOVABLE)) {
579:
580: //good for ACCESSORY
581: try {
582: transaction = this .getPersistenceManager()
583: .currentTransaction();
584: transaction.begin();
585:
586: extent = this .getPersistenceManager().getExtent(
587: Avatar.class, true);
588: filter = new String(
589: "SELECT Avatar FROM Avatar a WHERE a.getInventory().contains(objectWorld)");
590: query = this .getPersistenceManager().newQuery(
591: Avatar.class, extent, filter);
592: collection = (Collection) query.execute();
593:
594: transaction.commit();
595:
596: if (collection.size() == 0) {
597:
598: try {
599: transaction = this .getPersistenceManager()
600: .currentTransaction();
601: transaction.begin();
602:
603: extent = this .getPersistenceManager()
604: .getExtent(Avatar.class, true);
605: filter = new String(
606: "SELECT Skin FROM Skin s WHERE s.getAccessory().contains(objectWorld)");
607: query = this .getPersistenceManager()
608: .newQuery(Avatar.class, extent,
609: filter);
610: collection = (Collection) query.execute();
611:
612: transaction.commit();
613:
614: //there should be at most one avatar
615: if (collection.size() == 0) {
616: //good for MOVABLE
617: this .accessories.add(objectWorld);
618: this .setDirty();
619: objectWorld.doAccessorize(this );
620: this .doAccessoriesChanged();
621: }
622:
623: } catch (Exception exception) {
624: }
625:
626: }
627:
628: } catch (Exception exception) {
629: }
630:
631: }
632:
633: }
634:
635: }
636:
637: public final void removeAccessory(ObjectWorld objectWorld) {
638:
639: this .accessories.remove(objectWorld);
640: this .setDirty();
641: objectWorld.doUnAccessorize();
642: this .doAccessoriesChanged();
643:
644: }
645:
646: //CALLS DEPENDING ON CAPABILITIES
647:
648: public int getDesignerCapabilities() {
649:
650: //The designer of the object has to encode the desired feature mask of its object
651: //by setting objectCapabilities
652: //just to ensure no one will subclass his object to do undesired behaviors
653: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
654:
655: //capabilities concerning:
656: //ObjectWorld.CUTABLE, ObjectWorld.GLUABLE, ObjectWorld.ACCESSORY
657: //should NOT be set
658:
659: //on the opposite, a skin with gesture and verbals should be set to:
660: //ObjectWorld.MOVABLE, ObjectWorld.RESHAPEABLE, ObjectWorld.VISIBLE
661:
662: return super .getDesignerCapabilities();
663:
664: }
665:
666: //gesture must be in the gesture list for something to happen
667: //ObjectWorld.MOVABLE not checked
668: protected void fireGesture(Gesture gesture) {
669:
670: Enumeration enumeration;
671: Object object;
672: boolean found;
673: int i;
674:
675: if (this .gestures.contains(gesture)) {
676: enumeration = animationSwitch.getAllChildren();
677: found = false;
678: i = 0;
679: while ((enumeration.hasMoreElements()) && (!found)) {
680: object = enumeration.nextElement();
681: if (object instanceof BranchGroup) {
682: if (((String) ((BranchGroup) object).getUserData())
683: .equals(gesture.getName())) {
684: found = true;
685: }
686: }
687: i++;
688: }
689: animationSwitch.setWhichChild(i - 1);
690: this .doGesture(gesture);
691: }
692:
693: }
694:
695: //displacer must be in the displacer list for something to happen
696: //ObjectWorld.RESHAPEABLE not checked
697: protected void fireVerbal(Displacer verbal) {
698:
699: //next lines copied from Displacement
700: Enumeration enumeration;
701: Object object;
702:
703: if (this .getVerbals().contains(verbal)) {
704:
705: enumeration = verbalsBranchGroup.getAllChildren();
706:
707: while (enumeration.hasMoreElements()) {
708:
709: object = enumeration.nextElement();
710: if (object instanceof MorphingBehavior) {
711: if ((((MorphingBehavior) object).getUserData()) == verbal) {
712: ((MorphingBehavior) object).restart();
713: this .doVerbal(verbal);
714: }
715: }
716:
717: }
718:
719: }
720:
721: }
722:
723: //time sliced actions
724:
725: public final void doAccessoriesChanged() {
726:
727: }
728:
729: public final void doGesturesChanged() {
730:
731: }
732:
733: //Skins can Duplicate
734: //unless the designer decides not
735:
736: //Skins shouldn't be able to be cut
737: public final void doCut() {
738: //do nothing
739: }
740:
741: //Skins shouldn't be able to be glue or be glued
742: //this the the purpose of accessories
743:
744: public final void doGlue(ObjectWorld objectWorld) {
745: //do nothing
746: }
747:
748: public final void doUnGlue(ObjectWorld objectWorld) {
749: //do nothing
750: }
751:
752: //gesture must be in the gesture list for something to happen
753: public void doGesture(Gesture gesture) {
754:
755: }
756:
757: public void doVerbal(Displacer verbal) {
758:
759: }
760:
761: //Skins can Color, Resize, SoundAlter, Visible, Sonore, Inventorize
762: //unless the designer decides not
763:
764: //please don't inventorize weared skins as avatar will become invisible (desirable feature in some virtual world nevertheless)
765:
766: //accessories have a life on their own as any ObjectWorld
767: //once worn they should move with the avatar
768:
769: //it shouldn't be possible to accessorize a skin on the opposite
770:
771: public final void doAccessorize(Avatar user) {
772:
773: throw new java.lang.IllegalArgumentException(
774: "A skin can't be accessorized.");
775:
776: }
777:
778: public final void doUnAccessorize() {
779: //do nothing
780: }
781:
782: //capabilities must be set (as usual) for both avatars
783: //shake is made against the current avatar skin
784: public void doShakeHands(Avatar avatar) {
785:
786: //there should be a physical bond but not necessarily
787: //(for example by a call from the user)
788: //see doStatusChanged
789:
790: }
791:
792: //SceneGraph serialization for Geometry and Sound
793: //see parent
794:
795: }
|