diff --git a/runetek3-web/src/main/java/jagex2/io/WebClientStream.java b/runetek3-web/src/main/java/jagex2/io/WebClientStream.java new file mode 100644 index 00000000..c66750ff --- /dev/null +++ b/runetek3-web/src/main/java/jagex2/io/WebClientStream.java @@ -0,0 +1,153 @@ +package jagex2.io; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Queue; +import java.util.LinkedList; + +import org.teavm.interop.Async; +import org.teavm.interop.AsyncCallback; +import org.teavm.jso.dom.events.Event; +import org.teavm.jso.dom.events.EventListener; +import org.teavm.jso.dom.events.MessageEvent; +import org.teavm.jso.typedarrays.Int8Array; +import org.teavm.jso.websocket.CloseEvent; +import org.teavm.jso.websocket.WebSocket; + +public class WebClientStream { + private String host; + private boolean secure; + private int port; + + private WebSocket client; + private Queue queue = new LinkedList<>(); + private int remaining = 0; + private Int8Array buffer = null; + private int offset = 0; + + public WebClientStream(String host, int port) { + this.host = host.substring(host.indexOf("//") + 2); + this.secure = host.startsWith("https:"); + // tcp on main port, ws on main port + 1, wss on main port + 2 + this.port = secure ? port + 2 : port + 1; + } + + @Async + public native int connect(); + public void connect(AsyncCallback callback) { + String protocol = this.secure ? "wss" : "ws"; + this.client = WebSocket.create(protocol + "://" + this.host + ":" + this.port, "binary"); + this.client.setBinaryType("arraybuffer"); + + this.client.onMessage(new EventListener(){ + public void handleEvent(MessageEvent event) { + Int8Array data = Int8Array.create(event.getDataAsArray()); + remaining += data.getLength(); + queue.add(data); + }; + }); + + this.client.onOpen(new EventListener(){ + public void handleEvent(MessageEvent event) { + callback.complete(1); + } + }); + + this.client.onError(new EventListener(){ + public void handleEvent(Event event) { + callback.error(new IOException("WebSocket error")); + } + }); + } + + public void write(byte[] src, int length, int offset) throws IOException { + if (this.client.getReadyState() != 1) { + throw new IOException("Socket is not able to write"); + } + + Int8Array data = Int8Array.create(length); + + for (int i = 0; i < length; i++) { + data.set(i, src[offset + i]); + } + + this.client.send(data); + } + + // read 1 byte + public int read() throws IOException { + if (this.client.getReadyState() != 1) { + throw new IOException("Socket is not able to read"); + } + + if (this.remaining < 1) { + try { + Thread.sleep(5); + } catch (InterruptedException e) { + } + + return this.read(); + } + + if (this.buffer == null) { + this.buffer = this.queue.poll(); + this.offset = 0; + } + + int value = this.buffer.get(this.offset) & 0xFF; + this.offset++; + this.remaining--; + + if (this.offset == this.buffer.getLength()) { + this.buffer = null; + } + + return value; + } + + // read n bytes + public int read(byte[] destination, int off, int length) throws IOException { + if (this.client.getReadyState() != 1) { + throw new IOException("Socket is not able to read"); + } + + if (this.available() < length) { + try { + Thread.sleep(5); + } catch (InterruptedException e) { + } + + return this.read(destination, off, length); + } + + for (int i = 0; i < length; i++) { + destination[off + i] = (byte) this.read(); + } + + return length; + } + + public void close() { + if (this.client.getReadyState() != 1) { + return; + } + + this.client.close(); + } + + public int available() { + return this.remaining; + } + + public void clear() { + if (this.client.getReadyState() == 1) { + this.client.close(); + } + + this.queue.clear(); + + this.remaining = 0; + this.buffer = null; + this.offset = 0; + } +} diff --git a/runetek3-web/src/main/java/jagex2/io/WebSocket.java b/runetek3-web/src/main/java/jagex2/io/WebSocket.java deleted file mode 100644 index 02f08581..00000000 --- a/runetek3-web/src/main/java/jagex2/io/WebSocket.java +++ /dev/null @@ -1,162 +0,0 @@ -package jagex2.io; - -import org.teavm.interop.Async; -import org.teavm.interop.AsyncCallback; -import org.teavm.jso.dom.events.Event; -import org.teavm.jso.dom.events.EventListener; -import org.teavm.jso.dom.events.MessageEvent; -import org.teavm.jso.typedarrays.Int8Array; -import org.teavm.jso.websocket.CloseEvent; - -import java.io.IOException; -import java.util.ArrayList; - -public class WebSocket { - private String host; - private int port; - private org.teavm.jso.websocket.WebSocket client; - private boolean connected = false; - private int bytesAvailable = 0; - private ArrayList buffers = new ArrayList(); - private Int8Array currentBuffer; - private int offset = 0; - private int bytesLeft = 0; - - public WebSocket(String host, int port) { - this.host = host; - this.port = port; - } - - @Async - public native int connect(); - public void connect(AsyncCallback callback) { - boolean isSecure = this.host.startsWith("https:"); - this.client = org.teavm.jso.websocket.WebSocket.create((isSecure ? "wss" : "ws") + "://" + this.host.substring("http://".length()) + ":" + (isSecure ? this.port + 2 : this.port + 1), "binary"); - this.client.setBinaryType("arraybuffer"); - - this.client.onClose(new EventListener(){ - public void handleEvent(CloseEvent event) { - connected = false; - } - }); - - this.client.onMessage(new EventListener(){ - public void handleEvent(MessageEvent event) { - Int8Array toAdd = Int8Array.create(event.getDataAsArray()); - buffers.add(toAdd); - bytesAvailable += toAdd.getLength(); - refreshCurrentBuffer(); - }; - }); - - this.client.onOpen(new EventListener(){ - public void handleEvent(MessageEvent event) { - connected = true; - callback.complete(1); - } - }); - - this.client.onError(new EventListener(){ - public void handleEvent(Event event) { - connected = false; - callback.error(new IOException("WebSocket error")); - } - }); - } - - public void write(byte[] bytes, int length, int offset) throws IOException { - if (!this.connected) { - throw new IOException("Socket is not connected"); - } - - Int8Array toSend = Int8Array.create(length); - - for (int i = 0; i < length; i += 1) { - toSend.set(i, bytes[offset + i]); - } - - this.client.send(toSend); - } - - private void refreshCurrentBuffer() { - if (this.bytesLeft == 0 && this.bytesAvailable > 0) { - this.currentBuffer = this.buffers.remove(0); - this.offset = 0; - - if (this.currentBuffer != null && this.currentBuffer.getLength() > 0) { - this.bytesLeft = this.currentBuffer.getLength(); - } else { - this.bytesLeft = 0; - } - } - } - - public int read() throws IOException { - if (!this.connected) { - throw new IOException("Socket is not connected"); - } - - if (this.bytesLeft > 0) { - this.bytesLeft--; - this.bytesAvailable--; - return this.currentBuffer.get(this.offset++) & 0xff; - } - - try { - Thread.sleep(5); - } catch (InterruptedException e) { - } - - return this.read(); - } - - public int read(byte[] destination, int off, int length) throws IOException { - if (!this.connected) { - throw new IOException("Socket is not connected"); - } - - if (this.bytesAvailable >= length) { - while (length > 0) { - destination[off++] = this.currentBuffer.get(this.offset++); - this.bytesLeft -= 1; - this.bytesAvailable -= 1; - length -= 1; - - if (this.bytesLeft == 0) { - this.refreshCurrentBuffer(); - } - } - - return length; - } - - try { - Thread.sleep(5); - } catch (InterruptedException e) { - } - - return this.read(destination, offset, length); - } - - public void close() { - if (!this.connected) { - return; - } - - this.client.close(); - } - - public int available() { - return this.bytesAvailable; - } - - public void clear() { - if (this.connected) { - this.client.close(); - } - - this.currentBuffer = null; - this.buffers.clear(); - this.bytesLeft = 0; - } -} diff --git a/webclient/src/main/java/jagex2/client/Client.java b/webclient/src/main/java/jagex2/client/Client.java index 61efc034..d314763b 100644 --- a/webclient/src/main/java/jagex2/client/Client.java +++ b/webclient/src/main/java/jagex2/client/Client.java @@ -785,7 +785,7 @@ public final class Client extends GameShell { public static int updateGame; @OriginalMember(owner = "client!client", name = "Uf", descriptor = "Lclient!d;") - private WebSocket connection; + private WebClientStream connection; @OriginalMember(owner = "client!client", name = "Vf", descriptor = "[[B") private byte[][] sceneMapLocData; @@ -7402,7 +7402,7 @@ protected void unload() { } @OriginalMember(owner = "client!client", name = "A", descriptor = "(I)Ljava/net/Socket;") - private WebSocket openSocket(@OriginalArg(0) int arg0) throws IOException { + private WebClientStream openSocket(@OriginalArg(0) int arg0) throws IOException { return Signlink.opensocket(arg0); } @@ -7735,9 +7735,11 @@ private void updateGame() { this.out.pos = 0; this.heartbeatTimer = 0; } - } catch (@Pc(1001) IOException local1001) { + } catch (@Pc(1001) IOException ex) { + ex.printStackTrace(); this.tryReconnect(); - } catch (@Pc(1006) Exception local1006) { + } catch (@Pc(1006) Exception ex) { + ex.printStackTrace(); this.logout(); } } @@ -7913,9 +7915,6 @@ private boolean tryMove(@OriginalArg(0) int arg0, @OriginalArg(1) int arg1, @Ori } @Pc(882) byte local882 = 0; this.bfsStepX[local882] = local11; - if (arg5 != 0) { - this.packetType = this.in.g1(); - } local57 = local882 + 1; this.bfsStepZ[local882] = local39; local193 = local809 = this.bfsDirection[local11][local39]; @@ -8553,7 +8552,7 @@ private void tryReconnect() { this.fontPlain12.drawStringCenter(158, 16777215, "Please wait - attempting to reestablish", 256); this.areaViewport.draw(11, this.context, 8); this.flagSceneTileX = 0; - @Pc(60) WebSocket local60 = this.connection; + @Pc(60) WebClientStream local60 = this.connection; this.ingame = false; this.login(this.username, this.password, true); if (!this.ingame) { @@ -9439,7 +9438,7 @@ private boolean read() { this.connection.read(this.in.data, 0, 1); this.packetType = this.in.data[0] & 0xFF; if (this.randomIn != null) { - this.packetType = this.packetType - this.randomIn.nextInt() & 0xFF; + this.packetType = (this.packetType - this.randomIn.nextInt()) & 0xFF; } this.packetSize = ServerProt.PACKET_LENGTHS[this.packetType]; local15--; @@ -10482,9 +10481,11 @@ private boolean read() { } Signlink.reporterror("T1 - " + this.packetType + "," + this.packetSize + " - " + this.lastPacketType1 + "," + this.lastPacketType2); this.logout(); - } catch (@Pc(3862) IOException local3862) { + } catch (@Pc(3862) IOException ex) { + ex.printStackTrace(); this.tryReconnect(); - } catch (@Pc(3867) Exception local3867) { + } catch (@Pc(3867) Exception ex) { + ex.printStackTrace(); local1264 = "T2 - " + this.packetType + "," + this.lastPacketType1 + "," + this.lastPacketType2 + " - " + this.packetSize + "," + (this.sceneBaseTileX + this.localPlayer.pathTileX[0]) + "," + (this.sceneBaseTileZ + this.localPlayer.pathTileZ[0]) + " - "; for (local462 = 0; local462 < this.packetSize && local462 < 50; local462++) { local1264 = local1264 + this.in.data[local462] + ","; diff --git a/webclient/src/main/java/jagex2/client/Signlink.java b/webclient/src/main/java/jagex2/client/Signlink.java index f8691b40..0a91bc8c 100644 --- a/webclient/src/main/java/jagex2/client/Signlink.java +++ b/webclient/src/main/java/jagex2/client/Signlink.java @@ -2,7 +2,7 @@ import jagex2.io.DatabaseStore; import jagex2.io.FileDownloadStream; -import jagex2.io.WebSocket; +import jagex2.io.WebClientStream; import org.openrs2.deob.annotation.OriginalArg; import org.openrs2.deob.annotation.OriginalClass; import org.openrs2.deob.annotation.OriginalMember; @@ -58,7 +58,7 @@ public final class Signlink implements Runnable { public static int wavevol = 192; @OriginalMember(owner = "client!sign/signlink", name = "socket", descriptor = "Ljava/net/Socket;") - private static WebSocket socket = null; + private static WebClientStream socket = null; @OriginalMember(owner = "client!sign/signlink", name = "threadreqpri", descriptor = "I") private static int threadreqpri = 1; @@ -181,7 +181,7 @@ public static synchronized void cachesave(@OriginalArg(0) String arg0, @Original } @OriginalMember(owner = "client!sign/signlink", name = "opensocket", descriptor = "(I)Ljava/net/Socket;") - public static synchronized WebSocket opensocket(@OriginalArg(0) int arg0) throws IOException { + public static synchronized WebClientStream opensocket(@OriginalArg(0) int arg0) throws IOException { socketreq = arg0; while (socketreq != 0) { try { @@ -342,7 +342,7 @@ public void run() { if (socketreq != 0) { try { - socket = new WebSocket(socketip, socketreq); + socket = new WebClientStream(socketip, socketreq); socket.connect(); } catch (@Pc(19) Exception local19) { socket = null;