package NET.worlds.scape; import NET.worlds.console.Console; import NET.worlds.console.Main; import NET.worlds.console.MainCallback; import NET.worlds.core.Std; import NET.worlds.network.InfiniteWaitException; import NET.worlds.network.ObjID; import NET.worlds.network.PacketTooLargeException; import NET.worlds.network.PropertyList; import NET.worlds.network.PropertySetCmd; import NET.worlds.network.WorldServer; import NET.worlds.network.net2Property; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.text.MessageFormat; import java.util.Enumeration; import java.util.Vector; public class Sharer extends SuperRoot implements MainCallback { private Vector attributes; private ByteArrayOutputStream bs = new ByteArrayOutputStream(); private boolean shared = false; public static final int FIRST_TIME = 0; public static final int STATIC = 2; public static final int FORWARDED_STATIC = 3; public static final int DYNAMIC = 4; public static final int FORWARDED_DYNAMIC = 5; public static final int FORWARDED = 1; private boolean createdFromNet; Vector noteQ; Vector prepQ; Vector sendQ; private DynamicForwardAttribute dfa; int lastSendTime; private static Object classCookie = new Object(); private Vector restoredAttributes = null; public Sharer() { this.attributes = new Vector(256); this.attributes.setSize(256); } public boolean isShared() { return this.shared; } private int getMaybeDefaultMode() { return ((WObject)this.getOwner()).getSharerMode(); } public int getMode() { int mode = this.getMaybeDefaultMode(); if (mode == 0) { this.setMode(mode); } return mode; } public void setMode(int mode) { WObject w = (WObject)this.getOwner(); if (w instanceof Room) { mode = 2; } else if (this.createdFromNet) { mode = 4; } else if (mode == 2 || mode == 4) { mode = 0; } if (mode == 0) { mode = 3; } int oldMode = this.getMaybeDefaultMode(); if (oldMode != mode) { this.unshare(); w.setSharerMode(mode); } this.share(); } public void createDynamicForwardedFromNet(DynamicForwardAttribute dfa) { assert !((WObject)this.getOwner()).isActive(); this.dfa = dfa; ((WObject)this.getOwner()).setSharerMode(5); } public void createDynamicFromNet() { assert !((WObject)this.getOwner()).isActive() || this.createdFromNet; this.createdFromNet = true; ((WObject)this.getOwner()).setSharerMode(4); } public void adjustShare() { this.share(); } private void share() { if (!this.shared) { int mode = this.getMaybeDefaultMode(); switch (mode) { case 0: this.setMode(0); case 1: case 2: default: break; case 3: this.flushQueue(); Enumeration e = this.getAttributes(); while (e.hasMoreElements()) { e.nextElement().addForwarding(); } break; case 4: assert this.createdFromNet; break; case 5: if (this.dfa == null) { this.flushQueue(); WObject w = (WObject)this.getOwner(); WObject terminal = w.getServed(); if (w.getSourceURL() != null && terminal != null) { this.dfa = new DynamicForwardAttribute(-1); if (terminal.getSharer().addAttribute(this.dfa) == -1) { this.dfa = null; } else { this.dfa.connect(w); } } } } this.shared = true; } } private void unshare() { if (this.shared) { int mode = this.getMaybeDefaultMode(); switch (mode) { case 2: case 4: default: break; case 3: Enumeration e = this.getAttributes(); while (e.hasMoreElements()) { e.nextElement().unforward(); } break; case 5: if (this.dfa != null) { this.dfa.unconnect(); this.dfa = null; } } this.shared = false; } } public int addAttribute(Attribute a) { this.setMode(this.getMaybeDefaultMode()); a._attrID = this.getFreeAttrIDFor(a, a._attrID); if (a._attrID == -1) { return a._attrID; } else { try { this.add(a); } catch (ClassCastException var3) { Console.println(Console.message("Cant-attach") + var3); a._attrID = -1; return a._attrID; } this.attributes.setElementAt(a, a._attrID); if (this.getMaybeDefaultMode() == 3) { a.addForwarding(); } return a._attrID; } } public boolean attrIDAvailable(int id) { return this.attributes.elementAt(id) == null; } private int getFreeAttrID(int id, int low, int high) { if (id >= 20 && id <= 255 && this.attrIDAvailable(id)) { return id; } else { int freeCount = this.countFree(low, high); if (freeCount == 0) { return -1; } else { int i; label42: while (true) { int pos = (int)(Math.random() * freeCount); i = low; while (true) { if (this.attributes.elementAt(i) == null) { if (--pos < 0) { assert i <= high; if (i != 150 && i != 155 && i != 160) { break label42; } break; } } i++; } } return i; } } } public int getFreeAttrIDFor(Attribute a, int id) { return a instanceof DynamicForwardAttribute ? this.getFreeAttrID(id, 210, 249) : this.getFreeAttrID(id, 100, 249); } public void removeAttribute(Attribute a) { a.detach(); if (a.getOwner() == null) { this.attributes.setElementAt(null, a._attrID); } } public int resetAttributeID(Attribute a, int newID) { newID = this.getFreeAttrIDFor(a, newID); if (newID == -1) { return newID; } else { if (this.attributes.elementAt(newID) == null) { int oldID = a._attrID; this.attributes.setElementAt(a, newID); this.attributes.setElementAt(null, oldID); a._attrID = newID; } return newID; } } public void moveToSlot(WObject child, int newID) { if (child.isDynamic()) { Sharer s = child.getSharer(); if (s.dfa != null) { this.resetAttributeID(s.dfa, newID); } } } public Enumeration getAttributes() { return this.getAttributesList().elements(); } public Vector getAttributesList() { Vector v = new Vector(this.attributes.size()); this.fillAttributesList(v); return v; } public void fillAttributesList(Vector v) { int end = this.attributes.size(); for (int i = 0; i < end; i++) { Attribute a = this.attributes.elementAt(i); if (a != null) { v.addElement(a); } } } public Attribute getAttribute(int id) { try { return this.attributes.elementAt(id); } catch (ArrayIndexOutOfBoundsException var3) { return null; } } public boolean isEmpty() { return this.countFree(0, 255) == 256; } public int countFree(int low, int high) { int count = 0; for (int i = low; i <= high; i++) { if (this.attributes.elementAt(i) == null) { count++; } } return count; } @Override public void getChildren(DeepEnumeration d) { d.addChildVectorWithNulls(this.attributes); } public void noteChange(Attribute a, boolean sendTriggers) { assert Main.isMainThread(); if (this.prepQ == null) { this.noteQ = new Vector(); this.prepQ = new Vector(); this.sendQ = new Vector(); } if (sendTriggers && !this.noteQ.contains(a)) { if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { Main.register(this); } this.noteQ.addElement(a); } Attribute fa; if (this.getMode() == 3 && (fa = a.getForwardAttribute()) != null) { fa.noteChange(); } else if (this.dfa != null) { this.dfa.noteChange(); } else if (!this.prepQ.contains(a)) { if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { Main.register(this); } this.prepQ.addElement(a); } } private void prepQueue() { if (!this.noteQ.isEmpty()) { int end = this.noteQ.size(); for (int i = 0; i < end; i++) { Attribute a = this.noteQ.elementAt(i); ValueEvent e = new ValueEvent(Std.getFastTime(), this.getOwner(), (WObject)this.getOwner(), a); a.trigger(e); } this.noteQ.removeAllElements(); } int end = this.prepQ.size(); for (int i = 0; i < end; i++) { Attribute a = this.prepQ.elementAt(i); this.bs.reset(); try { a.generateNetData(new DataOutputStream(this.bs)); } catch (IOException var5) { System.err.println(var5); throw new Error("Fatal in generateNetData"); } a._outgoing = this.bs.toByteArray(); if (Std.byteArraysEqual(a._outgoing, a._serverData)) { a._outgoing = null; } else if (!this.sendQ.contains(a)) { this.sendQ.addElement(a); } } this.prepQ.removeAllElements(); } @Override public void mainCallback() { if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { Main.unregister(this); } else { int frameTime = Std.getFastTime(); if (frameTime > this.lastSendTime + 250) { this.sendQueue(); Main.unregister(this); this.lastSendTime = frameTime; } } } private void flushQueue() { if (this.prepQ != null) { this.prepQueue(); if (!this.sendQ.isEmpty()) { int i = this.sendQ.size(); while (--i >= 0) { Attribute a = this.sendQ.elementAt(i); a._waitingForFeedback = false; a._serverData = null; a._outgoing = null; } this.sendQ.removeAllElements(); } } } private void sendQueue() { this.prepQueue(); WorldServer rs = ((WObject)this.getOwner()).getServer(); if (rs != null) { int end = this.sendQ.size(); for (int i = 0; i < end; i++) { Attribute a = this.sendQ.elementAt(i); if (a._outgoing != null) { this.share(rs, a); a._serverData = a._outgoing; a._outgoing = null; a._waitingForFeedback = true; } } } this.sendQ.removeAllElements(); } private void share(WorldServer ws, Attribute a) { SuperRoot w = this.getOwner(); ObjID objID = null; if (w instanceof Room) { Pilot pilot = Pilot.getActive(); if (pilot != null && pilot.getLastServedRoom() != w) { objID = new ObjID(((Room)w).getNetworkRoom().getLongID()); } else { objID = new ObjID(253); } } else if (w instanceof Pilot) { objID = new ObjID(1); } else { objID = new ObjID(w.getName()); } try { PropertyList propList = new PropertyList(); propList.addProperty(new net2Property(a._attrID, a.getFlags(), a.getAccessFlags(), a._outgoing)); ws.sendNetworkMsg(new PropertySetCmd(objID, propList)); } catch (InfiniteWaitException var6) { Console.println(Console.message("Net-shutdown") + var6.toString()); } catch (PacketTooLargeException var7) { assert false; } } public void setFromNetData(int attrID, byte[] data) { if (this.prepQ != null) { this.prepQueue(); } Attribute a = this.getAttribute(attrID); if (a == null) { if ((this.getMode() & 1) != 0) { Object[] arguments = new Object[]{new String("" + attrID), new String(this.getOwner().getName())}; Console.println(MessageFormat.format(Console.message("Unknown-attr"), arguments)); return; } a = new DynamicForwardAttribute(attrID); this.addAttribute(a); } this.setData(a, data); if (!a.loaded) { a.loaded = true; if (a.callbacks != null && a.callbacks.size() > 0) { Enumeration e = a.callbacks.elements(); while (e.hasMoreElements()) { LoadedAttribute la = e.nextElement(); la.loadedAttribute(a, null); } a.callbacks.removeAllElements(); } } } private void setData(Attribute a, byte[] data) { boolean matchesLastSent = Std.byteArraysEqual(data, a._serverData); if (a._waitingForFeedback) { if (!matchesLastSent) { return; } a._waitingForFeedback = false; if (data.length != 0 || a._outgoing != null) { return; } } else if (matchesLastSent) { return; } a._serverData = data; if (Std.byteArraysEqual(data, a._outgoing)) { a._outgoing = null; } else if (a._outgoing == null) { try { a.setFromNetData(new DataInputStream(new ByteArrayInputStream(data)), data.length); } catch (IOException var5) { var5.printStackTrace(); Console.println(Console.message("Unrec-format") + a.getName()); } ValueEvent e = new ValueEvent(Std.getFastTime(), this, (WObject)this.getOwner(), a); a.trigger(e); } } @Override public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { throw new NoSuchPropertyException(); } @Override public void saveState(Saver s) throws IOException { s.saveVersion(2, classCookie); super.saveState(s); s.saveVector(this.getAttributesList()); } @Override public void restoreState(Restorer r) throws IOException, TooNewException { switch (r.restoreVersion(classCookie)) { case 0: this.setName(r.restoreString()); int nSharedAtts = r.restoreInt(); this.restoredAttributes = new Vector(nSharedAtts); for (int i = 0; i < nSharedAtts; i++) { this.restoredAttributes.addElement(r.restoreString()); } break; case 1: this.setName(r.restoreString()); this.restoredAttributes = r.restoreVector(); break; case 2: super.restoreState(r); this.restoredAttributes = r.restoreVector(); break; default: throw new TooNewException(); } } public void ownerPostRestore() { int desiredMode = this.getMaybeDefaultMode(); ((WObject)this.getOwner()).setSharerMode(0); this.setMode(desiredMode); Enumeration e = this.restoredAttributes.elements(); while (e.hasMoreElements()) { Attribute a = (Attribute)e.nextElement(); this.addAttribute(a); } this.restoredAttributes = null; } public void releaseAuxilaryData() { for (int i = 0; i < 256; i++) { Attribute a = this.attributes.elementAt(i); if (a != null) { a.releaseAuxilaryData(); } } } }