0001: /*
0002: * Copyright (c) 2001 Silvere Martin-Michiellot All Rights Reserved.
0003: *
0004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
0005: * royalty free, license to use, modify and redistribute this
0006: * software in source and binary code form,
0007: * provided that i) this copyright notice and license appear on all copies of
0008: * the software; and ii) Licensee does not utilize the software in a manner
0009: * which is disparaging to Silvere Martin-Michiellot.
0010: *
0011: * This software is provided "AS IS," without a warranty of any kind. ALL
0012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
0013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
0014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
0015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
0016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
0017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
0018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
0019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
0020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
0021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
0022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
0023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
0024: *
0025: * This software is not designed or intended for use in on-line control of
0026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
0027: * the design, construction, operation or maintenance of any nuclear
0028: * facility. Licensee represents and warrants that it will not use or
0029: * redistribute the Software for such purposes.
0030: *
0031: * @Author: Silvere Martin-Michiellot
0032: *
0033: */
0034:
0035: package com.db.server;
0036:
0037: import java.io.IOException;
0038: import java.io.Serializable;
0039: import java.util.*;
0040: import java.security.PublicKey;
0041: import javax.jdo.*;
0042: import javax.media.j3d.*;
0043: import javax.vecmath.*;
0044:
0045: /**
0046: */
0047: public abstract class ObjectWorld extends VirtualElement {
0048:
0049: //Lords and self are always allowed full rights
0050:
0051: public final static int NO_CAPABILITY = 0;
0052:
0053: public final static int SALABLE = 1;
0054: public final static int RESHAPEABLE = 2;
0055: public final static int SOUNDALTERABLE = 4;
0056: public final static int VISIBLE = 8;
0057: public final static int SONORE = 16;
0058: public final static int MOVABLE = 32;
0059: public final static int COLLIDABLE = 64;
0060: public final static int INVENTORIZABLE = 128;
0061: public final static int ACCESSORY = 256;
0062: public final static int CUTABLE = 512;
0063: public final static int GLUABLE = 1024;
0064: public final static int DUPLICABLE = 2048;
0065:
0066: private static int LAST_CAPABILITY = (ObjectWorld.DUPLICABLE * 2) - 1;
0067:
0068: public static int DEFAULT_DESIGNER_CAPABILITIES = ObjectWorld.LAST_CAPABILITY;
0069:
0070: /**
0071: * duplicable-instanciable (to have a copy of it) depending on a copier machine (tool)
0072: * cutable into some predefined pieces
0073: * gluable to some other object (There should be a list managing objects to which this object is directely glued. A tool should allow to glue or unglue two objects. Objects should only be glued if they share a physical bond.)
0074: * movable to some other place according to user's rights
0075: * collorable
0076: * resizable with no shape modification
0077: * reshapeable
0078: * collidable
0079: * visible
0080: * sonore
0081: * inventorisable (if it can be put in and out the pocket of the user) or pickable
0082: * salable
0083: * accessory (this means this object is targeted to be worn by an avatar, and should be small in size)
0084: */
0085:
0086: private Transform3D transform3D;
0087: //we don't care about bounds and Lord that can be automatically managed by the client depending on its needs (bounds are just needed by the server for client prefetch)
0088: private Node geometryDescription;
0089: private Sound soundDescription;
0090: //rights to activate a behavior for the object depending on the triggering user
0091: private HashSet gluedList;
0092: private Object status;
0093:
0094: private Node invisibleGeometry;
0095: private Sound inaudibleSound;
0096:
0097: public ObjectWorld(UniverseServer universeServer, Avatar userOwner) {
0098:
0099: super (universeServer, userOwner);
0100:
0101: }
0102:
0103: //must be >= 0
0104: public final void setPrice(double price) {
0105:
0106: if (this .checkWritable(VirtualElement.SALABLE)) {
0107:
0108: if (price >= 0) {
0109: this .price = price;
0110: this .setDirty();
0111: this .doPriceChanged();
0112: }
0113:
0114: }
0115:
0116: }
0117:
0118: //any valid string will fit
0119: public final void setCurrency(String currency) {
0120:
0121: if (this .checkWritable(VirtualElement.SALABLE)) {
0122:
0123: if ((currency != null) && currency.length() > 0) {
0124: this .currency = currency;
0125: this .setDirty();
0126: this .doCurrencyChanged();
0127: }
0128:
0129: }
0130:
0131: }
0132:
0133: //every "get" or "set" call assumes valid user's rights (depending on who calls)
0134: //otherwise the server returns a request refused message
0135:
0136: public final Node getGeometryDescription() {
0137:
0138: return this .geometryDescription;
0139:
0140: }
0141:
0142: public final Sound getSoundDescription() {
0143:
0144: return this .soundDescription;
0145:
0146: }
0147:
0148: public final Transform3D getTransform3D() {
0149:
0150: return this .transform3D;
0151:
0152: }
0153:
0154: public final Object getStatus() {
0155:
0156: return this .status;
0157:
0158: }
0159:
0160: //object must be one of:
0161: //Shape3D, Morph, Fog, Light, Behavior.Billboard, Behavior.Interpolator, Behavior.LOD
0162: //capabilities must be set to ObjectWorld.VISIBLE, ObjectWorld.RESHAPEABLE
0163: //unglues everything it is glued to
0164: public void setGeometryDescription(Node object) {
0165:
0166: Iterator iterator;
0167: ObjectWorld objectWorld;
0168:
0169: if (this .checkWritable(ObjectWorld.RESHAPEABLE)) {
0170:
0171: //good for ObjectWorld.VISIBLE + ObjectWorld.RESHAPEABLE
0172: //check for different cases depending on capabilities
0173: if ((object instanceof Shape3D)
0174: || (object instanceof Morph)
0175: || (object instanceof Fog)
0176: || (object instanceof Light)
0177: || (object instanceof Billboard)
0178: || (object instanceof Interpolator)
0179: || (object instanceof LOD)) {
0180: this .geometryDescription = object;
0181: this .setDirty();
0182: this .doReshape();
0183:
0184: iterator = this .gluedList.iterator();
0185: while (iterator.hasNext()) {
0186: objectWorld = (ObjectWorld) iterator.next();
0187: removeRemoteGluedObject(this );
0188: this .doUnGlue();
0189: }
0190:
0191: this .gluedList = null;
0192: }
0193:
0194: }
0195:
0196: //done when sending object to network for optimization purposes
0197: //this.geometryDescription.setCollidable(this.checkWritable(ObjectWorld.COLLIDABLE));
0198:
0199: }
0200:
0201: //capabilities must be set to ObjectWorld.SOUNDALTERABLE
0202: public void setSoundDescription(Sound sound) {
0203:
0204: if (this .checkWritable(ObjectWorld.SOUNDALTERABLE)) {
0205:
0206: //good for ObjectWorld.SOUNDALTERABLE
0207: this .soundDescription = sound;
0208: this .setDirty();
0209: this .doSoundAlter();
0210:
0211: }
0212:
0213: }
0214:
0215: //next calls to make an object disappear when inventorized and reappear
0216: public void setInvisible() {
0217:
0218: if (this .checkWritable(ObjectWorld.VISIBLE)) {
0219:
0220: if (this .isVisible()) {
0221: this .invisibleGeometry = this .geometryDescription;
0222: this .geometryDescription = null;
0223: }
0224:
0225: }
0226:
0227: }
0228:
0229: protected boolean isVisible() {
0230:
0231: return (this .invisibleGeometry == null);
0232:
0233: }
0234:
0235: public void setVisible() {
0236:
0237: if (this .checkWritable(ObjectWorld.VISIBLE)) {
0238:
0239: if (this .geometryDescription == null) {
0240: this .geometryDescription = invisibleGeometry;
0241: this .invisibleGeometry = null;
0242: }
0243:
0244: }
0245:
0246: }
0247:
0248: public void setUnSonore() {
0249:
0250: if (this .checkWritable(ObjectWorld.SONORE)) {
0251:
0252: if (this .isSonore()) {
0253: this .inaudibleSound = this .soundDescription;
0254: this .soundDescription = null;
0255: }
0256:
0257: }
0258:
0259: }
0260:
0261: protected boolean isSonore() {
0262:
0263: return (this .inaudibleSound == null);
0264:
0265: }
0266:
0267: public void setSonore() {
0268:
0269: if (this .checkWritable(ObjectWorld.SONORE)) {
0270:
0271: if (this .inaudibleSound == null) {
0272: this .soundDescription = inaudibleSound;
0273: this .inaudibleSound = null;
0274: }
0275:
0276: }
0277:
0278: }
0279:
0280: //does not fire a status change
0281: public final void resetStatus() {
0282:
0283: this .status = null;
0284: this .setDirty();
0285:
0286: }
0287:
0288: private Land oldLand;
0289:
0290: //capabilities must be set to ObjectWorld.MOVABLE
0291: //glued objects should move along with object
0292: //transform3D should be feasible only if desired space is accessible (access rights valid and no object already there)
0293: //object should be repositionned to userowner home position if actual transform value is not correct
0294: //uses caller
0295: public void setTransform3D(Transform3D transform3D) {
0296:
0297: Transform3D oldTransform3D;
0298: Transaction transaction;
0299: Extent extent;
0300: Query query;
0301: String filter;
0302: Collection collection;
0303: Land land;
0304: int relation;
0305: Point3d point3d;
0306:
0307: if (this .getCaller() != null) {
0308:
0309: if (this .checkWritable(ObjectWorld.MOVABLE)) {
0310:
0311: oldTransform3D = new Transform3D(this .getTransform3D());
0312:
0313: if (transform3D != oldTransform3D) {
0314:
0315: //check arrival position is valid
0316: //find destination land
0317: //get capabilities for caller
0318: point3d = new Point3d();
0319: transform3D.transform(point3d);
0320:
0321: try {
0322: transaction = this .getPersistenceManager()
0323: .currentTransaction();
0324: transaction.begin();
0325:
0326: extent = this .getPersistenceManager()
0327: .getExtent(Land.class, true);
0328: filter = new String(
0329: "SELECT Land FROM Land l WHERE l.getBounds().intersect(point3d)");
0330: query = this .getPersistenceManager().newQuery(
0331: Land.class, extent, filter);
0332: collection = (Collection) query.execute();
0333:
0334: transaction.commit();
0335:
0336: //there should be exactely one land or transform is not valid
0337: if (collection.size() > 0) {
0338: land = (Land) (collection.iterator().next());
0339: relation = Avatar.getFeudalRelation(this
0340: .getCaller(), land.getUserOwner());
0341:
0342: if ((relation == Avatar.LORD)
0343: || (relation == Avatar.SELF)) {
0344: //do the transform
0345: this .internalTransform(transform3D);
0346: if ((this instanceof Skin)
0347: && (oldLand != land)) {
0348: oldLand.doGetOut(this .getCaller());
0349: oldLand = land;
0350: land.doEnter(this .getCaller());
0351: }
0352: land.doDrop(this .getCaller(), this );
0353: } else {
0354: if (this
0355: .getOthersAccessRights(relation) != VirtualElement.HIDDEN) {
0356: //do the transform
0357: this .internalTransform(transform3D);
0358: if ((this instanceof Skin)
0359: && (oldLand != land)) {
0360: oldLand.doGetOut(this
0361: .getCaller());
0362: oldLand = land;
0363: land.doEnter(this .getCaller());
0364: }
0365: land.doDrop(this .getCaller(), this );
0366: }
0367: }
0368: } else {
0369: //invalid transform
0370: }
0371:
0372: } catch (Exception exception) {
0373: }
0374: }
0375:
0376: }
0377:
0378: }
0379:
0380: }
0381:
0382: private final void internalTransform(Transform3D transform3D) {
0383:
0384: Transform3D oldTransform3D;
0385: Transaction transaction;
0386: Extent extent;
0387: Query query;
0388: String filter;
0389: Collection collection;
0390: Transform3D partialTransform3D;
0391: Iterator iterator;
0392: ObjectWorld objectWorld;
0393:
0394: //good for ObjectWorld.MOVABLE
0395: //good for ObjectWorld.COLLIDABLE
0396: try {
0397: transaction = this .getPersistenceManager()
0398: .currentTransaction();
0399: transaction.begin();
0400:
0401: extent = this .getPersistenceManager().getExtent(
0402: Avatar.class, true);
0403: filter = new String(
0404: "SELECT ObjectWorld FROM ObjectWorld o WHERE o.getGeometryBounds().intersect(this.getGeometryBounds())");
0405: query = this .getPersistenceManager().newQuery(Avatar.class,
0406: extent, filter);
0407: collection = (Collection) query.execute();
0408:
0409: transaction.commit();
0410:
0411: oldTransform3D = this .transform3D;
0412: //do the transform anyway
0413: //it would be nice to find the nearest available position that still collides with selected objects but this is computationnally very intensive
0414: this .transform3D = transform3D;
0415: this .setDirty();
0416:
0417: //set transform3D of glued objects accordingly
0418: iterator = this .gluedList.iterator();
0419: while (iterator.hasNext()) {
0420: objectWorld = (ObjectWorld) iterator.next();
0421: partialTransform3D = new Transform3D();
0422: partialTransform3D.sub(transform3D, oldTransform3D);
0423: partialTransform3D.add(objectWorld.getTransform3D());
0424: objectWorld.setTransform3D(partialTransform3D);
0425: }
0426:
0427: this .doMove();
0428:
0429: if (this .checkWritable(ObjectWorld.COLLIDABLE)) {
0430:
0431: if (collection.size() != 0) {
0432: iterator = collection.iterator();
0433: while (iterator.hasNext()) {
0434: objectWorld = (ObjectWorld) iterator.next();
0435: this .doCollide(objectWorld);
0436: objectWorld.doCollide(this );
0437: }
0438: }
0439:
0440: }
0441:
0442: } catch (Exception exception) {
0443: }
0444:
0445: }
0446:
0447: //check if actual land is still valid and if not use home position to go back home
0448: //uses caller
0449: //XXX not checked
0450: protected final void refreshTransform() {
0451:
0452: Transform3D futureTransform3D;
0453: Transaction transaction;
0454: Extent extent;
0455: Query query;
0456: String filter;
0457: Collection collection;
0458: Point3d point3d;
0459: Land land;
0460: int relation;
0461:
0462: futureTransform3D = new Transform3D();
0463: futureTransform3D.set(this .getUserOwner().getHomePosition());
0464: point3d = new Point3d();
0465: futureTransform3D.transform(point3d);
0466:
0467: try {
0468: transaction = this .getPersistenceManager()
0469: .currentTransaction();
0470: transaction.begin();
0471:
0472: extent = this .getPersistenceManager().getExtent(Land.class,
0473: true);
0474: filter = new String(
0475: "SELECT Land FROM Land l WHERE l.getBounds().intersect(point3d)");
0476: query = this .getPersistenceManager().newQuery(Land.class,
0477: extent, filter);
0478: collection = (Collection) query.execute();
0479:
0480: transaction.commit();
0481:
0482: //there should be exactely one land or transform is not valid
0483: if (collection.size() > 0) {
0484: land = (Land) (collection.iterator().next());
0485: relation = Avatar.getFeudalRelation(this .getCaller(),
0486: land.getUserOwner());
0487:
0488: if ((relation == Avatar.LORD)
0489: || (relation == Avatar.SELF)) {
0490: //do the transform
0491: this .internalTransform(transform3D);
0492: if ((this instanceof Skin) && (oldLand != land)) {
0493: oldLand.doGetOut(this .getCaller());
0494: oldLand = land;
0495: land.doEnter(this .getCaller());
0496: }
0497: land.doDrop(this .getCaller(), this );
0498: } else {
0499: if (this .getOthersAccessRights(relation) != VirtualElement.HIDDEN) {
0500: //do the transform
0501: this .internalTransform(transform3D);
0502: if ((this instanceof Skin) && (oldLand != land)) {
0503: oldLand.doGetOut(this .getCaller());
0504: oldLand = land;
0505: land.doEnter(this .getCaller());
0506: }
0507: land.doDrop(this .getCaller(), this );
0508: }
0509: }
0510: } else {
0511: //invalid transform
0512: }
0513:
0514: } catch (Exception exception) {
0515: }
0516:
0517: }
0518:
0519: //put out of inventory, unglue, unaccessory
0520: protected final void refresh() {
0521:
0522: Transaction transaction;
0523: Extent extent;
0524: Query query;
0525: String filter;
0526: Collection collection;
0527: Avatar avatar;
0528: ObjectWorld objectWorld;
0529: Skin skin;
0530: //GuideWorld guideWorld;
0531: Iterator iterator;
0532:
0533: //done when sending object to network for optimization purposes
0534: //this.geometryDescription.setCollidable(this.checkWritable(ObjectWorld.COLLIDABLE));
0535:
0536: this .refreshTransform();
0537:
0538: try {
0539: transaction = this .getPersistenceManager()
0540: .currentTransaction();
0541: transaction.begin();
0542:
0543: extent = this .getPersistenceManager().getExtent(
0544: Avatar.class, true);
0545: filter = new String(
0546: "SELECT Avatar FROM Avatar a WHERE a.getInventory().contains(this)");
0547: query = this .getPersistenceManager().newQuery(Avatar.class,
0548: extent, filter);
0549: collection = (Collection) query.execute();
0550:
0551: transaction.commit();
0552:
0553: if (collection.size() > 0) {
0554: avatar = (Avatar) collection.iterator().next();
0555: avatar.removeInventoryEntry(this );
0556: }
0557:
0558: } catch (Exception exception) {
0559: }
0560:
0561: try {
0562: transaction = this .getPersistenceManager()
0563: .currentTransaction();
0564: transaction.begin();
0565:
0566: extent = this .getPersistenceManager().getExtent(
0567: ObjectWorld.class, true);
0568: filter = new String(
0569: "SELECT ObjectWorld FROM ObjectWorld o WHERE o.getGluedObjects().contains(this)");
0570: query = this .getPersistenceManager().newQuery(
0571: ObjectWorld.class, extent, filter);
0572: collection = (Collection) query.execute();
0573:
0574: transaction.commit();
0575:
0576: if (collection.size() > 0) {
0577: iterator = collection.iterator();
0578: objectWorld = (ObjectWorld) iterator.next();
0579: objectWorld.removeAllGluedObjects();
0580: }
0581:
0582: } catch (Exception exception) {
0583: }
0584:
0585: try {
0586: transaction = this .getPersistenceManager()
0587: .currentTransaction();
0588: transaction.begin();
0589:
0590: extent = this .getPersistenceManager().getExtent(Skin.class,
0591: true);
0592: filter = new String(
0593: "SELECT Skin FROM Skin s WHERE s.getAccessories().contains(this)");
0594: query = this .getPersistenceManager().newQuery(Skin.class,
0595: extent, filter);
0596: collection = (Collection) query.execute();
0597:
0598: transaction.commit();
0599:
0600: if (collection.size() > 0) {
0601: iterator = collection.iterator();
0602: skin = (Skin) collection.iterator().next();
0603: skin.removeAccessory(this );
0604: }
0605:
0606: } catch (Exception exception) {
0607: }
0608:
0609: /**
0610: * try {
0611: * transaction = this.getPersistenceManager().currentTransaction();
0612: * transaction.begin();
0613: *
0614: * extent = this.getPersistenceManager().getExtent(GuideWorld.class, true);
0615: * filter = new String("SELECT GuideWorld FROM GuideWorld g WHERE g.getInventory().contains(this)");
0616: * query = this.getPersistenceManager().newQuery(GuideWorld.class, extent, filter);
0617: * collection = (Collection) query.execute();
0618: *
0619: * transaction.commit();
0620: * }
0621: * catch (Exception exception) {
0622: * }
0623: *
0624: * if (collection.size()>0) {
0625: * iterator = collection.iterator();
0626: * while (iterator.hasNext()) {
0627: * guideWorld = (GuideWorld) iterator.next();
0628: * guideWorld.removeInventoryEntry(this);
0629: * }
0630: * }
0631: **/
0632: }
0633:
0634: public void setStatus(Object status) {
0635:
0636: //every access to setStatus should be send automatically to system
0637: this .status = status;
0638: this .setDirty();
0639: this .doStatusChanged();
0640:
0641: }
0642:
0643: public final HashSet getGluedObjects() {
0644:
0645: return this .gluedList;
0646:
0647: }
0648:
0649: //glues this object to a list of already glued objects
0650: //capabilities must be set to ObjectWorld.GLUABLE for both objects
0651: public final void addGluedObject(ObjectWorld objectWorld) {
0652:
0653: if (this .checkWritable(ObjectWorld.GLUABLE)) {
0654:
0655: if ((objectWorld != null)
0656: && (objectWorld != this )
0657: && (objectWorld.getUserOwner() == this
0658: .getUserOwner())) {
0659: //don't add self
0660: //glue if intersection exists
0661: if (objectWorld.getGeometryBounds().intersect(
0662: this .getGeometryBounds())) {
0663: this .gluedList.add(objectWorld);
0664: objectWorld.addRemoteGluedObject(this );
0665: this .doGlue(objectWorld);
0666: }
0667: }
0668:
0669: }
0670:
0671: }
0672:
0673: protected void addRemoteGluedObject(ObjectWorld objectWorld) {
0674:
0675: this .gluedList.add(objectWorld);
0676: this .setDirty();
0677: this .doGlue(objectWorld);
0678:
0679: }
0680:
0681: public final void removeGluedObject(ObjectWorld objectWorld) {
0682:
0683: if (this .gluedList.contains(objectWorld)) {
0684: this .gluedList.remove(objectWorld);
0685: this .setDirty();
0686: objectWorld.removeRemoteGluedObject(this );
0687: this .doUnGlue();
0688: }
0689:
0690: }
0691:
0692: protected void removeRemoteGluedObject(ObjectWorld objectWorld) {
0693:
0694: this .gluedList.remove(objectWorld);
0695: this .setDirty();
0696: this .doUnGlue();
0697:
0698: }
0699:
0700: public final void removeAllGluedObjects() {
0701:
0702: ObjectWorld objectWorld;
0703: Iterator iterator;
0704:
0705: iterator = this .getGluedObjects().iterator();
0706: while (iterator.hasNext()) {
0707: objectWorld = (ObjectWorld) iterator.next();
0708: this .setDirty();
0709: objectWorld.removeRemoteGluedObject(this );
0710: this .doUnGlue();
0711: }
0712:
0713: }
0714:
0715: protected Bounds getGluedBounds() {
0716:
0717: Iterator iterator;
0718: BoundingPolytope bounds;
0719: Bounds[] boundsArray;
0720: int i;
0721: ObjectWorld objectWorld;
0722:
0723: bounds = new BoundingPolytope();
0724: boundsArray = new Bounds[this .getGluedObjects().size()];
0725: iterator = this .getGluedObjects().iterator();
0726:
0727: i = 0;
0728: while (iterator.hasNext()) {
0729: objectWorld = (ObjectWorld) iterator.next();
0730: boundsArray[i] = objectWorld.getGeometryBounds();
0731: i++;
0732: }
0733:
0734: bounds.combine(boundsArray);
0735:
0736: return bounds;
0737:
0738: }
0739:
0740: //resulting Object is glued to nothing
0741: //objectWorld.DUPLICABLE
0742: //object should be created near its parent (1 meter on x and z)
0743: public final void duplicate() {
0744:
0745: ObjectWorld objectWorld;
0746: Transform3D otherTransform;
0747: Transaction transaction;
0748:
0749: if (this .checkWritable(ObjectWorld.DUPLICABLE)) {
0750:
0751: //objectWorld = new ObjectWorld(this.getPersistenceManager(), this.getUserOwner());
0752: try {
0753:
0754: objectWorld = (ObjectWorld) this .clone();
0755:
0756: //objectWorld.setGeometryDescription(this.getGeometryDescription());
0757: //objectWorld.setSoundDescription(this.getSoundDescription());
0758: otherTransform = new Transform3D(this .getTransform3D());
0759: otherTransform.add(new Transform3D(new Matrix3d(),
0760: new Vector3d(1, 0, 1), 1));
0761: objectWorld.setTransform3D(otherTransform);
0762: //objectWorld.setStatus(this.getStatus());
0763: //objectWorld.setInformation(this.getInformation());
0764: //objectWorld.setPrice(this.getPrice());
0765: //objectWorld.setCurrency(this.getCurrency());
0766: //objectWorld.setOthersAccessRights(this.getOthersAccessRights());
0767:
0768: try {
0769: transaction = this .getPersistenceManager()
0770: .currentTransaction();
0771: transaction.begin();
0772:
0773: this .getPersistenceManager().makePersistent(
0774: objectWorld);
0775:
0776: transaction.commit();
0777: } catch (Exception exception) {
0778: }
0779:
0780: this .doDuplicate();
0781:
0782: } catch (CloneNotSupportedException cloneNotSupportedException) {
0783: }
0784:
0785: }
0786:
0787: }
0788:
0789: //Shape3D array must have the same geometry bounds as this.
0790: public final void cut(Shape3D[] shapes3D) {
0791:
0792: ObjectWorld objectWorld;
0793: ObjectWorld[] objectWorlds;
0794: BoundingPolytope bound;
0795: Bounds[] bounds;
0796: Transaction transaction;
0797:
0798: if (this .checkWritable(ObjectWorld.CUTABLE)) {
0799:
0800: if (shapes3D.length > 0) {
0801:
0802: bounds = new Bounds[shapes3D.length];
0803: for (int i = 0; i < shapes3D.length; i++) {
0804: bounds[i] = shapes3D[i].getBounds();
0805: }
0806:
0807: bound = new BoundingPolytope();
0808: bound.combine(bounds);
0809:
0810: if (this .getGeometryBounds().equals(bound)) {
0811:
0812: objectWorlds = new ObjectWorld[shapes3D.length];
0813:
0814: for (int i = 0; i < shapes3D.length; i++) {
0815:
0816: try {
0817:
0818: //objectWorld = new ObjectWorld(this.getPersistenceManager(), this.getUserOwner());
0819: objectWorld = (ObjectWorld) this .clone();
0820:
0821: objectWorld
0822: .setGeometryDescription(shapes3D[i]);
0823: //objectWorld.setSoundDescription(this.getSoundDescription());
0824: //objectWorld.setTransform3D(this.getTransform3D());
0825: //objectWorld.setStatus(this.getStatus());
0826: //objectWorld.setInformation(this.getInformation());
0827: //objectWorld.setPrice(this.getPrice());
0828: //objectWorld.setCurrency(this.getCurrency());
0829: //objectWorld.setOthersAccessRights(this.getOthersAccessRights());
0830:
0831: objectWorlds[i] = objectWorld;
0832:
0833: } catch (CloneNotSupportedException cloneNotSupportedException) {
0834: }
0835:
0836: }
0837:
0838: try {
0839: transaction = this .getPersistenceManager()
0840: .currentTransaction();
0841: transaction.begin();
0842:
0843: this .getPersistenceManager().makePersistentAll(
0844: objectWorlds);
0845:
0846: transaction.commit();
0847: } catch (Exception exception) {
0848: }
0849:
0850: for (int i = 0; i < objectWorlds.length; i++) {
0851: objectWorlds[i].doCut();
0852: }
0853:
0854: this .deleteVirtualElement(this );
0855:
0856: }
0857:
0858: }
0859:
0860: }
0861:
0862: }
0863:
0864: //uses caller
0865: protected final boolean checkWritable(int capabilities) {
0866:
0867: int relation;
0868: Land land;
0869:
0870: relation = Avatar.getFeudalRelation(this .getUserOwner(), this
0871: .getCaller());
0872:
0873: if ((relation == Avatar.LORD) || (relation == Avatar.SELF)) {
0874: return true;
0875: } else {
0876: if (this .getOthersAccessRight(relation,
0877: VirtualElement.READ_WRITE)) {
0878: //if object is owned by the land owner
0879: land = this .getCurrentLand();
0880: if (land.getUserOwner() == this .getUserOwner()) {
0881: return land.getOwnersObjectsDefaultRights(relation,
0882: capabilities);
0883: } else {
0884: return true;
0885: }
0886: } else {
0887: return false;
0888: }
0889: }
0890:
0891: }
0892:
0893: //returns the land this object is currently on if available
0894: //should always be ok
0895: public final Land getCurrentLand() {
0896:
0897: Transform3D transform3D;
0898: Point3d point3d;
0899: Transaction transaction;
0900: Extent extent;
0901: Query query;
0902: String filter;
0903: Collection collection;
0904:
0905: transform3D = this .getTransform3D();
0906: point3d = new Point3d();
0907: transform3D.transform(point3d);
0908:
0909: try {
0910: transaction = this .getPersistenceManager()
0911: .currentTransaction();
0912: transaction.begin();
0913:
0914: extent = this .getPersistenceManager().getExtent(Land.class,
0915: true);
0916: filter = new String(
0917: "SELECT Land FROM Land l WHERE l.getBounds().intersect(point3d)");
0918: query = this .getPersistenceManager().newQuery(Land.class,
0919: extent, filter);
0920: collection = (Collection) query.execute();
0921:
0922: transaction.commit();
0923:
0924: if (collection.size() > 0) {
0925: //each object should be in exactly one land at a time
0926: return (Land) (collection.iterator().next());
0927: } else {
0928: return null;
0929: }
0930:
0931: } catch (Exception exception) {
0932:
0933: return null;
0934:
0935: }
0936:
0937: }
0938:
0939: //access to Bounds subject to the same rights access as Geometry and Sound Field access
0940: //auto-compute Bounds for a later use.
0941: //a change in the geometry for this object should also change the Bounds.
0942: //objects shouldn't be able to have a geometry that is over a land.
0943: //For example, a gate shouldn't open towards the public alley but towards the garden of a house
0944: //geometry should be truncated if access right is not filled
0945: //designers should find a way to ensure their object "doesn't" grow to large to the surprise of the user
0946: //Bounds give the current bounds of an object and should be used to prefetch geometry based on the avatar position
0947: //same restrictions and usage apply on the Collision Bounds, the Sound Bounds (and Bounding Leaf)
0948:
0949: public final Bounds getGeometryBounds() {
0950:
0951: return this .geometryDescription.getBounds();
0952:
0953: }
0954:
0955: //(interpolator & lod & billboard)schedulingBounds, (light & fog)influencingBounds, (Morph & Shape3D) collisionBounds,
0956: public final Bounds getCollisionBounds() {
0957:
0958: if (this .geometryDescription instanceof Morph) {
0959: return ((Morph) this .geometryDescription)
0960: .getCollisionBounds();
0961: } else {
0962: if (this .geometryDescription instanceof Shape3D) {
0963: return ((Shape3D) this .geometryDescription)
0964: .getCollisionBounds();
0965: } else {
0966: return null;
0967: }
0968: }
0969:
0970: }
0971:
0972: public final Bounds getSoundBounds() {
0973:
0974: return this .soundDescription.getSchedulingBounds();
0975:
0976: }
0977:
0978: public final BoundingLeaf getSoundBoundingLeaf() {
0979:
0980: return this .soundDescription.getSchedulingBoundingLeaf();
0981:
0982: }
0983:
0984: //time sliced actions
0985:
0986: public int getDesignerCapabilities() {
0987:
0988: //The designer of the object has to encode the desired feature mask of its object
0989: //by setting objectCapabilities
0990: //just to ensure no one will subclass his object to do undesired behaviors
0991: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
0992:
0993: return super .getDesignerCapabilities();
0994:
0995: }
0996:
0997: public void doReshape() {
0998: //modifies the Geometry or the colors or the size
0999:
1000: }
1001:
1002: public void doSoundAlter() {
1003:
1004: }
1005:
1006: public void doMove() {
1007:
1008: }
1009:
1010: public void doStatusChanged() {
1011:
1012: //by default sets the status of this object
1013: //which does nothing but indirectly sends a notification to the system
1014: //designers can if they wish trigger some actions (doResize, doColor...)
1015:
1016: }
1017:
1018: public void doDuplicate() {
1019: //resulting array should contain original ObjectWorld at position 0 and the copy at position 1
1020: //Objects should both be in the database as any other Object and differ only by their position
1021:
1022: }
1023:
1024: public void doCut() {
1025: //not a real generation of objects, this object is geometrically splited into some objects
1026: //that will all have the same properties that the original object but doCut (capability unset by system)
1027:
1028: }
1029:
1030: //glued objects should share a physical bond
1031: //if object a is glued to object b then object b is also glued to object a
1032: public void doGlue(ObjectWorld objectWorld) {
1033:
1034: }
1035:
1036: public void doUnGlue() {
1037:
1038: }
1039:
1040: public void doCollide(ObjectWorld objectWorld) {
1041: //what happens when this objects collides to something that also collides
1042: //can subspecify reaction depending on ObjectWorld
1043:
1044: //sometimes the object shatters (doCut())
1045: //sometimes the object "Boings!"
1046:
1047: }
1048:
1049: public void doVisible() {
1050: //when the object becomes visible for a user
1051:
1052: //the designer has to put something here if he wants a visible object
1053: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
1054: //if this is the desired behavior
1055:
1056: }
1057:
1058: public void doInvisible() {
1059: //when the object becomes invisible for a user
1060:
1061: }
1062:
1063: public void doSonore() {
1064: //when the object becomes audible for a user
1065:
1066: //the designer has to put something here if he wants an audible object
1067: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
1068: //if this is the desired behavior
1069:
1070: }
1071:
1072: public void doUnSonore() {
1073: //when the object becomes inaudible for a user
1074:
1075: }
1076:
1077: public void doInventorize(Avatar user) {
1078: //Owner may also carry its objects in its inventory sometimes
1079:
1080: }
1081:
1082: public void doUnInventorize() {
1083:
1084: }
1085:
1086: public void doAccessorize(Skin skin) {
1087: //Owner can also decide to wear it's own accessories sometimes
1088:
1089: }
1090:
1091: public void doUnAccessorize() {
1092:
1093: }
1094:
1095: }
|