package NET.worlds.scape; import NET.worlds.console.Console; import NET.worlds.console.Main; import NET.worlds.console.MainCallback; import NET.worlds.network.NetUpdate; import NET.worlds.network.URL; import java.awt.Color; import java.io.IOException; import java.text.MessageFormat; import java.util.Vector; public class Portal extends Rect implements BumpHandler, Prerenderable, Postrenderable, Properties, Persister, LoadedURLSelf { static final int UNCONNECTED = -1; static final int INITIAL = 0; static final int DOWNLOADING = 1; static final int DONE = 2; private int _state = -1; private Portal _farSidePortal = null; String _farSidePortalName = null; private boolean _farSideIsPortal = true; private boolean _allowDownload = true; String _farSideRoomName = null; private URL _farSideWorld = null; private Room _farSideRoom = null; private float _farx; private float _fary; private float _farz; private float _fartheta; private float _userFarx; private float _userFary; private float _userFarz; private float _userFartheta; private boolean frozeFrameEvents; private Transform _p2pxform = null; private int _changeNum = 0; private int _farChangeNum = -1; static BumpCalc standardPassthroughBumpCalc = new PassthroughBumpCalc(); private static Object classCookie = new Object(); static { nativeInit(); standardPassthroughBumpCalc.setName("defaultPassthroughBumpCalc"); } protected Room getFarSideRoom() { return this._farSideRoom; } public Portal(float w, float h) { super(w, h, null); } public Portal(float llx, float lly, float llz, float urx, float ury, float urz) { super(llx, lly, llz, urx, ury, urz, null); } public Portal() { } public void setFarSideInfo(URL world, String room, String portal) { this._farSideWorld = world; this._farSideRoomName = room; this._farSidePortalName = portal; } public Portal(Point3Temp llc, Point3Temp urc) { super(llc, urc, null); } public static Portal findByName(Room r, String portalName) { SuperRoot sr = SuperRoot.nameSearch(r.getDeepOwned(), portalName); return sr != null && sr instanceof Portal ? (Portal)sr : null; } public Portal connectTo(Portal far) { assert this._state == -1; this._farSideIsPortal = true; this._farSidePortal = far; this.newFarSide(); return this; } public Portal connectTo(URL farworld, String farroom, Point3Temp llc, Point3Temp urc) { return this.connectTo(farworld, farroom, llc.x, llc.y, llc.z, urc.x, urc.y, urc.z); } public Portal connectTo(Room r, Point3Temp llc, Point3Temp urc) { System.out.println("Warning! Old style Portal.connectTo called!"); Thread.dumpStack(); assert this._state == -1; this._farSideWorld = r.getWorld().getSourceURL(); this._farSideRoomName = r.getName(); this.setFarSideRoom(r); this._farx = this._userFarx = urc.x; this._fary = this._userFary = urc.y; this._farz = this._userFarz = llc.z; this._userFartheta = (float)(Math.atan2(llc.y - urc.y, llc.x - urc.x) * 180.0 / Math.PI); this._fartheta = this._userFartheta; this._state = 2; this._farSideIsPortal = false; this.setTransform(); this.updateVisible(); return this; } public Portal connectTo(URL farworld, String farroom, float llx, float lly, float llz, float urx, float ury, float urz) { float theta = (float)(Math.atan2(lly - ury, llx - urx) * 180.0 / Math.PI); return this.connectTo(farworld, farroom, urx, ury, llz, theta); } public Portal connectTo(URL farworld, String farroom, float x, float y, float z, float theta) { assert this._state == -1; this._farSideWorld = farworld; this._farSideRoomName = farroom; this._farx = this._userFarx = x; this._fary = this._userFary = y; this._farz = this._userFarz = z; this._fartheta = this._userFartheta = theta; this._farSideIsPortal = false; this.reset(); return this; } public Portal remotify() { RPAction rpa = new RPAction(); this.addAction(rpa); this.addHandler(new SameRoomSensor(rpa)); return this; } private void findFarSidePortal(boolean showmessage) { if (this._farSideIsPortal) { if (this._farSidePortalName == null) { this._state = -1; } else { this._farSidePortal = null; Vector portals = this._farSideRoom.getOutgoingPortals(); int len = portals.size(); for (int i = 0; i < len; i++) { Portal p = (Portal)portals.elementAt(i); if (p.getName().equals(this._farSidePortalName)) { this._farSidePortal = p; break; } } if (this._farSidePortal == null) { if (showmessage) { Object[] arguments = new Object[]{ new String(this.getName()), new String("" + this._farSideWorld), new String(this._farSideRoomName), new String(this._farSidePortalName) }; Console.println(MessageFormat.format(Console.message("Portal-doesnt"), arguments)); } this._state = -1; } } if (this._farSidePortal != null) { this.newFarSide(); } } else { this._farSidePortal = null; this._farx = this._userFarx; this._fary = this._userFary; this._farz = this._userFarz; this._fartheta = this._userFartheta; this._p2pxform = null; } } public void reset() { this.reset(true); } public void reset(boolean showmessage) { this.setFarSideRoom(null); if (this._farSideRoomName == null || (this.flags & 262144) != 0) { this._state = -1; } else if (this._farSideWorld == null) { Room r = this.getRoom(); if (r != null) { World w = r.getWorld(); if (w != null) { this.setFarSideRoom(w.getRoom(this._farSideRoomName)); } } if (this._farSideRoom != null) { this.findFarSidePortal(showmessage); } else { this._state = -1; this._farSidePortal = null; if (showmessage) { Object[] arguments = new Object[]{ new String(this.getName()), new String("" + this.getRoom()), new String(this._farSideRoomName), new String(this._farSidePortalName) }; Console.println(MessageFormat.format(Console.message("Room-doesnt"), arguments)); } } } else { if (this._farSidePortalName == null) { this._farSidePortal = null; } this._state = 0; } this.setTransform(); this.updateVisible(); } @Override public void discard() { Portal far = this._farSidePortal; this.setFarSideRoom(null); this._state = 0; super.discard(); if (far != null && far.getRoom() != null && this._farSideWorld != null) { far.reset(); } } private void recomputeFarPosition() { this.setFarSideRoom(this._farSidePortal.getRoom()); if (this._farSideRoom != null) { this._farSideRoomName = this._farSideRoom.getName(); } this._farSidePortalName = this._farSidePortal.getName(); Point3Temp farext = Point3Temp.make(1.0F, 0.0F, 1.0F).vectorTimes(this._farSidePortal); Point3Temp farlrc = this._farSidePortal.getPosition(); if ((this.flags & 4) == 0) { farlrc.x = farlrc.x + farext.x; farlrc.y = farlrc.y + farext.y; } this._farx = farlrc.x; this._fary = farlrc.y; this._farz = farlrc.z; this._fartheta = (-this._farSidePortal.getYaw() + 180.0F) % 360.0F; this._farChangeNum = this._farSidePortal._changeNum; this._p2pxform = null; } public Portal biconnect(Portal far) { this.connectTo(far); far.connectTo(this); return this; } public void disconnect() { this._farSideWorld = null; this._farSideRoomName = null; this.setFarSideRoom(null); this._farSidePortal = null; this._farSideIsPortal = true; this._farSidePortalName = null; this._state = -1; this.updateVisible(); this.discardTransform(); } public void bidisconnect() { this._farSidePortal.disconnect(); this.disconnect(); } public boolean connected() { return this._farSidePortal != null || this._farSideRoomName != null && !this._farSideIsPortal; } public boolean active() { return this._state == 2; } public boolean unconnected() { return this._state == -1; } public boolean remote() { return this._farSideWorld != null; } public Portal farSide() { return this._farSideIsPortal ? this._farSidePortal : null; } public Room farSideRoom() { return this._farSideRoom; } private void setFarSideRoom(Room far) { this._farSideRoom = far; } @Override protected void noteAddingTo(SuperRoot s) { this.addToRoom(s); super.noteAddingTo(s); } private void addToRoom(SuperRoot s) { if (s instanceof WObject) { Room r = ((WObject)s).getRoom(); if (r != null) { r.addOutgoingPortal(this); } } } @Override public void detach() { Room r = this.getRoom(); if (r != null) { r.removeOutgoingPortal(this); } super.detach(); } public String farRoom() { return this._farSideRoomName; } public URL farWorld() { return this._farSideWorld; } public Transform p2pXform() { return this._p2pxform; } @Override protected void addRwChildren(WObject parent) { if (this._farSidePortal != null && this._farSidePortal instanceof TwoWayPortal && !this._farSidePortal.isActive()) { Main.register(new MainCallback() { @Override public void mainCallback() { Portal.this.detach(); Main.unregister(this); } }); } super.addRwChildren(parent); this.updateVisible(); this.setTransform(); this.getRoom().prependPrerenderHandler(this); this.getRoom().prependPostrenderHandler(this); } @Override protected void markVoid() { this.getRoom().removePrerenderHandler(this); this.getRoom().removePostrenderHandler(this); super.markVoid(); } @Override protected void noteTransformChange() { this._changeNum++; super.noteTransformChange(); this.discardTransform(); } public static native void nativeInit(); @Override protected native void updateVisible(); native void setTransform(); public void discardTransform() { if (this._p2pxform != null) { this._p2pxform = null; if (this._farSidePortal != null) { this._farSidePortal.discardTransform(); } } } @Override public native void prerender(Camera var1); @Override public native void postrender(Camera var1); @Override public BumpCalc getBumpCalc(BumpEventTemp b) { if (this._farSidePortal == null || !(b.source instanceof Camera) || (this.flags & 4) == 0 && this._farSidePortal.active() && this._farSidePortal._p2pxform != null && this._farSidePortal.getVisible()) { if (this.bumpCalc != null) { return this.bumpCalc; } else if (this._farSideRoomName == null) { return standardPassthroughBumpCalc; } else { if (this.connected() && (this.flags & 262144) == 0) { if (this._farSideRoom == null && this._farSideIsPortal && this._farSidePortal != null) { this.setFarSideRoom(this._farSidePortal.getRoom()); } if (this._farSideRoom != null && this._farSideRoom.isActive()) { return standardPassthroughBumpCalc; } } return super.getBumpCalc(b); } } else { return super.getBumpCalc(b); } } @Override public boolean handle(BumpEventTemp b) { if (this._farSidePortal == null || !(b.source instanceof Camera) || (this.flags & 4) == 0 && this._farSidePortal.active() && this._farSidePortal._p2pxform != null && this._farSidePortal.getVisible()) { this.portalBumpHandler(b); return true; } else { return true; } } public void portalBumpHandler(BumpEventTemp b) { if (b.target == this && this._state == 2) { if (this._farSideRoom == null && this._farSideIsPortal && this._farSidePortal != null) { this.setFarSideRoom(this._farSidePortal.getRoom()); } if (this._farSideRoom != null && this._farSideRoom.isActive()) { if (this._p2pxform == null) { this.setTransform(); if (this._p2pxform == null) { return; } } b.postBumpRoom = this._farSideRoom; Transform t = ((WObject)b.source).getObjectToWorldMatrix(); b.postBumpPosition.setTransform(t); t.recycle(); b.postBumpPosition.moveBy(b.path).post(this._p2pxform); b.postBumpPath = new Point3(b.fullPath).times(1.0F - b.fraction).vectorTimes(this._p2pxform); } } else { if (this._state == 1 && this._farSideWorld != null && !this._farSideWorld.isRemote() && !this.frozeFrameEvents) { this.frozeFrameEvents = true; Console.setFreezeFrameEvents(true); } } } @Override public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { Object ret = null; switch (index - offset) { case 0: if (mode == 0) { ret = URLPropertyEditor.make(new Property(this, index, "Destination World URL (null means this world)").allowSetNull(), "world"); } else if (mode == 1) { ret = this._farSideWorld; } else if (mode == 2) { this._farSideWorld = (URL)value; this.reset(); this.triggerLoad(); } break; case 1: if (mode == 0) { ret = StringPropertyEditor.make(new Property(this, index, "Destination Room Name").allowSetNull()); } else if (mode == 1) { ret = this._farSideRoomName == null ? "" : this._farSideRoomName; } else if (mode == 2) { this._farSideRoomName = (String)value; if ("".equals(this._farSideRoomName)) { this._farSideRoomName = null; } this.reset(); this.triggerLoad(); } break; case 2: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Connect to a portal"), "Use location and orientation", "Use portal"); } else if (mode == 1) { ret = new Boolean(this._farSideIsPortal); } else if (mode == 2) { boolean tmp = (Boolean)value; this._farSideIsPortal = tmp; this.reset(); this.triggerLoad(); } break; case 3: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Download if world not present"), "Never download", "Allow download"); } else if (mode == 1) { ret = new Boolean(this._allowDownload); } else if (mode == 2) { boolean tmp = (Boolean)value; this._allowDownload = tmp; } break; case 4: if (mode == 0) { ret = new Property(this, index, "Destination Portal Name"); if (this._farSideIsPortal) { ret = StringPropertyEditor.make((Property)ret); } } else if (mode == 1) { ret = this._farSidePortalName == null ? "" : this._farSidePortalName; } else if (mode == 2) { this._farSidePortalName = (String)value; if ("".equals(this._farSidePortalName)) { this._farSidePortalName = null; } this.reset(); this.triggerLoad(); } break; case 5: if (mode == 0) { ret = new Property(this, index, "Destination position"); if (!this._farSideIsPortal) { ret = Point3PropertyEditor.make((Property)ret); } } else if (mode == 1) { ret = new Point3(this._userFarx, this._userFary, this._userFarz); } else if (mode == 2) { Point3 p = (Point3)value; this._farx = this._userFarx = p.x; this._fary = this._userFary = p.y; this._farz = this._userFarz = p.z; this.reset(); this.triggerLoad(); } break; case 6: if (mode == 0) { ret = new Property(this, index, "Destination orientation (degrees, clockwise from North)"); if (!this._farSideIsPortal) { ret = FloatPropertyEditor.make((Property)ret, 0.0F, 360.0F); } } else if (mode == 1) { ret = new Float(this._userFartheta); } else if (mode == 2) { this._fartheta = this._userFartheta = (Float)value; this.reset(); this.triggerLoad(); } break; case 7: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Mirrored"), "Normal", "Mirrored"); } else if (mode == 1) { ret = new Boolean((this.flags & 4) != 0); } else if (mode == 2) { if ((Boolean)value) { this.flags |= 4; } else { this.flags &= -5; } this.reset(); this.triggerLoad(); } break; default: ret = super.properties(index, offset + 8, mode, value); } return ret; } private void newFarSide() { this._farSidePortalName = this._farSidePortal.getName(); if (this._state == -1 && (this.flags & 262144) == 0) { this._state = 2; } this.recomputeFarPosition(); this.setTransform(); this.updateVisible(); } @Override public void saveState(Saver s) throws IOException { Portal tmp = null; if (this._farSideWorld != null || this._farSidePortal != null && (!this._farSidePortal.isActive() || this._farSidePortal instanceof NonPersister)) { tmp = this._farSidePortal; this._farSidePortal = null; } s.saveVersion(9, classCookie); super.saveState(s); s.saveBoolean(this._farSideIsPortal); s.saveBoolean(this._allowDownload); s.saveString(this._farSidePortalName); s.saveMaybeNull(this._farSidePortal); URL.save(s, this._farSideWorld); s.saveString(this._farSideRoomName); s.saveFloat(this._userFarx); s.saveFloat(this._userFary); s.saveFloat(this._userFarz); s.saveFloat(this._userFartheta); if (tmp != null) { this._farSidePortal = tmp; } } public void superRestoreState(Restorer r) throws IOException, TooNewException { this.restoreWObjectState(r); this.setMaterial(new Material(Color.black)); } @Override public void restoreState(Restorer r) throws IOException, TooNewException { float x = 0.0F; float y = 0.0F; float z = 0.0F; int vers = r.restoreVersion(classCookie); switch (vers) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: r.setOldFlag(); this.superRestoreState(r); if (vers < 6) { if (vers == 0) { r.restoreInt(); } x = r.restoreFloat(); y = r.restoreFloat(); z = r.restoreFloat(); this.scale(x, 1.0F, z); } if (r.restoreBoolean()) { this.flags |= 4; } if (vers >= 4) { this._farSidePortalName = r.restoreString(); } this._farSidePortal = (Portal)r.restoreMaybeNull(); if (vers == 1) { String n = r.restoreString(); if (!"".equals(n)) { this.setName(n); } } else if (vers >= 3) { if (vers >= 7) { this._farSideWorld = URL.restore(r); } else { this._farSideWorld = URL.restore(r, ".world"); } this._farSideRoomName = r.restoreString(); this._farx = r.restoreFloat(); this._fary = r.restoreFloat(); this._farz = r.restoreFloat(); this._fartheta = r.restoreFloat(); Material initialCover = Material.restore(r); Material downloadCover = Material.restore(r); if (initialCover != null) { this.setMaterial(initialCover); if (downloadCover != null && (initialCover.textureName == null || !initialCover.textureName.equals(downloadCover.textureName))) { System.out .println( "Both initial and download covers, " + initialCover.textureName + " and " + downloadCover.textureName + ", in " + this.getName() + " -- using initial." ); } } else { this.setMaterial(downloadCover); } if (vers >= 5) { this._farSideIsPortal = r.restoreBoolean(); } } break; case 8: case 9: super.restoreState(r); this._farSideIsPortal = r.restoreBoolean(); if (vers >= 9) { this._allowDownload = r.restoreBoolean(); } this._farSidePortalName = r.restoreString(); this._farSidePortal = (Portal)r.restoreMaybeNull(); this._farSideWorld = URL.restore(r); this._farSideRoomName = r.restoreString(); this._farx = r.restoreFloat(); this._fary = r.restoreFloat(); this._farz = r.restoreFloat(); this._fartheta = r.restoreFloat(); break; default: throw new TooNewException(); } if (vers <= 4 && this._farSideRoomName != null && this._farSidePortal == null && this._farSidePortalName == null) { this._farSideIsPortal = false; } this._userFarx = this._farx; this._userFary = this._fary; this._userFarz = this._farz; this._userFartheta = this._fartheta; } @Override public void postRestore(int version) { super.postRestore(version); if (this.getOwner() != null) { this.addToRoom(this.getOwner()); Room r = this.getOwner().getRoom(); if (this._farSidePortal == null) { this.reset(); } else { this.newFarSide(); } } } @Override public String toString() { String to; if (this._state == -1) { to = "(not connected)"; } else { if (this._farSideWorld != null) { to = this._farSideWorld.toString(); } else { to = ""; } if (this._farSideRoom != null) { to = to + "#" + this._farSideRoomName; } if (this._farSidePortalName != null) { to = to + "#" + this._farSidePortalName; } } return super.toString() + "[Connected To " + to + "]"; } public Portal triggerLoad() { if (this._farSideWorld != null && this._farSideRoomName != null) { if (this._farSidePortal != null && !this._farSidePortal.isActive()) { this.reset(); } if (this._state == 0) { this._state = 1; World.load(this._farSideWorld, this); } } return this; } @Override public void loadedURLSelf(URLSelf o, URL url, String err) { if (this.frozeFrameEvents) { this.frozeFrameEvents = false; Console.setFreezeFrameEvents(false); } if (this._state == 1) { if (err == null && o instanceof World) { World w = (World)o; this.setFarSideRoom(w.getRoom(this._farSideRoomName)); if (this._farSideRoom != null) { this._state = 2; this.findFarSidePortal(true); } else { Object[] arguments = new Object[]{new String(this._farSideRoomName), new String("" + this._farSideWorld)}; Console.println(MessageFormat.format(Console.message("Cant-find-remote"), arguments)); this._state = -1; } } else { if (err == null) { err = "doesn't contain a World"; o.decRef(); } String readable = TeleportAction.getReadableNameOfWorld(url); this._state = -1; if (this._allowDownload && !World.isProscribed(url, false)) { Object[] arguments = new Object[]{new String(readable)}; Console.println(MessageFormat.format(Console.message("Dont-have-world"), arguments)); String packageName = TeleportAction.getPackageNameOfWorld(url); if (packageName != null) { NetUpdate.loadWorld(packageName, false); } } } this.updateVisible(); } } }