From 0a9e4ea3f38dcb8337c27d16eded7c218b65e9d1 Mon Sep 17 00:00:00 2001 From: PeytonPlayz595 <106421860+PeytonPlayz595@users.noreply.github.com> Date: Tue, 19 Dec 2023 22:25:00 -0500 Subject: [PATCH] Fix several crashes, added Multiplayer menu --- .../java/com/mojang/minecraft/Minecraft.java | 64 ++--- .../com/mojang/minecraft/SessionData.java | 2 - .../mojang/minecraft/SleepForeverThread.java | 27 -- .../com/mojang/minecraft/gui/HUDScreen.java | 5 +- .../com/mojang/minecraft/gui/MainMenu.java | 54 ++++ .../mojang/minecraft/gui/MultiplayerMenu.java | 137 ++++++++++ .../com/mojang/minecraft/level/LevelIO.java | 258 ------------------ .../mojang/minecraft/net/NetworkManager.java | 4 +- ...rConnectThread.java => ServerConnect.java} | 7 +- .../java/com/mojang/net/NetworkHandler.java | 62 +---- .../net/PeytonPlayz585/level/LevelUtils.java | 2 +- .../websocket/WebSocketChannel.java | 102 +++++++ .../java/net/lax1dude/eaglercraft/Client.java | 6 +- .../adapter/EaglerAdapterImpl2.java | 55 ---- 14 files changed, 345 insertions(+), 440 deletions(-) delete mode 100644 src/teavm/java/com/mojang/minecraft/SleepForeverThread.java create mode 100644 src/teavm/java/com/mojang/minecraft/gui/MainMenu.java create mode 100644 src/teavm/java/com/mojang/minecraft/gui/MultiplayerMenu.java delete mode 100644 src/teavm/java/com/mojang/minecraft/level/LevelIO.java rename src/teavm/java/com/mojang/minecraft/net/{ServerConnectThread.java => ServerConnect.java} (83%) create mode 100644 src/teavm/java/net/PeytonPlayz585/websocket/WebSocketChannel.java diff --git a/src/teavm/java/com/mojang/minecraft/Minecraft.java b/src/teavm/java/com/mojang/minecraft/Minecraft.java index b5ca645..57a3ed4 100644 --- a/src/teavm/java/com/mojang/minecraft/Minecraft.java +++ b/src/teavm/java/com/mojang/minecraft/Minecraft.java @@ -7,7 +7,6 @@ import com.mojang.minecraft.gui.*; import com.mojang.minecraft.item.Arrow; import com.mojang.minecraft.item.Item; import com.mojang.minecraft.level.Level; -import com.mojang.minecraft.level.LevelIO; import com.mojang.minecraft.level.generator.LevelGenerator; import com.mojang.minecraft.level.liquid.LiquidType; import com.mojang.minecraft.level.tile.Block; @@ -41,8 +40,9 @@ import java.io.*; import java.nio.IntBuffer; import java.util.Collections; import java.util.List; +import java.util.zip.GZIPInputStream; -public final class Minecraft implements Runnable { +public final class Minecraft { public GameMode gamemode = new SurvivalGameMode(this); public int width; @@ -60,7 +60,6 @@ public final class Minecraft implements Runnable { public GuiScreen currentScreen = null; public ProgressBarDisplay progressBar = new ProgressBarDisplay(this); public Renderer renderer = new Renderer(this); - public LevelIO levelIo; private int ticks; private int blockHitTime; public String levelName; @@ -82,7 +81,6 @@ public final class Minecraft implements Runnable { public Minecraft() { - this.levelIo = new LevelIO(this.progressBar); this.ticks = 0; this.blockHitTime = 0; this.levelName = null; @@ -96,7 +94,6 @@ public final class Minecraft implements Runnable { this.hasMouse = false; this.lastClick = 0; this.raining = false; - new SleepForeverThread(this); this.width = GL11.getCanvasWidth(); this.height = GL11.getCanvasHeight(); } @@ -107,14 +104,16 @@ public final class Minecraft implements Runnable { this.currentScreen.onClose(); } - if(var1 == null && this.player.health <= 0) { + if(var1 == null && level != null && player != null && this.player.health <= 0) { var1 = new GameOverScreen(); } this.currentScreen = (GuiScreen)var1; if(var1 != null) { if(this.hasMouse) { - this.player.releaseAllKeys(); + if(level != null) { + this.player.releaseAllKeys(); + } this.hasMouse = false; GL11.mouseSetGrabbed(false); } @@ -168,18 +167,7 @@ public final class Minecraft implements Runnable { Item.initModels(); Mob.modelCache = new ModelManager(); GL11.glViewport(0, 0, this.width, this.height); - if(this.server != null) { - Level var85; - (var85 = new Level()).setData(8, 8, 8, new byte[512]); - this.setLevel(var85, false); - } else { - Level level1 = new LevelUtils().load(); - if(level1 == null) { - this.generateLevel(1); - } else { - this.setLevel(level1, true); - } - } + this.setCurrentScreen(new MainMenu()); this.particleManager = new ParticleManager(this.level); checkGLError("Post startup"); this.hud = new HUDScreen(this, this.width, this.height); @@ -899,7 +887,7 @@ public final class Minecraft implements Runnable { } public final void grabMouse() { - if(!GL11.isFocused()) { + if(!GL11.isFocused() || level == null) { return; } if (GL11.isPointerLocked2()) { @@ -924,7 +912,7 @@ public final class Minecraft implements Runnable { } public final void pause() { - if(this.currentScreen == null) { + if(this.currentScreen == null && level != null) { this.setCurrentScreen(new PauseScreen()); } } @@ -1068,10 +1056,10 @@ public final class Minecraft implements Runnable { NetworkManager var20 = this.networkManager; if(this.networkManager.successful) { NetworkHandler var18 = var20.netHandler; - if(GL11.connectionOpen()) { + if(var18.channel.connectionOpen()) { try { NetworkHandler var22 = var20.netHandler; - var20.netHandler.read(var22.in); + var20.netHandler.channel.read(var22.in); var4 = 0; while(var22.in.position() > 0 && var4++ != 100) { @@ -1115,8 +1103,18 @@ public final class Minecraft implements Runnable { } catch (IOException var14) { var14.printStackTrace(); } - - byte[] var51 = LevelIO.decompress(new ByteArrayInputStream(var42.levelData.toByteArray())); + + byte[] var51; + try { + DataInputStream var3; + byte[] var1 = new byte[(var3 = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(var42.levelData.toByteArray())))).readInt()]; + var3.readFully(var1); + var3.close(); + var51 = var1; + } catch (Exception var2) { + throw new RuntimeException(var2); + } + var42.levelData = null; short var55 = ((Short)var7[0]).shortValue(); short var63 = ((Short)var7[1]).shortValue(); @@ -1264,7 +1262,7 @@ public final class Minecraft implements Runnable { } } - if(!GL11.connectionOpen()) { + if(!var22.channel.connectionOpen()) { break; } @@ -1273,7 +1271,7 @@ public final class Minecraft implements Runnable { if(var22.out.position() > 0) { var22.out.flip(); - var22.write(var22.out); + var22.channel.write(var22.out); var22.out.compact(); } } catch (Exception var15) { @@ -1352,7 +1350,7 @@ public final class Minecraft implements Runnable { } while(GL11.keysNext()) { - this.player.setKey(GL11.getEventKey(), GL11.getEventKeyState()); + this.player.setKey(GL11.getEventKey(), GL11.getEventKeyState()); if(GL11.getEventKeyState()) { if(this.currentScreen != null) { this.currentScreen.keyboardEvent(); @@ -1507,7 +1505,9 @@ public final class Minecraft implements Runnable { this.particleManager.tick(); } - this.player.arrows = 1; + if(player != null) { + this.player.arrows = 1; + } } @@ -1515,12 +1515,12 @@ public final class Minecraft implements Runnable { private void levelSave() { if(this.level == null) { - ticksUntilSave = this.hud.ticks + 600; + ticksUntilSave = this.ticks + 600; } - if(this.hud.ticks >= this.ticksUntilSave) { + if(this.ticks >= this.ticksUntilSave) { new LevelUtils().save(); - ticksUntilSave = this.hud.ticks + 600; + ticksUntilSave = this.ticks + 600; } } diff --git a/src/teavm/java/com/mojang/minecraft/SessionData.java b/src/teavm/java/com/mojang/minecraft/SessionData.java index 64452a3..fc5595f 100644 --- a/src/teavm/java/com/mojang/minecraft/SessionData.java +++ b/src/teavm/java/com/mojang/minecraft/SessionData.java @@ -10,8 +10,6 @@ public final class SessionData { public String username; public String sessionId; public String mppass; - public boolean haspaid; - public SessionData(String var1, String var2) { this.username = var1; diff --git a/src/teavm/java/com/mojang/minecraft/SleepForeverThread.java b/src/teavm/java/com/mojang/minecraft/SleepForeverThread.java deleted file mode 100644 index d64606b..0000000 --- a/src/teavm/java/com/mojang/minecraft/SleepForeverThread.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.mojang.minecraft; - -public class SleepForeverThread extends Thread -{ - public SleepForeverThread(Minecraft minecraft) - { - setDaemon(true); - - start(); - } - - @Override - public void run() - { - while(true) - { - try { - while(true) - { - Thread.sleep(2147483647L); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } -} diff --git a/src/teavm/java/com/mojang/minecraft/gui/HUDScreen.java b/src/teavm/java/com/mojang/minecraft/gui/HUDScreen.java index 4e53cd6..782265f 100644 --- a/src/teavm/java/com/mojang/minecraft/gui/HUDScreen.java +++ b/src/teavm/java/com/mojang/minecraft/gui/HUDScreen.java @@ -33,13 +33,16 @@ public final class HUDScreen extends Screen { this.width = var2 * 240 / var3; this.height = var3 * 240 / var3; - if(firstTimeLaunch) { + if(firstTimeLaunch && Minecraft.getMinecraft().level != null) { mc.setCurrentScreen(new PauseScreen()); firstTimeLaunch = false; } } public final void render(float var1, boolean var2, int var3, int var4) { + if(Minecraft.getMinecraft().level == null) { + return; + } FontRenderer var5 = this.mc.fontRenderer; this.mc.renderer.enableGuiMode(); new TextureLocation("/gui/gui.png").bindTexture(); diff --git a/src/teavm/java/com/mojang/minecraft/gui/MainMenu.java b/src/teavm/java/com/mojang/minecraft/gui/MainMenu.java new file mode 100644 index 0000000..e1fa4c1 --- /dev/null +++ b/src/teavm/java/com/mojang/minecraft/gui/MainMenu.java @@ -0,0 +1,54 @@ +package com.mojang.minecraft.gui; + +import org.lwjgl.opengl.GL11; + +import com.mojang.minecraft.Minecraft; +import com.mojang.minecraft.level.Level; +import com.mojang.minecraft.render.TextureLocation; + +import net.PeytonPlayz585.level.LevelUtils; +import net.lax1dude.eaglercraft.adapter.Tessellator; + +public class MainMenu extends GuiScreen { + + public final void onOpen() { + this.buttons.clear(); + this.buttons.add(new Button(1, this.width / 2 - 100, this.height / 4 + 48, "Singleplayer")); + this.buttons.add(new Button(2, this.width / 2 - 100, this.height / 4 + 72, "Multiplayer")); + } + + protected final void onButtonClick(Button var1) { + if(var1.id == 1) { + Level level1 = new LevelUtils().load(); + if(level1 == null) { + Minecraft.getMinecraft().setCurrentScreen(null); + this.minecraft.generateLevel(1); + this.minecraft.player.releaseAllKeys(); + } else { + Minecraft.getMinecraft().setCurrentScreen(null); + this.minecraft.setLevel(level1, true); + this.minecraft.player.releaseAllKeys(); + } + } else if(var1.id == 2) { + this.minecraft.setCurrentScreen(new MultiplayerMenu()); + } + } + + public final void render(int var1, int var2) { + int var4 = this.minecraft.width * 240 / this.minecraft.height; + int var5 = this.minecraft.height * 240 / this.minecraft.height; + GL11.glClear(16640); + Tessellator tessellator = Tessellator.instance; + int var7 = new TextureLocation("/dirt.png").bindTexture(); + float var10 = 32.0F; + tessellator.startDrawing(7); + tessellator.setColorOpaque_I(4210752); + tessellator.addVertexWithUV(0.0F, (float)var5, 0.0F, 0.0F, (float)var5 / var10); + tessellator.addVertexWithUV((float)var4, (float)var5, 0.0F, (float)var4 / var10, (float)var5 / var10); + tessellator.addVertexWithUV((float)var4, 0.0F, 0.0F, (float)var4 / var10, 0.0F); + tessellator.addVertexWithUV(0.0F, 0.0F, 0.0F, 0.0F, 0.0F); + tessellator.draw(); + super.render(var1, var2); + } + +} diff --git a/src/teavm/java/com/mojang/minecraft/gui/MultiplayerMenu.java b/src/teavm/java/com/mojang/minecraft/gui/MultiplayerMenu.java new file mode 100644 index 0000000..2a932e5 --- /dev/null +++ b/src/teavm/java/com/mojang/minecraft/gui/MultiplayerMenu.java @@ -0,0 +1,137 @@ +package com.mojang.minecraft.gui; + +import org.lwjgl.opengl.GL11; + +import com.mojang.minecraft.Minecraft; +import com.mojang.minecraft.SessionData; +import com.mojang.minecraft.level.Level; +import com.mojang.minecraft.net.NetworkManager; +import com.mojang.minecraft.render.TextureLocation; + +import net.PeytonPlayz585.level.LevelUtils; +import net.lax1dude.eaglercraft.adapter.Tessellator; + +public class MultiplayerMenu extends GuiScreen { + + boolean textBox1Active = false; + boolean textBox2Active = false; + private int counter = 0; + String server = ""; + String username = ""; + Button connect; + + public final void onOpen() { + GL11.enableRepeatEvents(true); + this.buttons.clear(); + this.buttons.add(connect = new Button(0, this.width / 2 - 100, this.height / 4 + 96 + 12, "Connect")); + this.buttons.add(new Button(1, this.width / 2 - 100, this.height / 4 + 120 + 12, "Cancel")); + connect.active = false; + } + + public final void tick() { + ++this.counter; + } + + protected final void onButtonClick(Button var1) { + if(var1.id == 0 && var1.active) { + GL11.enableRepeatEvents(false); + minecraft.session = new SessionData(this.username, "mcpass"); + Level var85; + (var85 = new Level()).setData(8, 8, 8, new byte[512]); + minecraft.setLevel(var85, false); + minecraft.networkManager = new NetworkManager(minecraft, this.server, minecraft.session.username, minecraft.session.mppass); + } else if(var1.id == 1) { + GL11.enableRepeatEvents(false); + minecraft.setCurrentScreen(new MainMenu()); + } + } + + protected void onMouseClick(int var1, int var2, int var3) { + if(var3 == 0) { + if(var1 >= this.width / 2 - 100 && var1 < (this.width / 2 - 100) + 200 && var2 >= this.height / 4 - 10 + 50 + 18 && var2 < (this.height / 4 - 10 + 50 + 18) + 20) { + GL11.enableRepeatEvents(true); + textBox1Active = true; + textBox2Active = false; + } else if(var1 >= this.width / 2 - 100 && var1 < (this.width / 2 - 100) + 200 && var2 >= this.height / 4 - 10 + 50 - 20 && var2 < (this.height / 4 - 10 + 50 - 20) + 20) { + GL11.enableRepeatEvents(true); + textBox2Active = true; + textBox1Active = false; + } else { + GL11.enableRepeatEvents(false); + textBox1Active = false; + textBox2Active = false; + } + } + super.onMouseClick(var1, var2, var3); + } + + protected final void onKeyPress(char var1, int var2) { + if(textBox1Active) { + if(var2 == 14 && this.server.length() > 0) { + this.server = this.server.substring(0, this.server.length() - 1); + } + if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.:-_\'*!\\\"#%/()=+?[]{}<>@|$;".indexOf(var1) >= 0 && this.server.length() < 32) { + this.server = this.server + var1; + } + if(server.length() > 0 && username.length() > 0) { + connect.active = true; + } else { + connect.active = false; + } + } else if(textBox2Active) { + if(var2 == 14 && this.username.length() > 0) { + this.username = this.username.substring(0, this.username.length() - 1); + } + if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.:-_\'*!\\\"#%/()=+?[]{}<>@|$;".indexOf(var1) >= 0 && this.username.length() < 32) { + this.username = this.username + var1; + } + if(server.length() > 0 && username.length() > 0) { + connect.active = true; + } else { + connect.active = false; + } + } + } + + public final void render(int var1, int var2) { + int var4 = this.minecraft.width * 240 / this.minecraft.height; + int var5 = this.minecraft.height * 240 / this.minecraft.height; + GL11.glClear(16640); + Tessellator tessellator = Tessellator.instance; + int var7 = new TextureLocation("/dirt.png").bindTexture(); + float var10 = 32.0F; + tessellator.startDrawing(7); + tessellator.setColorOpaque_I(4210752); + tessellator.addVertexWithUV(0.0F, (float)var5, 0.0F, 0.0F, (float)var5 / var10); + tessellator.addVertexWithUV((float)var4, (float)var5, 0.0F, (float)var4 / var10, (float)var5 / var10); + tessellator.addVertexWithUV((float)var4, 0.0F, 0.0F, (float)var4 / var10, 0.0F); + tessellator.addVertexWithUV(0.0F, 0.0F, 0.0F, 0.0F, 0.0F); + tessellator.draw(); + + //username + drawBox((this.width / 2 - 100) - 1, (this.height / 4 - 10 + 50 - 20) - 1, (this.width / 2 - 100) + 200 + 1, (this.height / 4 - 10 + 50 - 20) + 20 + 1, -6250336); + drawBox(this.width / 2 - 100, this.height / 4 - 10 + 50 - 20, (this.width / 2 - 100) + 200, (this.height / 4 - 10 + 50 - 20) + 20, -16777216); + + this.drawString(this.fontRenderer, "Username:", this.width / 2 - 100, this.height / 4 - 10 + 50 - 30, 10526880); + + //server IP + drawBox((this.width / 2 - 100) - 1, (this.height / 4 - 10 + 50 + 18) - 1, (this.width / 2 - 100) + 200 + 1, (this.height / 4 - 10 + 50 + 18) + 20 + 1, -6250336); + drawBox(this.width / 2 - 100, this.height / 4 - 10 + 50 + 18, (this.width / 2 - 100) + 200, (this.height / 4 - 10 + 50 + 18) + 20, -16777216); + + this.drawString(this.fontRenderer, "Server address:", this.width / 2 - 100, this.height / 4 - 10 + 50 + 8, 10526880); + if(textBox1Active) { + boolean e = this.counter / 6 % 2 == 0; + this.drawString(this.fontRenderer, server + (e ? "_" : ""), (this.width / 2 - 100) + 4, (this.height / 4 - 10 + 50 + 18) + (20 - 8) / 2, 14737632); + } else { + this.drawString(this.fontRenderer, server, (this.width / 2 - 100) + 4, (this.height / 4 - 10 + 50 + 18) + (20 - 8) / 2, 14737632); + } + if(textBox2Active) { + boolean e = this.counter / 6 % 2 == 0; + this.drawString(this.fontRenderer, username + (e ? "_" : ""), (this.width / 2 - 100) + 4, (this.height / 4 - 10 + 50 - 20) + (20 - 8) / 2, 14737632); + } else { + this.drawString(this.fontRenderer, username, (this.width / 2 - 100) + 4, (this.height / 4 - 10 + 50 - 20) + (20 - 8) / 2, 14737632); + } + super.render(var1, var2); + } + +} diff --git a/src/teavm/java/com/mojang/minecraft/level/LevelIO.java b/src/teavm/java/com/mojang/minecraft/level/LevelIO.java deleted file mode 100644 index ba10a5e..0000000 --- a/src/teavm/java/com/mojang/minecraft/level/LevelIO.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.mojang.minecraft.level; - -import com.mojang.minecraft.ProgressBarDisplay; -import com.mojang.minecraft.level.Level; -import com.mojang.minecraft.level.LevelObjectInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -public final class LevelIO { - - private ProgressBarDisplay progressBar; - - - public LevelIO(ProgressBarDisplay var1) { - this.progressBar = var1; - } - - public final boolean save(Level var1, File var2) { - try { - FileOutputStream var5 = new FileOutputStream(var2); - save(var1, (OutputStream)var5); - var5.close(); - return true; - } catch (Exception var4) { - var4.printStackTrace(); - if(this.progressBar != null) { - this.progressBar.setText("Failed!"); - } - - try { - Thread.sleep(1000L); - } catch (InterruptedException var3) { - ; - } - - return false; - } - } - - public final Level load(File var1) { - try { - FileInputStream var5 = new FileInputStream(var1); - Level var2 = this.load((InputStream)var5); - var5.close(); - return var2; - } catch (Exception var4) { - var4.printStackTrace(); - if(this.progressBar != null) { - this.progressBar.setText("Failed!"); - } - - try { - Thread.sleep(1000L); - } catch (InterruptedException var3) { - ; - } - - return null; - } - } - - public final boolean saveOnline(Level var1, String var2, String var3, String var4, String var5, int var6) { - if(var4 == null) { - var4 = ""; - } - - if(this.progressBar != null && this.progressBar != null) { - this.progressBar.setTitle("Saving level"); - } - - try { - if(this.progressBar != null && this.progressBar != null) { - this.progressBar.setText("Compressing.."); - } - - ByteArrayOutputStream var7 = new ByteArrayOutputStream(); - save(var1, (OutputStream)var7); - var7.close(); - byte[] var10 = var7.toByteArray(); - if(this.progressBar != null && this.progressBar != null) { - this.progressBar.setText("Connecting.."); - } - - HttpURLConnection var12; - (var12 = (HttpURLConnection)(new URL("http://" + var2 + "/level/save.html")).openConnection()).setDoInput(true); - var12.setDoOutput(true); - var12.setRequestMethod("POST"); - DataOutputStream var13; - (var13 = new DataOutputStream(var12.getOutputStream())).writeUTF(var3); - var13.writeUTF(var4); - var13.writeUTF(var5); - var13.writeByte(var6); - var13.writeInt(var10.length); - if(this.progressBar != null) { - this.progressBar.setText("Saving.."); - } - - var13.write(var10); - var13.close(); - BufferedReader var11; - if(!(var11 = new BufferedReader(new InputStreamReader(var12.getInputStream()))).readLine().equalsIgnoreCase("ok")) { - if(this.progressBar != null) { - this.progressBar.setText("Failed: " + var11.readLine()); - } - - var11.close(); - Thread.sleep(1000L); - return false; - } else { - var11.close(); - return true; - } - } catch (Exception var9) { - var9.printStackTrace(); - if(this.progressBar != null) { - this.progressBar.setText("Failed!"); - } - - try { - Thread.sleep(1000L); - } catch (InterruptedException var8) { - ; - } - - return false; - } - } - - public final Level loadOnline(String var1, String var2, int var3) { - if(this.progressBar != null) { - this.progressBar.setTitle("Loading level"); - } - - try { - if(this.progressBar != null) { - this.progressBar.setText("Connecting.."); - } - - HttpURLConnection var6; - (var6 = (HttpURLConnection)(new URL("http://" + var1 + "/level/load.html?id=" + var3 + "&user=" + var2)).openConnection()).setDoInput(true); - if(this.progressBar != null) { - this.progressBar.setText("Loading.."); - } - - DataInputStream var7; - if((var7 = new DataInputStream(var6.getInputStream())).readUTF().equalsIgnoreCase("ok")) { - return this.load((InputStream)var7); - } else { - if(this.progressBar != null) { - this.progressBar.setText("Failed: " + var7.readUTF()); - } - - var7.close(); - Thread.sleep(1000L); - return null; - } - } catch (Exception var5) { - var5.printStackTrace(); - if(this.progressBar != null) { - this.progressBar.setText("Failed!"); - } - - try { - Thread.sleep(3000L); - } catch (InterruptedException var4) { - ; - } - - return null; - } - } - - public final Level load(InputStream var1) { - if(this.progressBar != null) { - this.progressBar.setTitle("Loading level"); - } - - if(this.progressBar != null) { - this.progressBar.setText("Reading.."); - } - - try { - DataInputStream var10; - if((var10 = new DataInputStream(new GZIPInputStream(var1))).readInt() != 656127880) { - return null; - } else { - byte var12; - if((var12 = var10.readByte()) > 2) { - return null; - } else if(var12 <= 1) { - String var14 = var10.readUTF(); - String var15 = var10.readUTF(); - long var3 = var10.readLong(); - short var5 = var10.readShort(); - short var6 = var10.readShort(); - short var7 = var10.readShort(); - byte[] var8 = new byte[var5 * var6 * var7]; - var10.readFully(var8); - var10.close(); - Level var11; - (var11 = new Level()).setData(var5, var7, var6, var8); - var11.name = var14; - var11.creator = var15; - var11.createTime = var3; - return var11; - } else { - Level var2; - LevelObjectInputStream var13; - (var2 = (Level)(var13 = new LevelObjectInputStream(var10)).readObject()).initTransient(); - var13.close(); - return var2; - } - } - } catch (Exception var9) { - var9.printStackTrace(); - System.out.println("Failed to load level: " + var9.toString()); - return null; - } - } - - public static void save(Level var0, OutputStream var1) { - try { - DataOutputStream var3; - (var3 = new DataOutputStream(new GZIPOutputStream(var1))).writeInt(656127880); - var3.writeByte(2); - ObjectOutputStream var4; - (var4 = new ObjectOutputStream(var3)).writeObject(var0); - var4.close(); - } catch (Exception var2) { - var2.printStackTrace(); - } - } - - public static byte[] decompress(InputStream var0) { - try { - DataInputStream var3; - byte[] var1 = new byte[(var3 = new DataInputStream(new GZIPInputStream(var0))).readInt()]; - var3.readFully(var1); - var3.close(); - return var1; - } catch (Exception var2) { - throw new RuntimeException(var2); - } - } -} diff --git a/src/teavm/java/com/mojang/minecraft/net/NetworkManager.java b/src/teavm/java/com/mojang/minecraft/net/NetworkManager.java index 6da16b3..1f68568 100644 --- a/src/teavm/java/com/mojang/minecraft/net/NetworkManager.java +++ b/src/teavm/java/com/mojang/minecraft/net/NetworkManager.java @@ -21,7 +21,7 @@ public class NetworkManager players = new HashMap(); - new ServerConnectThread(this, server, username, key, minecraft).start(); + new ServerConnect(this, server, username, key, minecraft).connect(); } public ByteArrayOutputStream levelData; @@ -53,7 +53,7 @@ public class NetworkManager public boolean isConnected() { - return netHandler != null && GL11.connectionOpen(); + return netHandler != null && netHandler.channel.connectionOpen(); } public List getPlayers() diff --git a/src/teavm/java/com/mojang/minecraft/net/ServerConnectThread.java b/src/teavm/java/com/mojang/minecraft/net/ServerConnect.java similarity index 83% rename from src/teavm/java/com/mojang/minecraft/net/ServerConnectThread.java rename to src/teavm/java/com/mojang/minecraft/net/ServerConnect.java index 3b43b94..e89ad29 100644 --- a/src/teavm/java/com/mojang/minecraft/net/ServerConnectThread.java +++ b/src/teavm/java/com/mojang/minecraft/net/ServerConnect.java @@ -4,9 +4,9 @@ import com.mojang.minecraft.Minecraft; import com.mojang.minecraft.gui.ErrorScreen; import com.mojang.net.NetworkHandler; -public class ServerConnectThread extends Thread +public class ServerConnect { - public ServerConnectThread(NetworkManager networkManager, String server, String username, String key, Minecraft minecraft) { + public ServerConnect(NetworkManager networkManager, String server, String username, String key, Minecraft minecraft) { super(); netManager = networkManager; @@ -19,8 +19,7 @@ public class ServerConnectThread extends Thread this.minecraft = minecraft; } - @Override - public void run() + public void connect() { try { netManager.netHandler = new NetworkHandler(server); diff --git a/src/teavm/java/com/mojang/net/NetworkHandler.java b/src/teavm/java/com/mojang/net/NetworkHandler.java index 96cf8ed..17fc59b 100644 --- a/src/teavm/java/com/mojang/net/NetworkHandler.java +++ b/src/teavm/java/com/mojang/net/NetworkHandler.java @@ -6,6 +6,8 @@ import com.mojang.minecraft.gui.ErrorScreen; import com.mojang.minecraft.net.NetworkManager; import com.mojang.minecraft.net.PacketType; +import net.PeytonPlayz585.websocket.WebSocketChannel; + import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -20,6 +22,7 @@ public final class NetworkHandler { public NetworkManager netManager; private boolean unused = false; private byte[] stringBytes = new byte[64]; + public WebSocketChannel channel; public NetworkHandler(String var1) { @@ -43,18 +46,14 @@ public final class NetworkHandler { Minecraft.getMinecraft().setCurrentScreen(new ErrorScreen(":(", "Invalid URI protocol!")); } - if(!GL11.startConnection(address)) { - if(!GL11.startConnection(address)) { - Minecraft.getMinecraft().setCurrentScreen(new ErrorScreen(address, "Failed to connect to server!")); - } - } + channel = new WebSocketChannel(address); } public final void close() { try { if(this.out.position() > 0) { this.out.flip(); - this.write(this.out); + this.channel.write(this.out); this.out.compact(); } } catch (Exception var2) { @@ -62,14 +61,14 @@ public final class NetworkHandler { } try { - GL11.endConnection(); + channel.endConnection(); } catch (Exception var1) { ; } } public final void send(PacketType var1, Object ... var2) { - if(GL11.connectionOpen()) { + if(channel.connectionOpen()) { this.out.put(var1.opcode); for(int var3 = 0; var3 < var2.length; ++var3) { @@ -77,7 +76,7 @@ public final class NetworkHandler { Object var4 = var2[var3]; Class var5 = var10001; NetworkHandler var6 = this; - if(GL11.connectionOpen()) { + if(channel.connectionOpen()) { try { if(var5 == Long.TYPE) { var6.out.putLong(((Long)var4).longValue()); @@ -129,7 +128,7 @@ public final class NetworkHandler { } public Object readObject(Class var1) { - if(!GL11.connectionOpen()) { + if(!channel.connectionOpen()) { return null; } else { try { @@ -162,49 +161,6 @@ public final class NetworkHandler { } } - public void read(ByteBuffer buf) { - int bytesRead = 0; - while (bytesRead < buf.capacity()) { - if (!GL11.receivedBuffers.isEmpty()) { - ByteBuffer receivedBuffer = GL11.receivedBuffers.peek(); - int remainingBytes = buf.capacity() - bytesRead; - int bytesToRead = Math.min(receivedBuffer.remaining(), remainingBytes); - receivedBuffer.get(buf.array(), bytesRead, bytesToRead); - bytesRead += bytesToRead; - - if (receivedBuffer.remaining() == 0) { - GL11.receivedBuffers.poll(); - } - } else { - break; - } - } - } - - private static ByteBuffer writeBuffer; - - public void write(ByteBuffer buf) { - if (writeBuffer == null) { - writeBuffer = ByteBuffer.allocate(buf.capacity()); - } - - int bytesToWrite = Math.min(buf.remaining(), writeBuffer.remaining()); - writeBuffer.put(buf.array(), buf.position(), bytesToWrite); - buf.position(buf.position() + bytesToWrite); - - if (writeBuffer.remaining() == 0 || buf.remaining() == 0) { - writeBuffer.flip(); - byte[] data = new byte[writeBuffer.remaining()]; - writeBuffer.get(data); - GL11.writePacket(data); - writeBuffer.clear(); - } - - if (buf.remaining() > 0) { - write(buf); - } - } - @JSBody(params = { }, script = "return window.location.href;") private static native String getLocationString(); diff --git a/src/teavm/java/net/PeytonPlayz585/level/LevelUtils.java b/src/teavm/java/net/PeytonPlayz585/level/LevelUtils.java index e85d26d..49f94c7 100644 --- a/src/teavm/java/net/PeytonPlayz585/level/LevelUtils.java +++ b/src/teavm/java/net/PeytonPlayz585/level/LevelUtils.java @@ -109,7 +109,7 @@ public class LevelUtils { public void save() { - if(Minecraft.getMinecraft().networkManager != null) { + if(Minecraft.getMinecraft().server != null || Minecraft.getMinecraft().networkManager != null || Minecraft.getMinecraft().level == null) { return; } diff --git a/src/teavm/java/net/PeytonPlayz585/websocket/WebSocketChannel.java b/src/teavm/java/net/PeytonPlayz585/websocket/WebSocketChannel.java new file mode 100644 index 0000000..f39509e --- /dev/null +++ b/src/teavm/java/net/PeytonPlayz585/websocket/WebSocketChannel.java @@ -0,0 +1,102 @@ +package net.PeytonPlayz585.websocket; + +import org.teavm.jso.JSBody; +import org.teavm.jso.ajax.*; +import org.teavm.jso.dom.events.MessageEvent; +import org.teavm.jso.typedarrays.ArrayBuffer; +import org.teavm.jso.typedarrays.DataView; +import org.teavm.jso.typedarrays.Int8Array; +import org.teavm.jso.websocket.WebSocket; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.Queue; + +public class WebSocketChannel { + private final WebSocket socket; + private final Queue messageQueue; + private final ByteBuffer readBuffer; + private boolean reading; + private boolean isConnected = false; + + public WebSocketChannel(String url) { + socket = WebSocket.create(url); + messageQueue = new LinkedList<>(); + readBuffer = ByteBuffer.allocate(4096); + reading = false; + + socket.onMessage(event -> { + isConnected = true; + messageQueue.offer(event); + }); + + socket.onOpen(event -> { + isConnected = true; + messageQueue.clear(); + }); + + socket.onClose((event) -> { + isConnected = false; + messageQueue.clear(); + }); + + socket.onError((event) -> { + isConnected = false; + socket.close(); + }); + } + + public void read(ByteBuffer buffer) { + if (reading || messageQueue.isEmpty()) { + return; + } + MessageEvent event = messageQueue.peek(); + readData(buffer, event); + if (!event.isBubbles() && !event.isCancelable()) { + messageQueue.poll(); + } + } + + private void readData(ByteBuffer buffer, MessageEvent event) { + DataView data = DataView.create(event.getDataAsArray()); + int length = Math.min(buffer.remaining(), data.getByteLength()); + for (int i = 0; i < length; i++) { + buffer.put((byte) data.getInt8(i)); + } + if (reading) { + return; + } + if (buffer.hasRemaining()) { + readBuffer.clear(); + readBuffer.put(buffer); + reading = true; + } else { + buffer.flip(); + } + } + + @JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);") + private static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer); + + public void write(ByteBuffer buffer) { + if (socket.getReadyState() == 3) { + return; + } + byte[] data = new byte[buffer.remaining()]; + buffer.get(data); + Int8Array array = Int8Array.create(data.length); + for (int i = 0; i < data.length; i++) { + array.set(i, data[i]); + } + nativeBinarySend(socket, array.getBuffer()); + } + + public boolean connectionOpen() { + return isConnected && socket.getReadyState() != 3; + } + + public void endConnection() { + socket.close(); + } +} diff --git a/src/teavm/java/net/lax1dude/eaglercraft/Client.java b/src/teavm/java/net/lax1dude/eaglercraft/Client.java index 1aecd66..b1b0578 100644 --- a/src/teavm/java/net/lax1dude/eaglercraft/Client.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/Client.java @@ -21,8 +21,6 @@ import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2; public class Client { private static final String crashImage = "data:image/png;base64,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c+Jxky5I/Mh1xeM3zkWXBZ4pmpnUPLFILBU7WOlgVjI14mniiKrplC9kPVY5b3HWKjXWuid/YSivr6S5TmsEcSwhgSQkKKihjApsRGnXSbGQovOYj3/Y9SfJpZCrDEaOBVShQXb94H/we7ZWYWrSSwrFgO4Xx/kYBXp2gWbdcb6PHad5AgSfgSu97a82gNlP0uttLXIEDGwDF9dtTdkDLneA8JMhm7IrBWkJhQLwfkbflAMGb4G+NW9urXOcPgAZmtXyDXBwCIwVKXvd5929nXP7t6c1vx8743KRRjbQVgAADfdpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6NDJlMTU3MGEtNmMyZS00Y2E1LWI3ZTMtOGI4ODI1MmMwZDMwIgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjU1NGY3N2UwLTc4NmEtNGFlZS1iYjhmLWNhYTBiZGNiYzE3MSIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmNmMWYyMjUxLWIwY2QtNDE1NS1hMjAyLTExNGI0ZGM2MmFhNSIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IldpbmRvd3MiCiAgIEdJTVA6VGltZVN0YW1wPSIxNjQzMDYxODUwNDk0OTc0IgogICBHSU1QOlZlcnNpb249IjIuMTAuMjQiCiAgIHRpZmY6T3JpZW50YXRpb249IjEiCiAgIHhtcDpDcmVhdG9yVG9vbD0iR0lNUCAyLjEwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ODUyMGQ4YTMtMWRhZC00ZjIwLWFjOTktODg4OTJkZDExNDQ0IgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKFdpbmRvd3MpIgogICAgICBzdEV2dDp3aGVuPSIyMDIxLTEyLTE3VDE3OjIyOjQ4Ii8+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjJkY2U5N2M4LTBkZjItNGQzNi1iMzE1LWE0YjdmMmUyMjJiNSIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMi0wMS0yNFQxNDowNDoxMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz61xwk6AAAABmJLR0QAnQCdAJ2roJyEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5gEYFgQKOBb3JwAAIABJREFUeNrtvXl0lFWePv7UvlelKvu+koSQRQiyBJGISEB0hFYZwW1sp4/2csaZ1jlz5sz80cc5c7rnaI8zju2o09qiIrKowEGURXYI+5IASQjZl0plT2rff3/073O/byVVlUQSRPs+5+QkkMpbb9333ud+lufzuaJgMBgEBwcHxw8UYj4EHBwcnMQ4ODg4OIlxcHBwcBLj4ODgJMbBwcHBSYyDg4ODkxgHBwcHJzEODg5OYhwcHBycxDg4ODg4iXFw/GWAqgHHfv+ufyv8+q7XvVMh4rWTHBwc3BLj4ODg4CTGwcHBwUmMg4ODkxgHBwcHJzEODg4OTmIcHBwcnMQ4ODg4iXFwcHBwEuPg4ODgJMbBwcHBSYyDg+NHBCkfAo6/ZAiLov1+P3w+H/x+P/x+P4LBIDQaDWQyGR+oSYyjSCSK+G9OYhwctwiHw4Guri44HA54vV74fD72FQgE4Pf74Xa74XA44Ha74Xa7EQgEsGrVKqSnp9+2BTlT5EJETT+PJZxgMAixWMx+FwgEIBb/2VGjn4W/o78P9/qxPSXo2pFez0mMg2MSC7mrqwt/+MMfYDabYbfb4XQ64XQ64XA42HeHw4HBwUFIJBJIJBLExMRg4cKFSEtL+0GSmJAwxsLn80EqlSIQCIRYomKxGD6fD2KxGH6/n31un88HiUQCv98fcm26Pr2H0LIlkhLeg/B3RIbCa30XS46TGMePHn6/HxaLBVu2bIFcLg9ZXLRQpFIpDAYDDAYDW0RyufwHRV7ChU9kQeQhtHyInLxeL7OwyFoS/o7caCI1+k7XlEgkjIiEJOXz+SASiSCVStl9SKX/j2pE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"; - public static Thread thread = null; - public static class AbortedLaunchException extends RuntimeException { // yee } @@ -60,13 +58,11 @@ public class Client { private static void run1() { instance.host = "0.0.0.0:25565"; - instance.session = new SessionData("PeytonPlayz585", "TeaVM-WebGL"); instance.levelLoaded = true; GL11.canvas.focus(); GL11.canvasBack.focus(); instance.waiting = false; - thread = new Thread(instance); - thread.run(); + instance.run(); } @JSBody(params = { }, script = "return window.classicConfig;") diff --git a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java index e2813e8..1460170 100644 --- a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java @@ -1201,61 +1201,6 @@ public class EaglerAdapterImpl2 { @JSBody(params = { "name", "cvs" }, script = "var a=document.createElement(\"a\");a.href=cvs.toDataURL(\"image/png\");a.download=name;a.click();") private static native void saveScreenshot(String name, HTMLCanvasElement cvs); - private static WebSocket webSocket; - private static boolean isConnected = false; - public static java.util.Queue receivedBuffers = new java.util.ArrayDeque(); - - public static boolean startConnection(String serverUrl) { - webSocket = WebSocket.create(serverUrl); - - webSocket.onOpen(new EventListener() { - @Override - public void handleEvent(MessageEvent evt) { - isConnected = true; - } - }); - - webSocket.onMessage(new EventListener() { - @Override - public void handleEvent(MessageEvent evt) { - Uint8Array a = Uint8Array.create(evt.getDataAsArray()); - byte[] b = new byte[a.getByteLength()]; - for(int i = 0; i < b.length; ++i) { - b[i] = (byte) (a.get(i) & 0xFF); - } - ByteBuffer buffer = ByteBuffer.wrap(b); - receivedBuffers.add(buffer); - } - }); - - webSocket.onClose(new EventListener() { - @Override - public void handleEvent(CloseEvent event) { - isConnected = false; - } - }); - - return isConnected; - } - - public static void endConnection() { - webSocket.close(); - } - - public static final boolean connectionOpen() { - return isConnected; - } - - @JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);") - private static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer); - public static final void writePacket(byte[] packet) { - if(webSocket != null && isConnected) { - Uint8Array arr = Uint8Array.create(packet.length); - arr.set(packet); - nativeBinarySend(webSocket, arr.getBuffer()); - } - } - public static final byte[] loadLocalStorage(String key) { String s = win.getLocalStorage().getItem("_eaglercraft_beta."+key); if(s != null) {