summaryrefslogtreecommitdiff
path: root/NET/worlds/scape/Sharer.java
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-12 22:33:32 -0800
committerFuwn <[email protected]>2026-02-12 22:33:32 -0800
commitc7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch)
treedf9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/scape/Sharer.java
downloadworldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz
worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip
Initial commit
Diffstat (limited to 'NET/worlds/scape/Sharer.java')
-rw-r--r--NET/worlds/scape/Sharer.java590
1 files changed, 590 insertions, 0 deletions
diff --git a/NET/worlds/scape/Sharer.java b/NET/worlds/scape/Sharer.java
new file mode 100644
index 0000000..aaa03eb
--- /dev/null
+++ b/NET/worlds/scape/Sharer.java
@@ -0,0 +1,590 @@
+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<Attribute> 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<Attribute> noteQ;
+ Vector<Attribute> prepQ;
+ Vector<Attribute> sendQ;
+ private DynamicForwardAttribute dfa;
+ int lastSendTime;
+ private static Object classCookie = new Object();
+ private Vector<Object> restoredAttributes = null;
+
+ public Sharer() {
+ this.attributes = new Vector<Attribute>(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<Attribute> 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<Attribute> 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<Attribute> getAttributes() {
+ return this.getAttributesList().elements();
+ }
+
+ public Vector<Attribute> getAttributesList() {
+ Vector<Attribute> v = new Vector<Attribute>(this.attributes.size());
+ this.fillAttributesList(v);
+ return v;
+ }
+
+ public void fillAttributesList(Vector<Attribute> 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<Attribute>();
+ this.prepQ = new Vector<Attribute>();
+ this.sendQ = new Vector<Attribute>();
+ }
+
+ 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<LoadedAttribute> 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<Object>(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<Object> 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();
+ }
+ }
+ }
+}