summaryrefslogtreecommitdiff
path: root/serverlist-server/src/main/com
diff options
context:
space:
mode:
authorPugmatt <pugmatt@gmail.com>2019-06-18 23:22:41 -0400
committerPugmatt <pugmatt@gmail.com>2019-06-18 23:22:41 -0400
commita98d6164e8f03c19ed568fbe05b69b2a1d4eccf2 (patch)
treef7fb1e3057cc942e5ba78be233339e15c6dea788 /serverlist-server/src/main/com
parent9be6579e87cc4db8dab08f007482317f5bd980a3 (diff)
downloadBedrockConnect-a98d6164e8f03c19ed568fbe05b69b2a1d4eccf2.tar.gz
BedrockConnect-a98d6164e8f03c19ed568fbe05b69b2a1d4eccf2.tar.bz2
BedrockConnect-a98d6164e8f03c19ed568fbe05b69b2a1d4eccf2.zip
Added serverlist bedrock server
Diffstat (limited to 'serverlist-server/src/main/com')
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/AuthData.java30
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java16
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Chunk.java107
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/PipePlayer.java206
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Server.java88
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ChunkData.java80
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ExtraData.java40
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/Section.java35
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIComponents.java83
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIForms.java50
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/ClientPacketHandler.java828
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/PacketHandler.java1016
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/Binary.java322
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/BinaryStream.java528
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/FixedPlayerListPacket.java7
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/PaletteManager.java69
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/VarInt.java235
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitMath.java67
-rw-r--r--serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitRandom.java79
19 files changed, 3886 insertions, 0 deletions
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/AuthData.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/AuthData.java
new file mode 100644
index 0000000..46955e8
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/AuthData.java
@@ -0,0 +1,30 @@
+package main.com.pyratron.pugmatt.bedrockconnect;
+
+import java.util.UUID;
+
+public class AuthData {
+ private final String displayName;
+ private final UUID identity;
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public UUID getIdentity() {
+ return identity;
+ }
+
+ public String getXuid() {
+ return xuid;
+ }
+
+ private final String xuid;
+
+ public AuthData(String displayName, UUID identity, String xuid) {
+ this.displayName = displayName;
+ this.identity = identity;
+ this.xuid = xuid;
+ }
+
+
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java
new file mode 100644
index 0000000..bda3b38
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java
@@ -0,0 +1,16 @@
+package main.com.pyratron.pugmatt.bedrockconnect;
+
+import main.com.pyratron.pugmatt.bedrockconnect.utils.PaletteManager;
+
+public class BedrockConnect {
+
+
+ public static PaletteManager paletteManager;
+
+ public static void main(String[] args) {
+ paletteManager = new PaletteManager();
+
+ Server server = new Server();
+ }
+
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Chunk.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Chunk.java
new file mode 100644
index 0000000..3f9ec0f
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Chunk.java
@@ -0,0 +1,107 @@
+package main.com.pyratron.pugmatt.bedrockconnect;
+
+// References to this: https://github.com/NukkitX/Nukkit/blob/4ce13f2afb9a1a330df63a482bee9995ce1f96d5/src/main/java/cn/nukkit/level/format/anvil/ChunkRequestTask.java
+// https://github.com/Nukkit/Nukkit/blob/master/src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java
+// https://github.com/Nukkit/Nukkit/blob/master/src/main/java/cn/nukkit/level/format/leveldb/Chunk.java
+// https://github.com/NukkitX/Nukkit/blob/4ce13f2afb9a1a330df63a482bee9995ce1f96d5/src/main/java/cn/nukkit/level/format/mcregion/McRegion.java
+
+import java.nio.ByteBuffer;
+
+public class Chunk{
+
+ byte[] ids;
+ byte[] meta;
+ byte[] heightMap;
+ byte[] skyLight;
+ byte[] blockLight;
+ byte[] biomes;
+ byte[] blockEntities;
+
+ public Chunk(int x, int z) {
+ ids = getBlockIdArray();
+ meta = getBlockDataArray();
+ heightMap = getHeightMapArray(x, z);
+ skyLight = getBlockSkyLightArray();
+ blockLight = getBlockLightArray();
+ biomes = getBiomeIdArray();
+ blockEntities = getBlockEntitiesArray();
+ }
+
+ public byte[] encode() {
+ return ByteBuffer.allocate(
+ 16 * 16 * 128
+ + 16 * 16 * 64
+ + heightMap.length
+ + biomes.length
+ + this.blockEntities.length)
+ .put(ids)
+ .put(meta)
+ .put(heightMap)
+ .put(biomes)
+ .put(blockEntities)
+ .array();
+ }
+
+ public byte[] getBlockIdArray() {
+ byte[] blocks = new byte[16*128*16];
+ for (int i = 0; i < 16*128*16; i++) {
+ int d = 1;
+ blocks[i] = (byte) d;
+ }
+ return blocks;
+ }
+
+ public byte[] getBlockDataArray() {
+ byte[] blocks = new byte[16384];
+ for (int i = 0; i < 16384; i++) {
+ int d = 0;
+ blocks[i] = (byte) d;
+ }
+ return blocks;
+ }
+
+ public byte[] getBlockSkyLightArray() {
+ byte[] lights = new byte[16384];
+ for (int i = 0; i < 16384; i++) {
+ int d = 0;
+ lights[i] = (byte) d;
+ }
+ return lights;
+ }
+
+ public byte[] getBlockLightArray() {
+ byte[] lights = new byte[16384];
+ for (int i = 0; i < 16384; i++) {
+ int d = 0;
+ lights[i] = (byte) d;
+ }
+ return lights;
+ }
+
+ public byte[] getHeightMapArray(int x, int z) {
+ byte[] heights = new byte[256];
+ for (int i = 0; i < 256; i++) {
+ int d = 1;
+ heights[i] = (byte) ((z << 4) | x & 0xFF);
+ }
+ return heights;
+ }
+
+ public byte[] getBiomeIdArray() {
+ byte[] ids = new byte[1024];
+ for (int i = 0; i < 1024; i++) {
+ int d = i;
+ ids[i] = (byte) (d >> 24);
+ }
+ return ids;
+ }
+
+ public byte[] getBlockEntitiesArray() {
+ byte[] ids = new byte[32];
+ for (int i = 0; i < 32; i++) {
+ int d = i;
+ ids[i] = (byte) d;
+ }
+ return ids;
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/PipePlayer.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/PipePlayer.java
new file mode 100644
index 0000000..110a53d
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/PipePlayer.java
@@ -0,0 +1,206 @@
+package main.com.pyratron.pugmatt.bedrockconnect;
+
+import com.flowpowered.math.vector.Vector2f;
+import com.flowpowered.math.vector.Vector3f;
+import com.flowpowered.math.vector.Vector3i;
+import com.nukkitx.protocol.bedrock.BedrockServerSession;
+import com.nukkitx.protocol.bedrock.data.Attribute;
+import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
+import com.nukkitx.protocol.bedrock.data.GameRule;
+import com.nukkitx.protocol.bedrock.packet.*;
+import main.com.pyratron.pugmatt.bedrockconnect.chunk.ChunkData;
+
+import java.util.ArrayList;
+
+public class PipePlayer {
+
+ private BedrockServerSession session;
+
+ public PipePlayer(AuthData data, BedrockServerSession session) {
+ this.session = session;
+ }
+
+ public BedrockServerSession getSession() {
+ return session;
+ }
+
+ public void joinGame() {
+
+ /**
+ StartGamePacket pkStartGame = new StartGamePacket();
+ pkStartGame.setUniqueEntityId(packet.getEntityId());
+ pkStartGame.setRuntimeEntityId(packet.getEntityId());
+ pkStartGame.setDimensionId(0);
+ pkStartGame.setSeed(0);
+ pkStartGame.setGeneratorId(1);
+ pkStartGame.setDifficulty(0);
+ pkStartGame.setDefaultSpawn(new Vector3i(0, 72, 0));
+ pkStartGame.setPlayerPosition(new Vector3f(0f, 72f + 5, 0f));
+ pkStartGame.setLevelId("");
+ pkStartGame.setWorldName("World");
+ pkStartGame.setDefaultPlayerPermission(2);
+ pkStartGame.setCommandsEnabled(true);
+ pkStartGame.setPremiumWorldTemplateId(""); **/
+
+ MovePlayerPacket mp = new MovePlayerPacket();
+ mp.setRuntimeEntityId(-1);
+ mp.setOnGround(false);
+ mp.setMode(MovePlayerPacket.Mode.NORMAL);
+ mp.setRotation(new Vector3f(0,0,0));
+ mp.setPosition(new Vector3f(0,0,0));
+ session.sendPacketImmediately(mp);
+
+ StartGamePacket startGamePacket = new StartGamePacket();
+ startGamePacket.setUniqueEntityId(0);
+ startGamePacket.setRuntimeEntityId(0);
+ startGamePacket.setPlayerGamemode(0);
+ startGamePacket.setPlayerPosition(new Vector3f(-249, 67, -275));
+ startGamePacket.setRotation(new Vector2f(1, 1));
+
+ startGamePacket.setSeed(1111);
+ startGamePacket.setDimensionId(0);
+ startGamePacket.setGeneratorId(0);
+ startGamePacket.setLevelGamemode(0);
+ startGamePacket.setDifficulty(0);
+ startGamePacket.setDefaultSpawn(new Vector3i(-249, 67, -275));
+ startGamePacket.setAcheivementsDisabled(true);
+ startGamePacket.setTime(1300);
+ startGamePacket.setEduLevel(false);
+ startGamePacket.setEduFeaturesEnabled(false);
+ startGamePacket.setRainLevel(0);
+ startGamePacket.setLightningLevel(0);
+ startGamePacket.setPlatformLockedContentConfirmed(false);
+ startGamePacket.setMultiplayerGame(false);
+ startGamePacket.setBroadcastingToLan(false);
+ startGamePacket.getGamerules().add((new GameRule("showcoordinates", true)));
+ startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
+ startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
+ startGamePacket.setCommandsEnabled(true);
+ startGamePacket.setTexturePacksRequired(false);
+ startGamePacket.setBonusChestEnabled(false);
+ startGamePacket.setStartingWithMap(false);
+ startGamePacket.setTrustingPlayers(true);
+ startGamePacket.setDefaultPlayerPermission(1);
+ startGamePacket.setServerChunkTickRange(4);
+ startGamePacket.setBehaviorPackLocked(false);
+ startGamePacket.setResourcePackLocked(false);
+ startGamePacket.setFromLockedWorldTemplate(false);
+ startGamePacket.setUsingMsaGamertagsOnly(false);
+ startGamePacket.setFromWorldTemplate(false);
+ startGamePacket.setWorldTemplateOptionLocked(false);
+
+ startGamePacket.setLevelId("oerjhii");
+ startGamePacket.setWorldName("world");
+ startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000");
+ startGamePacket.setCurrentTick(1);
+ startGamePacket.setEnchantmentSeed(1);
+ startGamePacket.setMultiplayerCorrelationId("");
+
+ startGamePacket.setCachedPalette(BedrockConnect.paletteManager.getCachedPalette());
+
+ session.sendPacketImmediately(startGamePacket);
+
+ spawn();
+
+
+ }
+
+ public void sendAttributes() {
+ UpdateAttributesPacket pk = new UpdateAttributesPacket();
+ pk.setRuntimeEntityId(0);
+ pk.setAttributes(new ArrayList<Attribute>() {
+ {
+ add(new Attribute("minecraft:health", 0.00f, 20.00f, 20.00f, 20.00f));
+ add(new Attribute("minecraft:player.hunger", 0.00f, 20.00f, 20.00f, 20.00f));
+ add(new Attribute("minecraft:movement", 0.00f, 340282346638528859811704183484516925440.00f, 0.10f, 0.10f));
+ add(new Attribute("minecraft:player.level", 0.00f, 24791.00f, 0.00f, 0.00f));
+ add(new Attribute("minecraft:player.experience", 0.00f, 1.00f, 0.00f, 0.00f));
+ }
+ });
+ session.sendPacketImmediately(pk);
+
+ RespawnPacket rp = new RespawnPacket();
+ rp.setPosition(new Vector3f(0, 0 ,0));
+ session.sendPacketImmediately(rp);
+
+ spawn();
+ }
+
+ public void spawn() {
+
+ ChunkData data = new ChunkData(true);
+ data.encode();
+
+ Vector3f pos = new Vector3f(-249, 67, -275);
+ int chunkX = pos.getFloorX() >> 4;
+ int chunkZ = pos.getFloorX() >> 4;
+
+ for (int x = -3; x < 3; x++) {
+ for (int z = -3; z < 3; z++) {
+ FullChunkDataPacket data2 = new FullChunkDataPacket();
+ data2.setChunkX(chunkX + x);
+ data2.setChunkZ(chunkZ + z);
+ data2.setData(new byte[0]);
+ session.sendPacketImmediately(data2);
+ }
+ }
+
+ PlayStatusPacket playStatus = new PlayStatusPacket();
+ playStatus.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
+ session.sendPacketImmediately(playStatus);
+
+ /** SetSpawnPositionPacket pkSpawn = new SetSpawnPositionPacket();
+ pkSpawn.setSpawnType(SetSpawnPositionPacket.Type.PLAYER_SPAWN);
+ pkSpawn.setSpawnForced(false);
+ pkSpawn.setBlockPosition(new Vector3i(-249, 67, -275));
+ session.sendPacketImmediately(pkSpawn);
+
+ MovePlayerPacket mp = new MovePlayerPacket();
+ mp.setRuntimeEntityId(-1);
+ mp.setOnGround(false);
+ mp.setMode(MovePlayerPacket.Mode.NORMAL);
+ mp.setRotation(new Vector3f(0,0,0));
+ mp.setPosition(new Vector3f(0,0,0));
+ session.sendPacketImmediately(mp);
+
+ SetTimePacket st = new SetTimePacket();
+ st.setTime(0);
+ session.sendPacketImmediately(st);
+
+ AdventureSettingsPacket as = new AdventureSettingsPacket();
+ as.setCommandPermission(0);
+ as.setCustomFlags(0);
+ as.setPlayerFlags(0);
+ as.setPlayerPermission(0);
+ as.setUniqueEntityId(0);
+ as.setWorldFlags(0);
+ as.setWorldFlags(0);
+ session.sendPacketImmediately(as);
+
+ RespawnPacket rp = new RespawnPacket();
+ rp.setPosition(new Vector3f(0,0,0));
+ session.sendPacketImmediately(rp);
+
+
+ /** FullChunkDataPacket fullChunk = new FullChunkDataPacket();
+ fullChunk.setChunkX(0);
+ fullChunk.setChunkZ(0);
+ fullChunk.setData(data.getBuffer());
+ session.sendPacketImmediately(fullChunk);
+ fullChunk.setChunkX(0);
+ fullChunk.setChunkZ(-1);
+ session.sendPacketImmediately(fullChunk);
+ fullChunk.setChunkX(-1);
+ fullChunk.setChunkZ(0);
+ session.sendPacketImmediately(fullChunk);
+ fullChunk.setChunkX(-1);
+ fullChunk.setChunkZ(-1);
+ session.sendPacketImmediately(fullChunk); **/
+
+ //SetSpawnPositionPacket ss = new SetSpawnPositionPacket();
+ //ss.setSpawnType(SetSpawnPositionPacket.Type.PLAYER_SPAWN);
+ //session.sendPacketImmediately(ss);
+
+
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Server.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Server.java
new file mode 100644
index 0000000..f2570ae
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/Server.java
@@ -0,0 +1,88 @@
+package main.com.pyratron.pugmatt.bedrockconnect;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+import com.nukkitx.protocol.bedrock.*;
+import com.nukkitx.protocol.bedrock.v354.Bedrock_v354;
+import main.com.pyratron.pugmatt.bedrockconnect.listeners.PacketHandler;
+
+
+import javax.annotation.Nonnull;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Server {
+
+ public BedrockServer server;
+ public BedrockPong pong;
+
+ private BedrockPacketCodec codec;
+
+ public int getProtocol() {
+ return codec.getProtocolVersion();
+ }
+
+ public BedrockPacketCodec getCodec() {
+ return codec;
+ }
+
+ public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ public static final YAMLMapper YAML_MAPPER = (YAMLMapper) new YAMLMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+
+ private List<PipePlayer> players = new ArrayList<>();
+
+ public List<PipePlayer> getPlayers() {
+ return players;
+ }
+
+ public void addPlayer(PipePlayer player) {
+ this.players.add(player);
+ }
+
+ public PipePlayer addPlayer(AuthData data, BedrockServerSession session) {
+ PipePlayer player = new PipePlayer(data, session);
+ this.players.add(player);
+ return player;
+ }
+
+ public void removePlayer(PipePlayer player) {
+ this.players.remove(player);
+ }
+
+
+ public Server() {
+ Server current = this;
+ InetSocketAddress bindAddress = new InetSocketAddress("localhost", 19132);
+ codec = Bedrock_v354.V354_CODEC;
+ server = new BedrockServer(bindAddress);
+ pong = new BedrockPong();
+ pong.setEdition("MCPE");
+ pong.setMotd("BedrockConnect Connection Successful");
+ pong.setSubMotd("Test");
+ pong.setPlayerCount(0);
+ pong.setMaximumPlayerCount(20);
+ pong.setGameType("Survival");
+ pong.setProtocolVersion(Bedrock_v354.V354_CODEC.getProtocolVersion());
+ server.setHandler(new BedrockServerEventHandler() {
+ @Override
+ public boolean onConnectionRequest(InetSocketAddress address) {
+ return true; // Connection will be accepted
+ }
+ @Nonnull
+ public BedrockPong onQuery(InetSocketAddress address) {
+ return pong;
+ }
+ @Override
+ public void onSessionCreation(BedrockServerSession session) {
+ session.setPacketHandler(new PacketHandler(session, current));
+ }
+ });
+ // Start server up
+ server.bind().join();
+ System.out.println("Bedrock Connection Started: localhost:19132");
+
+ while(true) { }
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ChunkData.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ChunkData.java
new file mode 100644
index 0000000..a7460d3
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ChunkData.java
@@ -0,0 +1,80 @@
+package main.com.pyratron.pugmatt.bedrockconnect.chunk;
+
+import main.com.pyratron.pugmatt.bedrockconnect.utils.BinaryStream;
+
+import java.util.Arrays;
+
+// reference: https://github.com/DragonetMC/DragonProxy/blob/master/protocol/src/main/java/org/dragonet/protocol/type/chunk/ChunkData.java
+// Original Author: HoverEpic
+
+public class ChunkData extends BinaryStream {
+
+ /**
+ * 16x16x16 section of the chunk. The array's keys also indicate the
+ * section's height (the 3rd element of the array will be the 3rd section
+ * from bottom, starting at `y=24`). The amount of sections should be in a
+ * range from 0 (empty chunk) to 16.
+ */
+ public Section[] sections = new Section[0];
+ public short[] heights = new short[256];
+ /**
+ * Biomes in order `xz`.
+ */
+ public byte[] biomes = new byte[256];
+ /**
+ * Colums where there are world borders (in format `xz`). This feature
+ * hasn't been implemented in the game yet and crashes the client.
+ */
+ public byte[] borders = new byte[0];
+ public ExtraData[] extraData = new ExtraData[0];
+ /**
+ * Additional data for the chunk's block entities (tiles), encoded in the
+ * same way as BlockEntityData.nbt is. The position is given by the `Int`
+ * tags `x`, `y`, `z` which are added to the block's compound tag together
+ * with the `String` tag `id` that contains the name of the tile in pascal
+ * case. Wrong encoding or missing tags may result in the block becoming
+ * invisible.
+ */
+ public byte[] blockEntities = new byte[0];
+
+ public ChunkData(boolean empty) {
+ if(empty) {
+ sections = new Section[16];
+ for (int cy = 0; cy < 16; cy++) {
+ sections[cy] = new Section();
+ if (cy < 6)
+ Arrays.fill(sections[cy].blockIds, (byte) 1);
+ }
+ }
+ }
+
+ public ChunkData(Section[] sections, short[] heights, byte[] biomes, byte[] borders, ExtraData[] extraData,
+ byte[] blockEntities) {
+ this.sections = sections;
+ this.heights = heights;
+ this.biomes = biomes;
+ this.borders = borders;
+ this.extraData = extraData;
+ this.blockEntities = blockEntities;
+ }
+
+ public void encode() {
+ reset();
+ putByte((byte) (sections.length & 0xff));
+ for (Section s : sections) {
+ s.encode(this);
+ }
+ for (short h : heights) {
+ this.putLShort(h);
+ }
+ this.put(biomes);
+ this.putByte((byte) (borders.length & 0xFF));
+ this.put(borders);
+ this.putVarInt(extraData.length);
+ for (ExtraData extra : extraData) {
+ extra.encode(this);
+ }
+ this.put(blockEntities);
+ }
+
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ExtraData.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ExtraData.java
new file mode 100644
index 0000000..351b2ad
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/ExtraData.java
@@ -0,0 +1,40 @@
+package main.com.pyratron.pugmatt.bedrockconnect.chunk;
+
+// reference: https://github.com/DragonetMC/DragonProxy/blob/master/protocol/src/main/java/org/dragonet/protocol/type/chunk/ExtraData.java
+// Original Author: HoverEpic
+
+import main.com.pyratron.pugmatt.bedrockconnect.utils.BinaryStream;
+
+public class ExtraData {
+
+ private int key;
+ private short value;
+
+ public int getKey() {
+ return key;
+ }
+
+ public short getValue() {
+ return value;
+ }
+
+ public ExtraData() {
+
+ }
+
+ public ExtraData(int key, short value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public void encode(BinaryStream out) {
+ out.putVarInt(key);
+ out.putLShort(value);
+ }
+
+ public void decode(BinaryStream in) {
+ key = (int) in.getUnsignedVarInt();
+ value = (short) in.getLShort();
+ }
+
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/Section.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/Section.java
new file mode 100644
index 0000000..f771f06
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/chunk/Section.java
@@ -0,0 +1,35 @@
+package main.com.pyratron.pugmatt.bedrockconnect.chunk;
+
+// reference: https://github.com/DragonetMC/DragonProxy/blob/master/protocol/src/main/java/org/dragonet/protocol/type/chunk/Section.java
+// Original Author: HoverEpic
+
+import main.com.pyratron.pugmatt.bedrockconnect.utils.BinaryStream;
+
+public class Section {
+
+ public byte storageVers = 0;
+ public byte[] blockIds = new byte[4096];
+ public byte[] blockMetas = new byte[2048];
+
+ public Section(byte storageVers, byte[] blockIds, byte[] blockMetas) {
+ this.storageVers = storageVers;
+ this.blockIds = blockIds;
+ this.blockMetas = blockMetas;
+ }
+
+ public Section() {
+
+ }
+
+ public void encode(BinaryStream out) {
+ out.putByte(storageVers);
+ out.put(blockIds);
+ out.put(blockMetas);
+ }
+
+ public void decode(BinaryStream in) {
+ storageVers = (byte) (in.getByte() & 0xFF);
+ blockIds = in.get(4096);
+ blockMetas = in.get(2048);
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIComponents.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIComponents.java
new file mode 100644
index 0000000..85c656b
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIComponents.java
@@ -0,0 +1,83 @@
+package main.com.pyratron.pugmatt.bedrockconnect.gui;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket;
+import org.json.simple.JSONArray;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import java.util.ArrayList;
+
+public class UIComponents {
+
+ public static JsonObject createLabel(String text) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty("type", "label");
+ obj.addProperty("text", text);
+ return obj;
+ }
+
+ public static JsonObject createInput(String text, String placeholder) {
+ JsonObject input = new JsonObject();
+ input.addProperty("type", "input");
+ input.addProperty("placeholder", placeholder);
+ input.addProperty("text", text);
+ return input;
+ }
+
+ public static JsonObject createButton(String text, String image, String imageType) {
+ JsonObject button = new JsonObject();
+ button.addProperty("text", text);
+ if(image != null && imageType != null) {
+ JsonObject buttonImage = new JsonObject();
+ buttonImage.addProperty("type", imageType);
+ buttonImage.addProperty("data", image);
+ button.add("image", buttonImage);
+ }
+ return button;
+ }
+
+ public static JsonObject createButton(String text) {
+ JsonObject button = new JsonObject();
+ button.addProperty("text", text);
+ return button;
+ }
+
+ public static JsonObject createForm(String type, String title) {
+ JsonObject form = new JsonObject();
+ form.addProperty("type", type);
+ form.addProperty("title", title);
+ return form;
+ }
+
+ public static ModalFormRequestPacket createError(String error) {
+ ModalFormRequestPacket mf = new ModalFormRequestPacket();
+ mf.setFormId(UIForms.ERROR);
+ JsonObject form = new JsonObject();
+ form.addProperty("type", "custom_form");
+ form.addProperty("title", "Error");
+ JsonArray content = new JsonArray();
+ content.add(createLabel(error));
+ form.add("content", content);
+ mf.setFormData(form.toString());
+ return mf;
+ }
+
+ public static ArrayList<String> getFormData(String data) {
+ JSONParser parser = new JSONParser();
+ try {
+ JSONArray obj = (JSONArray) parser.parse(data);
+ ArrayList<String> strings = new ArrayList<>();
+ for(int i=0;i<obj.size();i++) {
+ System.out.println(obj.get(i).toString());
+ strings.add(obj.get(i).toString());
+ }
+ return strings;
+ } catch(ParseException e) {
+ System.out.println(e.toString());
+ }
+
+ return null;
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIForms.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIForms.java
new file mode 100644
index 0000000..90d93e7
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/gui/UIForms.java
@@ -0,0 +1,50 @@
+package main.com.pyratron.pugmatt.bedrockconnect.gui;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket;
+
+public class UIForms {
+ public static final int ERROR = 2, MAIN = 0, DIRECT_CONNECT = 1;
+
+ public static int currentForm = 0;
+
+ public static ModalFormRequestPacket createMain() {
+ currentForm = MAIN;
+ ModalFormRequestPacket mf = new ModalFormRequestPacket();
+ mf.setFormId(UIForms.MAIN);
+
+ JsonObject out = UIComponents.createForm("form", "ServerList");
+ out.addProperty("content", "");
+
+ JsonArray buttons = new JsonArray();
+
+ buttons.add(UIComponents.createButton("Direct Connect"));
+ buttons.add(UIComponents.createButton("Play.SkyBlockpe.com:19132", "https://i.imgur.com/3BmFZRE.png", "url"));
+ buttons.add(UIComponents.createButton("Add Server"));
+ buttons.add(UIComponents.createButton("Remove Server"));
+
+ out.add("buttons", buttons);
+
+ mf.setFormData(out.toString());
+
+ return mf;
+ }
+
+ public static ModalFormRequestPacket createDirectConnect() {
+ currentForm = DIRECT_CONNECT;
+ ModalFormRequestPacket mf = new ModalFormRequestPacket();
+ mf.setFormId(UIForms.DIRECT_CONNECT);
+ JsonObject out = UIComponents.createForm("custom_form", "Add Server");
+
+ JsonArray inputs = new JsonArray();
+
+ inputs.add(UIComponents.createInput("Server Address", "Please enter IP or Address"));
+ inputs.add(UIComponents.createInput("Server Port", "Please enter Port (E.g. 19132)"));
+
+ out.add("content", inputs);
+ mf.setFormData(out.toString());
+
+ return mf;
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/ClientPacketHandler.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/ClientPacketHandler.java
new file mode 100644
index 0000000..2595a33
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/ClientPacketHandler.java
@@ -0,0 +1,828 @@
+package main.com.pyratron.pugmatt.bedrockconnect.listeners;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.nukkitx.protocol.bedrock.BedrockClientSession;
+import com.nukkitx.protocol.bedrock.packet.*;
+
+import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler;
+import com.nukkitx.protocol.bedrock.packet.LoginPacket;
+import main.com.pyratron.pugmatt.bedrockconnect.AuthData;
+import main.com.pyratron.pugmatt.bedrockconnect.PipePlayer;
+import net.minidev.json.JSONObject;
+
+// Heavily referenced from https://github.com/NukkitX/ProxyPass/blob/master/src/main/java/com/nukkitx/proxypass/network/bedrock/session/UpstreamPacketHandler.java
+
+public class ClientPacketHandler implements BedrockPacketHandler {
+
+ private static final int PIXEL_SIZE = 4;
+
+ public static final int SINGLE_SKIN_SIZE = 64 * 32 * PIXEL_SIZE;
+ public static final int DOUBLE_SKIN_SIZE = 64 * 64 * PIXEL_SIZE;
+ public static final int SKIN_128_64_SIZE = 128 * 64 * PIXEL_SIZE;
+ public static final int SKIN_128_128_SIZE = 128 * 128 * PIXEL_SIZE;
+
+ private BedrockClientSession session;
+ private PipePlayer player;
+
+ private JSONObject skinData;
+ private JSONObject extraData;
+ private ArrayNode chainData;
+ private AuthData authData;
+
+ @Override
+ public boolean handle(AdventureSettingsPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AnimatePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockEntityDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockPickRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BookEditPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ClientToServerHandshakePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandBlockUpdatePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerClosePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CraftingEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityFallPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityPickRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InteractPacket packet) {
+ System.out.println(packet.toString());
+ session.sendPacketImmediately(packet);
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventoryContentPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventorySlotPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventoryTransactionPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ItemFrameDropItemPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LabTablePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LecternUpdatePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEvent3Packet packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MapInfoRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobArmorEquipmentPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobEquipmentPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ModalFormResponsePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MoveEntityAbsolutePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MovePlayerPacket packet) {
+ System.out.println(packet.toString());
+ session.sendPacketImmediately(packet);
+ return false;
+ }
+
+ @Override
+ public boolean handle(NetworkStackLatencyPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PhotoTransferPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerActionPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerHotbarPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerInputPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerSkinPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PurchaseReceiptPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RequestChunkRadiusPacket packet) {
+ System.out.println(packet.toString());
+ ChunkRadiusUpdatedPacket chunk = new ChunkRadiusUpdatedPacket();
+ chunk.setRadius(Math.max(3, Math.min(packet.getRadius(), 5)));
+ //PacketHeader ph = new PacketHeader();
+ // ph.set
+ //chunk.setHeader();
+ session.sendPacketImmediately(chunk);
+
+ int chunkPositionX = 0;
+ int chunkPositionZ = 0;
+ int chunkRadius = 5;
+ for (int x = -chunkRadius; x < chunkRadius; x++) {
+ for (int z = -chunkRadius; z < chunkRadius; z++) {
+ FullChunkDataPacket fullChunk = new FullChunkDataPacket();
+ fullChunk.setChunkX(chunkPositionX + x);
+ fullChunk.setChunkZ(chunkPositionZ + z);
+ fullChunk.setData(new byte[0]);
+ session.sendPacket(fullChunk);
+ }
+ }
+
+ PlayStatusPacket play = new PlayStatusPacket();
+ play.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
+ session.sendPacketImmediately(play);
+
+ SetTimePacket st = new SetTimePacket();
+ st.setTime(0);
+ session.sendPacketImmediately(st);
+ return false;
+ }
+
+ @Override
+ public boolean handle(RiderJumpPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerSettingsRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDefaultGameTypePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetPlayerGameTypePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SubClientLoginPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TextPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddBehaviorTreePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddEntityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddHangingEntityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddItemEntityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddPaintingPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddPlayerPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AvailableCommandsPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BossEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CameraPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ChangeDimensionPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ChunkRadiusUpdatedPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ClientboundMapItemDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandOutputPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerOpenPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerSetDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CraftingDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ExplodePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(FullChunkDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(GameRulesChangedPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(GuiDataPickItemPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(HurtArmorPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AutomationClientConnectPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MapCreateLockedCopyPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobEffectPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ModalFormRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MoveEntityDeltaPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(NpcRequestPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(OnScreenTextureAnimationPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerListPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlaySoundPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayStatusPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RemoveEntityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RemoveObjectivePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackChunkDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackDataInfoPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePacksInfoPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackStackPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RespawnPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ScriptCustomEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerSettingsResponsePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerToClientHandshakePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetCommandsEnabledPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDifficultyPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDisplayObjectivePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityDataPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityLinkPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityMotionPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetHealthPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetLastHurtByPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetScoreboardIdentityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetScorePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetSpawnPositionPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetTimePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetTitlePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowCreditsPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowProfilePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowStoreOfferPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SimpleEventPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SpawnExperienceOrbPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StartGamePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StopSoundPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StructureBlockUpdatePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TakeItemEntityPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TransferPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateAttributesPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateBlockPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateBlockSyncedPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateEquipPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateSoftEnumPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateTradePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AvailableEntityIdentifiersPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BiomeDefinitionListPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEvent2Packet packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(NetworkChunkPublisherUpdatePacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SpawnParticleEffectPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ @Override
+ public boolean handle(VideoStreamConnectPacket packet) {
+ System.out.println(packet.toString());
+ return false;
+ }
+
+ public ClientPacketHandler(BedrockClientSession session) {
+ this.session = session;
+
+ session.addDisconnectHandler((Reason) -> disconnect());
+ }
+
+ public void disconnect() {
+ //player.getClient().getSession().disconnect("Left Game");
+ //server.removePlayer(player);
+ }
+
+ @Override
+ public boolean handle(DisconnectPacket packet) {
+ System.out.println(packet.toString());
+ return true;
+ }
+
+ @Override
+ public boolean handle(ResourcePackChunkRequestPacket packet) {
+ System.out.println(packet.toString());
+ return true;
+ }
+
+ @Override
+ public boolean handle(ResourcePackClientResponsePacket packet) {
+ System.out.println(packet.toString());
+ return true;
+ }
+
+ @Override
+ public boolean handle(LoginPacket packet) {
+ System.out.println(packet.toString());
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/PacketHandler.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/PacketHandler.java
new file mode 100644
index 0000000..64b680e
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/listeners/PacketHandler.java
@@ -0,0 +1,1016 @@
+package main.com.pyratron.pugmatt.bedrockconnect.listeners;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.nukkitx.network.util.Preconditions;
+import com.nukkitx.protocol.bedrock.packet.*;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSObject;
+import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory;
+import com.nukkitx.protocol.bedrock.BedrockServerSession;
+import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler;
+import com.nukkitx.protocol.bedrock.packet.LoginPacket;
+import com.nukkitx.protocol.bedrock.util.EncryptionUtils;
+import main.com.pyratron.pugmatt.bedrockconnect.AuthData;
+import main.com.pyratron.pugmatt.bedrockconnect.PipePlayer;
+import main.com.pyratron.pugmatt.bedrockconnect.Server;
+import main.com.pyratron.pugmatt.bedrockconnect.gui.UIComponents;
+import main.com.pyratron.pugmatt.bedrockconnect.gui.UIForms;
+import net.minidev.json.JSONObject;
+
+import java.io.IOException;
+import java.security.interfaces.ECPublicKey;
+import java.util.ArrayList;
+import java.util.UUID;
+
+// Heavily referenced from https://github.com/NukkitX/ProxyPass/blob/master/src/main/java/com/nukkitx/proxypass/network/bedrock/session/UpstreamPacketHandler.java
+
+public class PacketHandler implements BedrockPacketHandler {
+
+ private static final int PIXEL_SIZE = 4;
+
+ public static final int SINGLE_SKIN_SIZE = 64 * 32 * PIXEL_SIZE;
+ public static final int DOUBLE_SKIN_SIZE = 64 * 64 * PIXEL_SIZE;
+ public static final int SKIN_128_64_SIZE = 128 * 64 * PIXEL_SIZE;
+ public static final int SKIN_128_128_SIZE = 128 * 128 * PIXEL_SIZE;
+
+ private Server server;
+ private BedrockServerSession session;
+ private PipePlayer player;
+
+ private JSONObject skinData;
+ private JSONObject extraData;
+ private ArrayNode chainData;
+ private AuthData authData;
+
+ @Override
+ public boolean handle(AdventureSettingsPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AnimatePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockEntityDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockPickRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BookEditPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ClientToServerHandshakePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandBlockUpdatePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerClosePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CraftingEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityFallPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EntityPickRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(EventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InteractPacket packet) {
+ System.out.println(packet.getClass().getName());
+ session.sendPacketImmediately(packet);
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventoryContentPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventorySlotPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(InventoryTransactionPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ItemFrameDropItemPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LabTablePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LecternUpdatePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEvent3Packet packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MapInfoRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobArmorEquipmentPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobEquipmentPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+
+ @Override
+ public boolean handle(ModalFormResponsePacket packet) {
+ System.out.println(packet.getClass().getName());
+ System.out.println("\"" + packet.getFormData().replaceAll("\\s+","") + "\"");
+
+ switch (packet.getFormId()) {
+ case 0:
+ if(UIForms.currentForm == UIForms.MAIN) {
+ if (packet.getFormData().replaceAll("\\s+","").contains("0")) {
+ session.sendPacketImmediately(UIForms.createDirectConnect());
+ } else if (packet.getFormData().contains("null")) {
+ session.disconnect("Exiting Server List");
+ }
+ }
+ break;
+ case 1:
+ try {
+ ArrayList<String> data = UIComponents.getFormData(packet.getFormData());
+ TransferPacket tp = new TransferPacket();
+ tp.setAddress(data.get(0).replace(" ", ""));
+ tp.setPort(Integer.parseInt(data.get(1)));
+ session.sendPacketImmediately(tp);
+ } catch(Exception e) {
+ session.sendPacketImmediately(UIComponents.createError("Please enter a port that contains only numbers."));
+ }
+ break;
+ case 2:
+ session.sendPacketImmediately(UIForms.createMain());
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean handle(MoveEntityAbsolutePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MovePlayerPacket packet) {
+ System.out.println(packet.getClass().getName());
+ session.sendPacketImmediately(packet);
+ return false;
+ }
+
+ @Override
+ public boolean handle(NetworkStackLatencyPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PhotoTransferPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerActionPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerHotbarPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerInputPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerSkinPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PurchaseReceiptPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RequestChunkRadiusPacket packet) {
+ System.out.println(packet.getClass().getName());
+ /** chunk = new ChunkRadiusUpdatedPacket();
+ chunk.setRadius(Math.max(3, Math.min(packet.getRadius(), 5)));
+ //PacketHeader ph = new PacketHeader();
+ // ph.set
+ //chunk.setHeader();
+ session.sendPacketImmediately(chunk);
+
+ int chunkPositionX = 0;
+ int chunkPositionZ = 0;
+ int chunkRadius = 5;
+ for (int x = -chunkRadius; x < chunkRadius; x++) {
+ for (int z = -chunkRadius; z < chunkRadius; z++) {
+ FullChunkDataPacket fullChunk = new FullChunkDataPacket();
+ fullChunk.setChunkX(chunkPositionX + x);
+ fullChunk.setChunkZ(chunkPositionZ + z);
+ fullChunk.setData(new byte[0]);
+ session.sendPacketImmediately(fullChunk);
+ }
+ }
+
+ PlayStatusPacket play = new PlayStatusPacket();
+ play.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
+ session.sendPacketImmediately(play);
+
+ SetTimePacket st = new SetTimePacket();
+ st.setTime(0);
+ session.sendPacketImmediately(st);
+ return false; **/
+ return false;
+ }
+
+ @Override
+ public boolean handle(RiderJumpPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerSettingsRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDefaultGameTypePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
+ System.out.println(packet.getClass().getName());
+
+ session.sendPacketImmediately(UIForms.createMain());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetPlayerGameTypePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SubClientLoginPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TextPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddBehaviorTreePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddEntityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddHangingEntityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddItemEntityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddPaintingPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AddPlayerPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AvailableCommandsPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BlockEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BossEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CameraPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ChangeDimensionPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ChunkRadiusUpdatedPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ClientboundMapItemDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CommandOutputPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerOpenPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ContainerSetDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(CraftingDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ExplodePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(FullChunkDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(GameRulesChangedPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(GuiDataPickItemPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(HurtArmorPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AutomationClientConnectPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MapCreateLockedCopyPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MobEffectPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ModalFormRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(MoveEntityDeltaPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(NpcRequestPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(OnScreenTextureAnimationPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayerListPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlaySoundPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(PlayStatusPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RemoveEntityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RemoveObjectivePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackChunkDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackDataInfoPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePacksInfoPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackStackPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(RespawnPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ScriptCustomEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerSettingsResponsePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ServerToClientHandshakePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetCommandsEnabledPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDifficultyPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetDisplayObjectivePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityDataPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityLinkPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetEntityMotionPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetHealthPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetLastHurtByPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetScoreboardIdentityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetScorePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetSpawnPositionPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetTimePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SetTitlePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowCreditsPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowProfilePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(ShowStoreOfferPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SimpleEventPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SpawnExperienceOrbPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StartGamePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StopSoundPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(StructureBlockUpdatePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TakeItemEntityPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(TransferPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateAttributesPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateBlockPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateBlockSyncedPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateEquipPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateSoftEnumPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(UpdateTradePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(AvailableEntityIdentifiersPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(BiomeDefinitionListPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(LevelSoundEvent2Packet packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(NetworkChunkPublisherUpdatePacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(SpawnParticleEffectPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ @Override
+ public boolean handle(VideoStreamConnectPacket packet) {
+ System.out.println(packet.getClass().getName());
+ return false;
+ }
+
+ public PacketHandler(BedrockServerSession session, Server server) {
+ this.session = session;
+ this.server = server;
+
+ session.addDisconnectHandler((Reason) -> disconnect());
+ }
+
+ public void disconnect() {
+ server.removePlayer(player);
+ }
+
+ private static boolean validateChainData(JsonNode data) throws Exception {
+ ECPublicKey lastKey = null;
+ boolean validChain = false;
+ for (JsonNode node : data) {
+ JWSObject jwt = JWSObject.parse(node.asText());
+
+ if (!validChain) {
+ validChain = verifyJwt(jwt, EncryptionUtils.getMojangPublicKey());
+ }
+
+ if (lastKey != null) {
+ verifyJwt(jwt, lastKey);
+ }
+
+ JsonNode payloadNode = Server.JSON_MAPPER.readTree(jwt.getPayload().toString());
+ JsonNode ipkNode = payloadNode.get("identityPublicKey");
+ Preconditions.checkState(ipkNode != null && ipkNode.getNodeType() == JsonNodeType.STRING, "identityPublicKey node is missing in chain");
+ lastKey = EncryptionUtils.generateKey(ipkNode.asText());
+ }
+ return validChain;
+ }
+
+
+ private static boolean verifyJwt(JWSObject jwt, ECPublicKey key) throws JOSEException {
+ return jwt.verify(new DefaultJWSVerifierFactory().createJWSVerifier(jwt.getHeader(), key));
+ }
+
+ @Override
+ public boolean handle(DisconnectPacket packet) {
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackChunkRequestPacket packet) {
+ System.out.println("Received Chunk Radius request");
+ return false;
+ }
+
+ @Override
+ public boolean handle(ResourcePackClientResponsePacket packet) {
+ switch (packet.getStatus()) {
+ case COMPLETED:
+ this.player = this.server.addPlayer(authData, session);
+ this.player.joinGame();
+ break;
+ case HAVE_ALL_PACKS:
+ ResourcePackStackPacket rs = new ResourcePackStackPacket();
+ rs.setExperimental(false);
+ rs.setForcedToAccept(false);
+ session.sendPacketImmediately(rs);
+ break;
+ default:
+ session.disconnect("disconnectionScreen.resourcePack");
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean handle(LoginPacket packet) {
+ int protocolVersion = packet.getProtocolVersion();
+
+ if (protocolVersion != server.getProtocol()) {
+ PlayStatusPacket status = new PlayStatusPacket();
+ if (protocolVersion > server.getProtocol()) {
+ status.setStatus(PlayStatusPacket.Status.FAILED_SERVER);
+ } else {
+ status.setStatus(PlayStatusPacket.Status.FAILED_CLIENT);
+ }
+ session.sendPacket(status);
+ }
+ session.setPacketCodec(server.getCodec());
+
+ JsonNode certData;
+ try {
+ certData = Server.JSON_MAPPER.readTree(packet.getChainData().toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException("Certificate JSON can not be read.");
+ }
+
+ JsonNode certChainData = certData.get("chain");
+ if (certChainData.getNodeType() != JsonNodeType.ARRAY) {
+ throw new RuntimeException("Certificate data is not valid");
+ }
+ chainData = (ArrayNode) certChainData;
+
+ boolean validChain;
+ try {
+ validChain = validateChainData(certChainData);
+
+ JWSObject jwt = JWSObject.parse(certChainData.get(certChainData.size() - 1).asText());
+ JsonNode payload = Server.JSON_MAPPER.readTree(jwt.getPayload().toBytes());
+
+ if (payload.get("extraData").getNodeType() != JsonNodeType.OBJECT) {
+ throw new RuntimeException("AuthData was not found!");
+ }
+
+ extraData = (JSONObject) jwt.getPayload().toJSONObject().get("extraData");
+
+ this.authData = new AuthData(extraData.getAsString("displayName"),
+ UUID.fromString(extraData.getAsString("identity")), extraData.getAsString("XUID"));
+
+ if (payload.get("identityPublicKey").getNodeType() != JsonNodeType.STRING) {
+ throw new RuntimeException("Identity Public Key was not found!");
+ }
+ ECPublicKey identityPublicKey = EncryptionUtils.generateKey(payload.get("identityPublicKey").textValue());
+
+ JWSObject clientJwt = JWSObject.parse(packet.getSkinData().toString());
+ verifyJwt(clientJwt, identityPublicKey);
+ skinData = clientJwt.getPayload().toJSONObject();
+
+ System.out.println("Made it through login - " + "User: " + extraData.getAsString("displayName") + " (" + extraData.getAsString("identity") + ")");
+
+ PlayStatusPacket status = new PlayStatusPacket();
+ status.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
+ session.sendPacketImmediately(status);
+
+ ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
+ resourcePacksInfo.setForcedToAccept(false);
+ session.sendPacketImmediately(resourcePacksInfo);
+
+ //this.player = this.server.addPlayer(authData, session);
+ //System.out.println(this.player.getProtocol().getProfile().getId());
+
+ /** MovePlayerPacket mp = new MovePlayerPacket();
+ mp.setRuntimeEntityId(-1);
+ session.sendPacket(mp);
+
+ SetSpawnPositionPacket ss = new SetSpawnPositionPacket();
+ ss.setBlockPosition(new Vector3i(0, 0 ,0));
+ ss.setSpawnForced(true);
+ ss.setSpawnType(SetSpawnPositionPacket.Type.PLAYER_SPAWN);
+ session.sendPacket(ss);
+
+ session.sendPacket(mp);
+
+ SetTimePacket st = new SetTimePacket();
+ st.setTime(0);
+ session.sendPacket(st);
+
+ RespawnPacket rp = new RespawnPacket();
+ rp.setPosition(new Vector3f(0, 0 ,0));
+ session.sendPacket(rp); **/
+
+ //MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
+ //PlayerList playerList = server.getPlayerList();
+
+ // GameProfile gameProfile = new GameProfile(UUID.fromString(extraData.getAsString("identity")), extraData.getAsString("displayName"));
+
+ // PipePlayer pl = new PipePlayer(session);
+ // pl.addEvent(new LoginEvent(gameProfile));
+ // this.server.addPlayer(pl);
+
+
+
+
+ //saveSkin();
+ } catch (Exception e) {
+ session.disconnect("disconnectionScreen.internalError.cantConnect");
+ throw new RuntimeException("Unable to complete login", e);
+ }
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/Binary.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/Binary.java
new file mode 100644
index 0000000..f27a3ff
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/Binary.java
@@ -0,0 +1,322 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils;
+
+import main.com.pyratron.pugmatt.bedrockconnect.utils.math.NukkitMath;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ * author: MagicDroidX Nukkit Project
+ */
+public class Binary {
+
+ public Binary() {
+
+ }
+
+ public static int signByte(int value) {
+ return value << 56 >> 56;
+ }
+
+ public static int unsignByte(int value) {
+ return value & 0xff;
+ }
+
+ public static int signShort(int value) {
+ return value << 48 >> 48;
+ }
+
+ public int unsignShort(int value) {
+ return value & 0xffff;
+ }
+
+ public static int signInt(int value) {
+ return value << 32 >> 32;
+ }
+
+ public static int unsignInt(int value) {
+ return value;
+ }
+
+ // Triad: {0x00,0x00,0x01}<=>1
+ public static int readTriad(byte[] bytes) {
+ return readInt(new byte[]{(byte) 0x00, bytes[0], bytes[1], bytes[2]});
+ }
+
+ public static byte[] writeTriad(int value) {
+ return new byte[]{(byte) ((value >>> 16) & 0xFF), (byte) ((value >>> 8) & 0xFF), (byte) (value & 0xFF)};
+ }
+
+ // LTriad: {0x01,0x00,0x00}<=>1
+ public static int readLTriad(byte[] bytes) {
+ return readLInt(new byte[]{bytes[0], bytes[1], bytes[2], (byte) 0x00});
+ }
+
+ public static byte[] writeLTriad(int value) {
+ return new byte[]{(byte) (value & 0xFF), (byte) ((value >>> 8) & 0xFF), (byte) ((value >>> 16) & 0xFF)};
+ }
+
+ public static UUID readUUID(byte[] bytes) {
+ return new UUID(readLLong(bytes), readLLong(
+ new byte[]{bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]}));
+ }
+
+ public static byte[] writeUUID(UUID uuid) {
+ return appendBytes(writeLLong(uuid.getMostSignificantBits()), writeLLong(uuid.getLeastSignificantBits()));
+ }
+
+ public static boolean readBool(byte b) {
+ return b == 0;
+ }
+
+ public static byte writeBool(boolean b) {
+ return (byte) (b ? 0x01 : 0x00);
+ }
+
+ public static int readSignedByte(byte b) {
+ return b & 0xFF;
+ }
+
+ public static byte writeByte(byte b) {
+ return b;
+ }
+
+ public static int readShort(byte[] bytes) {
+ return ((bytes[0] & 0xFF) << 8) + (bytes[1] & 0xFF);
+ }
+
+ public static short readSignedShort(byte[] bytes) {
+ return (short) readShort(bytes);
+ }
+
+ public static byte[] writeShort(int s) {
+ return new byte[]{(byte) ((s >>> 8) & 0xFF), (byte) (s & 0xFF)};
+ }
+
+ public static int readLShort(byte[] bytes) {
+ return (bytes[1] & 0xFF << 8) + (bytes[0] & 0xFF);
+ }
+
+ public static short readSignedLShort(byte[] bytes) {
+ return (short) readLShort(bytes);
+ }
+
+ public static byte[] writeLShort(int s) {
+ s &= 0xffff;
+ return new byte[]{(byte) (s & 0xFF), (byte) ((s >>> 8) & 0xFF)};
+ }
+
+ public static int readInt(byte[] bytes) {
+ return ((bytes[0] & 0xff) << 24) + ((bytes[1] & 0xff) << 16) + ((bytes[2] & 0xff) << 8) + (bytes[3] & 0xff);
+ }
+
+ public static byte[] writeInt(int i) {
+ return new byte[]{(byte) ((i >>> 24) & 0xFF), (byte) ((i >>> 16) & 0xFF), (byte) ((i >>> 8) & 0xFF),
+ (byte) (i & 0xFF)};
+ }
+
+ public static int readLInt(byte[] bytes) {
+ return ((bytes[3] & 0xff) << 24) + ((bytes[2] & 0xff) << 16) + ((bytes[1] & 0xff) << 8) + (bytes[0] & 0xff);
+ }
+
+ public static byte[] writeLInt(int i) {
+ return new byte[]{(byte) (i & 0xFF), (byte) ((i >>> 8) & 0xFF), (byte) ((i >>> 16) & 0xFF),
+ (byte) ((i >>> 24) & 0xFF)};
+ }
+
+ public static float readFloat(byte[] bytes) {
+ return readFloat(bytes, -1);
+ }
+
+ public static float readFloat(byte[] bytes, int accuracy) {
+ float val = Float.intBitsToFloat(readInt(bytes));
+ if (accuracy > -1) {
+ return (float) NukkitMath.round(val, accuracy);
+ } else {
+ return val;
+ }
+ }
+
+ public static byte[] writeFloat(float f) {
+ return writeInt(Float.floatToIntBits(f));
+ }
+
+ public static float readLFloat(byte[] bytes) {
+ return readLFloat(bytes, -1);
+ }
+
+ public static float readLFloat(byte[] bytes, int accuracy) {
+ float val = Float.intBitsToFloat(readLInt(bytes));
+ if (accuracy > -1) {
+ return (float) NukkitMath.round(val, accuracy);
+ } else {
+ return val;
+ }
+ }
+
+ public static byte[] writeLFloat(float f) {
+ return writeLInt(Float.floatToIntBits(f));
+ }
+
+ public static double readDouble(byte[] bytes) {
+ return Double.longBitsToDouble(readLong(bytes));
+ }
+
+ public static byte[] writeDouble(double d) {
+ return writeLong(Double.doubleToLongBits(d));
+ }
+
+ public static double readLDouble(byte[] bytes) {
+ return Double.longBitsToDouble(readLLong(bytes));
+ }
+
+ public static byte[] writeLDouble(double d) {
+ return writeLLong(Double.doubleToLongBits(d));
+ }
+
+ public static long readLong(byte[] bytes) {
+ return (((long) bytes[0] << 56) + ((long) (bytes[1] & 0xFF) << 48) + ((long) (bytes[2] & 0xFF) << 40)
+ + ((long) (bytes[3] & 0xFF) << 32) + ((long) (bytes[4] & 0xFF) << 24) + ((bytes[5] & 0xFF) << 16)
+ + ((bytes[6] & 0xFF) << 8) + ((bytes[7] & 0xFF)));
+ }
+
+ public static byte[] writeLong(long l) {
+ return new byte[]{(byte) (l >>> 56), (byte) (l >>> 48), (byte) (l >>> 40), (byte) (l >>> 32),
+ (byte) (l >>> 24), (byte) (l >>> 16), (byte) (l >>> 8), (byte) (l)};
+ }
+
+ public static long readLLong(byte[] bytes) {
+ return (((long) bytes[7] << 56) + ((long) (bytes[6] & 0xFF) << 48) + ((long) (bytes[5] & 0xFF) << 40)
+ + ((long) (bytes[4] & 0xFF) << 32) + ((long) (bytes[3] & 0xFF) << 24) + ((bytes[2] & 0xFF) << 16)
+ + ((bytes[1] & 0xFF) << 8) + ((bytes[0] & 0xFF)));
+ }
+
+ public static byte[] writeLLong(long l) {
+ return new byte[]{(byte) (l), (byte) (l >>> 8), (byte) (l >>> 16), (byte) (l >>> 24), (byte) (l >>> 32),
+ (byte) (l >>> 40), (byte) (l >>> 48), (byte) (l >>> 56),};
+ }
+
+ public static byte[] writeVarInt(int v) {
+ BinaryStream stream = new BinaryStream();
+ stream.putVarInt(v);
+ return stream.getBuffer();
+ }
+
+ public static byte[] writeUnsignedVarInt(long v) {
+ BinaryStream stream = new BinaryStream();
+ stream.putUnsignedVarInt(v);
+ return stream.getBuffer();
+ }
+
+ public static byte[] reserveBytes(byte[] bytes) {
+ byte[] newBytes = new byte[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ newBytes[bytes.length - 1 - i] = bytes[i];
+ }
+ return newBytes;
+ }
+
+ public static String bytesToHexString(byte[] src) {
+ return bytesToHexString(src, false);
+ }
+
+ public static String bytesToHexString(byte[] src, boolean blank) {
+ StringBuilder stringBuilder = new StringBuilder("");
+ if (src == null || src.length <= 0) {
+ return null;
+ }
+
+ for (byte b : src) {
+ if (!(stringBuilder.length() == 0) && blank) {
+ stringBuilder.append(" ");
+ }
+ int v = b & 0xFF;
+ String hv = Integer.toHexString(v);
+ if (hv.length() < 2) {
+ stringBuilder.append(0);
+ }
+ stringBuilder.append(hv);
+ }
+ return stringBuilder.toString().toUpperCase();
+ }
+
+ public static byte[] hexStringToBytes(String hexString) {
+ if (hexString == null || hexString.equals("")) {
+ return null;
+ }
+ String str = "0123456789ABCDEF";
+ hexString = hexString.toUpperCase().replace(" ", "");
+ int length = hexString.length() / 2;
+ char[] hexChars = hexString.toCharArray();
+ byte[] d = new byte[length];
+ for (int i = 0; i < length; i++) {
+ int pos = i * 2;
+ d[i] = (byte) (((byte) str.indexOf(hexChars[pos]) << 4) | ((byte) str.indexOf(hexChars[pos + 1])));
+ }
+ return d;
+ }
+
+ public static byte[] subBytes(byte[] bytes, int start, int length) {
+ int len = Math.min(bytes.length, start + length);
+ return Arrays.copyOfRange(bytes, start, len);
+ }
+
+ public static byte[] subBytes(byte[] bytes, int start) {
+ return subBytes(bytes, start, bytes.length - start);
+ }
+
+ public static byte[][] splitBytes(byte[] bytes, int chunkSize) {
+ byte[][] splits = new byte[(bytes.length + chunkSize - 1) / chunkSize][chunkSize];
+ int chunks = 0;
+
+ for (int i = 0; i < bytes.length; i += chunkSize) {
+ if ((bytes.length - i) > chunkSize) {
+ splits[chunks] = Arrays.copyOfRange(bytes, i, i + chunkSize);
+ } else {
+ splits[chunks] = Arrays.copyOfRange(bytes, i, bytes.length);
+ }
+ chunks++;
+ }
+
+ return splits;
+ }
+
+ public static byte[] appendBytes(byte[][] bytes) {
+ int length = 0;
+ for (byte[] b : bytes) {
+ length += b.length;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(length);
+ for (byte[] b : bytes) {
+ buffer.put(b);
+ }
+ return buffer.array();
+ }
+
+ public static byte[] appendBytes(byte byte1, byte[]... bytes2) {
+ int length = 1;
+ for (byte[] bytes : bytes2) {
+ length += bytes.length;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(length);
+ buffer.put(byte1);
+ for (byte[] bytes : bytes2) {
+ buffer.put(bytes);
+ }
+ return buffer.array();
+ }
+
+ public static byte[] appendBytes(byte[] bytes1, byte[]... bytes2) {
+ int length = bytes1.length;
+ for (byte[] bytes : bytes2) {
+ length += bytes.length;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(length);
+ buffer.put(bytes1);
+ for (byte[] bytes : bytes2) {
+ buffer.put(bytes);
+ }
+ return buffer.array();
+ }
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/BinaryStream.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/BinaryStream.java
new file mode 100644
index 0000000..a52301e
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/BinaryStream.java
@@ -0,0 +1,528 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * author: MagicDroidX Nukkit Project
+ */
+public class BinaryStream {
+
+ public int offset;
+ private byte[] buffer = new byte[32];
+ private int count;
+
+ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ public BinaryStream() {
+ this.buffer = new byte[32];
+ this.offset = 0;
+ this.count = 0;
+ }
+
+ public BinaryStream(byte[] buffer) {
+ this(buffer, 0);
+ }
+
+ public BinaryStream(byte[] buffer, int offset) {
+ this.buffer = buffer;
+ this.offset = offset;
+ this.count = buffer.length;
+ }
+
+ public void reset() {
+ this.buffer = new byte[32];
+ this.offset = 0;
+ this.count = 0;
+ }
+
+ public byte[] getBuffer() {
+ return Arrays.copyOf(buffer, count);
+ }
+
+ public void setBuffer(byte[] buffer) {
+ this.buffer = buffer;
+ this.count = buffer == null ? -1 : buffer.length;
+ }
+
+ public void setBuffer(byte[] buffer, int offset) {
+ this.setBuffer(buffer);
+ this.setOffset(offset);
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public byte[] get() {
+ return this.get(this.count - this.offset);
+ }
+
+ public byte[] get(int len) {
+ if (len < 0) {
+ this.offset = this.count - 1;
+ return new byte[0];
+ }
+ len = Math.min(len, this.getCount() - this.offset);
+ this.offset += len;
+ return Arrays.copyOfRange(this.buffer, this.offset - len, this.offset);
+ }
+
+ public void put(byte[] bytes) {
+ if (bytes == null) {
+ return;
+ }
+
+ this.ensureCapacity(this.count + bytes.length);
+
+ System.arraycopy(bytes, 0, this.buffer, this.count, bytes.length);
+ this.count += bytes.length;
+ }
+
+ public long getLong() {
+ return Binary.readLong(this.get(8));
+ }
+
+ public void putLong(long l) {
+ this.put(Binary.writeLong(l));
+ }
+
+ public int getInt() {
+ return Binary.readInt(this.get(4));
+ }
+
+ public void putInt(int i) {
+ this.put(Binary.writeInt(i));
+ }
+
+ public long getLLong() {
+ return Binary.readLLong(this.get(8));
+ }
+
+ public void putLLong(long l) {
+ this.put(Binary.writeLLong(l));
+ }
+
+ public int getLInt() {
+ return Binary.readLInt(this.get(4));
+ }
+
+ public void putLInt(int i) {
+ this.put(Binary.writeLInt(i));
+ }
+
+ public int getShort() {
+ return Binary.readShort(this.get(2));
+ }
+
+ public void putShort(int s) {
+ this.put(Binary.writeShort(s));
+ }
+
+ public int getLShort() {
+ return Binary.readLShort(this.get(2));
+ }
+
+ public void putLShort(int s) {
+ this.put(Binary.writeLShort(s));
+ }
+
+ public float getFloat() {
+ return getFloat(-1);
+ }
+
+ public float getFloat(int accuracy) {
+ return Binary.readFloat(this.get(4), accuracy);
+ }
+
+ public void putFloat(float v) {
+ this.put(Binary.writeFloat(v));
+ }
+
+ public float getLFloat() {
+ return getLFloat(-1);
+ }
+
+ public float getLFloat(int accuracy) {
+ return Binary.readLFloat(this.get(4), accuracy);
+ }
+
+ public void putLFloat(float v) {
+ this.put(Binary.writeLFloat(v));
+ }
+
+ public int getTriad() {
+ return Binary.readTriad(this.get(3));
+ }
+
+ public void putTriad(int triad) {
+ this.put(Binary.writeTriad(triad));
+ }
+
+ public int getLTriad() {
+ return Binary.readLTriad(this.get(3));
+ }
+
+ public void putLTriad(int triad) {
+ this.put(Binary.writeLTriad(triad));
+ }
+
+ public boolean getBoolean() {
+ return this.getByte() == 0x01;
+ }
+
+ public void putBoolean(boolean bool) {
+ this.putByte((byte) (bool ? 1 : 0));
+ }
+
+ public int getByte() {
+ return this.buffer[this.offset++] & 0xff;
+ }
+
+ public void putByte(byte b) {
+ this.put(new byte[]{b});
+ }
+
+ /** public void putEntityLink(PEEntityLink link) {
+ putVarLong(link.riding);
+ putVarLong(link.rider);
+ putByte(link.type);
+ putByte(link.unknownByte);
+ }
+
+// public PEEntityLink getEntityLink() {
+// return new PEEntityLink(
+// getVarLong(),
+// getVarLong(),
+// getByte(),
+// getByte());
+// }
+
+ public Map<String, GameRule> getGameRules() {
+ int count = (int) getUnsignedVarInt();
+ Map<String, GameRule> rules = new HashMap<>();
+ for (int i = 0; i < count; i++) {
+ GameRule rule = GameRule.read(this);
+ rules.put(rule.name, rule);
+ }
+ return rules;
+ }
+
+ public void putGameRules(Map<String, GameRule> rules) {
+ if (rules == null) {
+ putUnsignedVarInt(0);
+ return;
+ }
+ putUnsignedVarInt(rules.size());
+ for (GameRule rule : rules.values()) {
+ rule.write(this);
+ }
+ }
+
+ public float getByteRotation() {
+ return (((float) (getByte() & 0xFF)) * (360 / 256));
+ }
+
+ public void putByteRotation(float rotation) {
+ putByte((byte) (((int) (rotation / (360 / 256))) & 0xFF));
+ }
+
+ /**
+ * Reads a list of Attributes from the stream.
+ *
+ * @return Attribute[]
+ */
+ /**
+ public PEEntityAttribute[] getAttributeList() throws Exception {
+ List<PEEntityAttribute> list = new ArrayList<>();
+ long count = this.getUnsignedVarInt();
+
+ for (int i = 0; i < count; ++i) {
+ String name = this.getString();
+ PEEntityAttribute attr = PEEntityAttribute.findAttribute(name);
+ if (attr != null) {
+ attr.min = getLFloat();
+ attr.currentValue = getLFloat();
+ attr.max = this.getLFloat();
+ list.add(attr);
+ } else {
+ throw new Exception("Unknown attribute type \"" + name + "\"");
+ }
+ }
+
+ return list.stream().toArray(PEEntityAttribute[]::new);
+ }
+ /**
+
+ /**
+ * Writes a list of Attributes to the packet buffer using the standard
+ * format.
+ */
+ /**
+ public void putAttributeList(PEEntityAttribute[] attributes) {
+ this.putUnsignedVarInt(attributes.length);
+ for (PEEntityAttribute attribute : attributes) {
+ this.putString(attribute.name);
+ this.putLFloat(attribute.min);
+ this.putLFloat(attribute.currentValue);
+ this.putLFloat(attribute.max);
+ }
+ }
+
+ public void putUUID(UUID uuid) {
+ this.put(Binary.writeUUID(uuid));
+ }
+
+ public UUID getUUID() {
+ return Binary.readUUID(this.get(16));
+ }
+
+ public void putSkin(Skin skin) {
+ this.putString(skin.getModel());
+ this.putByteArray(skin.getData());
+ this.putByteArray(skin.getCape().getData());
+ }
+
+ public Skin getSkin() {
+ String modelId = this.getString();
+ byte[] skinData = this.getByteArray();
+ return new Skin(skinData, modelId);
+ }
+
+ public Slot getSlot() {
+ int id = this.getVarInt();
+
+ if (id <= 0) {
+ return Slot.AIR;
+ }
+ int auxValue = this.getVarInt();
+ int data = auxValue >> 8;
+ if (data == Short.MAX_VALUE) {
+ data = -1;
+ }
+ int cnt = auxValue & 0xff;
+
+ int nbtLen = this.getLShort();
+ byte[] nbt;
+ CompoundTag tag = null;
+ if (nbtLen > 0) {
+ nbt = this.get(nbtLen);
+ try {
+ tag = NBTIO.read(nbt, ByteOrder.LITTLE_ENDIAN, false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // TODO
+ int canPlaceOn = this.getVarInt();
+ if (canPlaceOn > 0) {
+ for (int i = 0; i < canPlaceOn; ++i) {
+ this.getString();
+ }
+ }
+
+ // TODO
+ int canDestroy = this.getVarInt();
+ if (canDestroy > 0) {
+ for (int i = 0; i < canDestroy; ++i) {
+ this.getString();
+ }
+ }
+
+ return new Slot(id, data, cnt, tag);
+ }
+
+ public void putSlot(Slot item) {
+ if (item == null || item.id == 0) {
+ this.putVarInt(0);
+ return;
+ }
+
+ this.putVarInt(item.id);
+ int auxValue = ((item.damage & 0x7fff) << 8) | item.count;
+ this.putVarInt(auxValue);
+ byte[] nbt;
+ if (item.tag != null) {
+ try {
+ nbt = NBTIO.write(item.tag, ByteOrder.LITTLE_ENDIAN, false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ nbt = new byte[0];
+ }
+ } else {
+ nbt = new byte[0];
+ }
+ this.putLShort(nbt.length);
+ this.put(nbt);
+ this.putVarInt(0); // TODO CanPlaceOn entry count
+ this.putVarInt(0); // TODO CanDestroy entry count
+ }
+
+ **/
+
+
+ public byte[] getByteArray() {
+ return this.get((int) this.getUnsignedVarInt());
+ }
+
+ public void putByteArray(byte[] b) {
+ this.putUnsignedVarInt(b.length);
+ this.put(b);
+ }
+
+ public String getString() {
+ return new String(this.getByteArray(), StandardCharsets.UTF_8);
+ }
+
+ public void putString(String string) {
+ byte[] b = string.getBytes(StandardCharsets.UTF_8);
+ this.putByteArray(b);
+ }
+
+ public long getUnsignedVarInt() {
+ return VarInt.readUnsignedVarInt(this);
+ }
+
+ public void putUnsignedVarInt(long v) {
+ VarInt.writeUnsignedVarInt(this, v);
+ }
+
+ public int getVarInt() {
+ return VarInt.readVarInt(this);
+ }
+
+ public void putVarInt(int v) {
+ VarInt.writeVarInt(this, v);
+ }
+
+ public long getVarLong() {
+ return VarInt.readVarLong(this);
+ }
+
+ public void putVarLong(long v) {
+ VarInt.writeVarLong(this, v);
+ }
+
+ public long getUnsignedVarLong() {
+ return VarInt.readUnsignedVarLong(this);
+ }
+
+ public void putUnsignedVarLong(long v) {
+ VarInt.writeUnsignedVarLong(this, v);
+ }
+
+ /**
+ public BlockPosition getBlockPosition() {
+ return new BlockPosition(this.getVarInt(), (int) this.getUnsignedVarInt(), this.getVarInt());
+ }
+
+ public BlockPosition getSignedBlockPosition() {
+ return new BlockPosition(getVarInt(), getVarInt(), getVarInt());
+ }
+
+ public void putSignedBlockPosition(BlockPosition v) {
+ putVarInt(v.x);
+ putVarInt(v.y);
+ putVarInt(v.z);
+ }
+
+ public void putBlockPosition(BlockPosition v) {
+ this.putBlockPosition(v.x, v.y, v.z);
+ }
+
+ public void putBlockPosition(int x, int y, int z) {
+ this.putVarInt(x);
+ this.putUnsignedVarInt(y);
+ this.putVarInt(z);
+ }
+
+ public Vector3F getVector3F() {
+ return new Vector3F(this.getLFloat(4), this.getLFloat(4), this.getLFloat(4));
+ }
+
+ public void putVector3F(Vector3F v) {
+ if (v == null) {
+ this.putVector3F(0f, 0f, 0f);
+ } else {
+ this.putVector3F(v.x, v.y, v.z);
+ }
+ }
+
+ public void putVector3F(float x, float y, float z) {
+ this.putLFloat(Math.round(x * 10000f) / 10000f);
+ this.putLFloat(Math.round(y * 10000f) / 10000f);
+ this.putLFloat(Math.round(z * 10000f) / 10000f);
+ }
+
+ /**
+ * Reads and returns an EntityUniqueID
+ *
+ * @return int
+ */
+ public long getEntityUniqueId() {
+ return this.getVarLong();
+ }
+
+ /**
+ * Writes an EntityUniqueID
+ */
+ public void putEntityUniqueId(long eid) {
+ this.putVarLong(eid);
+ }
+
+ /**
+ * Reads and returns an EntityRuntimeID
+ */
+ public long getEntityRuntimeId() {
+ return this.getUnsignedVarLong();
+ }
+
+ /**
+ * Writes an EntityUniqueID
+ */
+ public void putEntityRuntimeId(long eid) {
+ this.putUnsignedVarLong(eid);
+ }
+
+ public boolean feof() {
+ return this.offset < 0 || this.offset >= this.buffer.length;
+ }
+
+ private void ensureCapacity(int minCapacity) {
+ // overflow-conscious code
+ if (minCapacity - buffer.length > 0) {
+ grow(minCapacity);
+ }
+ }
+
+ private void grow(int minCapacity) {
+ // overflow-conscious code
+ int oldCapacity = buffer.length;
+ int newCapacity = oldCapacity << 1;
+
+ if (newCapacity - minCapacity < 0) {
+ newCapacity = minCapacity;
+ }
+
+ if (newCapacity - MAX_ARRAY_SIZE > 0) {
+ newCapacity = hugeCapacity(minCapacity);
+ }
+ this.buffer = Arrays.copyOf(buffer, newCapacity);
+ }
+
+ private static int hugeCapacity(int minCapacity) {
+ if (minCapacity < 0) { // overflow
+ throw new OutOfMemoryError();
+ }
+ return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/FixedPlayerListPacket.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/FixedPlayerListPacket.java
new file mode 100644
index 0000000..8313681
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/FixedPlayerListPacket.java
@@ -0,0 +1,7 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils;
+
+import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
+
+public class FixedPlayerListPacket extends PlayerListPacket {
+
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/PaletteManager.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/PaletteManager.java
new file mode 100644
index 0000000..6c033fc
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/PaletteManager.java
@@ -0,0 +1,69 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.CollectionType;
+import com.nukkitx.network.VarInts;
+import com.nukkitx.protocol.bedrock.v354.BedrockUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import main.com.pyratron.pugmatt.bedrockconnect.BedrockConnect;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+// https://github.com/DragonetMC/DragonProxy/blob/rewrite/proxy/src/main/java/org/dragonet/proxy/util/PaletteManager.java
+// Author: lukeeey
+
+public class PaletteManager {
+
+ private ByteBuf cachedPalette;
+
+ public ByteBuf getCachedPalette() {
+ return cachedPalette;
+ }
+
+ public PaletteManager() {
+ InputStream stream = BedrockConnect.class.getClassLoader().getResourceAsStream("tables/runtimeid_table.json");
+ if (stream == null) {
+ throw new AssertionError("Static Runtime ID table not found");
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ CollectionType type = mapper.getTypeFactory().constructCollectionType(ArrayList.class, RuntimeEntry.class);
+
+ ArrayList<RuntimeEntry> entries = new ArrayList<>();
+ try {
+ entries = mapper.readValue(stream, type);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ cachedPalette = Unpooled.buffer();
+
+ VarInts.writeInt(cachedPalette, entries.size());
+
+ for (RuntimeEntry entry : entries) {
+ BedrockUtils.writeString(cachedPalette, entry.name);
+ cachedPalette.writeShortLE(entry.data);
+ }
+
+ }
+
+ private static class RuntimeEntry {
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("id")
+ private int id;
+ @JsonProperty("data")
+ private int data;
+
+ public RuntimeEntry() {}
+
+ public RuntimeEntry(String name, int id, int data) {
+ this.id = id;
+ this.name = name;
+ this.data = data;
+ }
+ }
+}
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/VarInt.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/VarInt.java
new file mode 100644
index 0000000..ad5ec7e
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/VarInt.java
@@ -0,0 +1,235 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Tool class for VarInt or VarLong operations.
+ * <p>
+ * Some code from http://wiki.vg/Protocol.
+ *
+ * @author MagicDroidX
+ * @author lmlstarqaq
+ */
+public final class VarInt {
+
+ private VarInt() {
+ // no instance
+ }
+
+ /**
+ * @param v Signed int
+ * @return Unsigned encoded int
+ */
+ public static long encodeZigZag32(int v) {
+ // Note: the right-shift must be arithmetic
+ return (long) ((v << 1) ^ (v >> 31));
+ }
+
+ /**
+ * @param v Unsigned encoded int
+ * @return Signed decoded int
+ */
+ public static int decodeZigZag32(long v) {
+ return (int) (v >> 1) ^ -(int) (v & 1);
+ }
+
+ /**
+ * @param v Signed long
+ * @return Unsigned encoded long
+ */
+ public static long encodeZigZag64(long v) {
+ return (v << 1) ^ (v >> 63);
+ }
+
+ /**
+ * @param v Signed encoded long
+ * @return Unsigned decoded long
+ */
+ public static long decodeZigZag64(long v) {
+ return (v >>> 1) ^ -(v & 1);
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @return Signed int
+ */
+ public static int readVarInt(BinaryStream stream) {
+ return decodeZigZag32(readUnsignedVarInt(stream));
+ }
+
+ /**
+ * @param stream InputStream
+ * @return Signed int
+ */
+ public static int readVarInt(InputStream stream) throws IOException {
+ return decodeZigZag32(readUnsignedVarInt(stream));
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @return Unsigned int
+ */
+ public static long readUnsignedVarInt(BinaryStream stream) {
+ return read(stream, 5);
+ }
+
+ /**
+ * @param stream InputStream
+ * @return Unsigned int
+ */
+ public static long readUnsignedVarInt(InputStream stream) throws IOException {
+ return read(stream, 5);
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @return Signed long
+ */
+ public static long readVarLong(BinaryStream stream) {
+ return decodeZigZag64(readUnsignedVarLong(stream));
+ }
+
+ /**
+ * @param stream InputStream
+ * @return Signed long
+ */
+ public static long readVarLong(InputStream stream) throws IOException {
+ return decodeZigZag64(readUnsignedVarLong(stream));
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @return Unsigned long
+ */
+ public static long readUnsignedVarLong(BinaryStream stream) {
+ return read(stream, 10);
+ }
+
+ /**
+ * @param stream InputStream
+ * @return Unsigned long
+ */
+ public static long readUnsignedVarLong(InputStream stream) throws IOException {
+ return read(stream, 10);
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @param value Signed int
+ */
+ public static void writeVarInt(BinaryStream stream, int value) {
+ writeUnsignedVarInt(stream, encodeZigZag32(value));
+ }
+
+ /**
+ * @param stream OutputStream
+ * @param value Signed int
+ */
+ public static void writeVarInt(OutputStream stream, int value) throws IOException {
+ writeUnsignedVarInt(stream, encodeZigZag32(value));
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @param value Unsigned int
+ */
+ public static void writeUnsignedVarInt(BinaryStream stream, long value) {
+ write(stream, value);
+ }
+
+ /**
+ * @param stream OutputStream
+ * @param value Unsigned int
+ */
+ public static void writeUnsignedVarInt(OutputStream stream, long value) throws IOException {
+ write(stream, value);
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @param value Signed long
+ */
+ public static void writeVarLong(BinaryStream stream, long value) {
+ writeUnsignedVarLong(stream, encodeZigZag64(value));
+ }
+
+ /**
+ * @param stream OutputStream
+ * @param value Signed long
+ */
+ public static void writeVarLong(OutputStream stream, long value) throws IOException {
+ writeUnsignedVarLong(stream, encodeZigZag64(value));
+ }
+
+ /**
+ * @param stream BinaryStream
+ * @param value Unsigned long
+ */
+ public static void writeUnsignedVarLong(BinaryStream stream, long value) {
+ write(stream, value);
+ }
+
+ /**
+ * @param stream OutputStream
+ * @param value Unsigned long
+ */
+ public static void writeUnsignedVarLong(OutputStream stream, long value) throws IOException {
+ write(stream, value);
+ }
+
+ private static long read(BinaryStream stream, int maxSize) {
+ long value = 0;
+ int size = 0;
+ int b;
+ while (((b = stream.getByte()) & 0x80) == 0x80) {
+ value |= (long) (b & 0x7F) << (size++ * 7);
+ if (size >= maxSize) {
+ throw new IllegalArgumentException("VarLong too big");
+ }
+ }
+
+ return value | ((long) (b & 0x7F) << (size * 7));
+ }
+
+ private static long read(InputStream stream, int maxSize) throws IOException {
+ long value = 0;
+ int size = 0;
+ int b;
+ while (((b = stream.read()) & 0x80) == 0x80) {
+ value |= (long) (b & 0x7F) << (size++ * 7);
+ if (size >= maxSize) {
+ throw new IllegalArgumentException("VarLong too big");
+ }
+ }
+
+ return value | ((long) (b & 0x7F) << (size * 7));
+ }
+
+ private static void write(BinaryStream stream, long value) {
+ do {
+ byte temp = (byte) (value & 0b01111111);
+ // Note: >>> means that the sign bit is shifted with the rest of the number
+ // rather than being left alone
+ value >>>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ stream.putByte(temp);
+ } while (value != 0);
+ }
+
+ private static void write(OutputStream stream, long value) throws IOException {
+ do {
+ byte temp = (byte) (value & 0b01111111);
+ // Note: >>> means that the sign bit is shifted with the rest of the number
+ // rather than being left alone
+ value >>>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ stream.write(temp);
+ } while (value != 0);
+ }
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitMath.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitMath.java
new file mode 100644
index 0000000..a7445df
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitMath.java
@@ -0,0 +1,67 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils.math;
+
+/**
+ * author: MagicDroidX Nukkit Project
+ */
+public class NukkitMath {
+
+ public NukkitMath() {
+
+ }
+
+ public static int floorDouble(double n) {
+ int i = (int) n;
+ return n >= i ? i : i - 1;
+ }
+
+ public static int ceilDouble(double n) {
+ int i = (int) (n + 1);
+ return n >= i ? i : i - 1;
+ }
+
+ public static int floorFloat(float n) {
+ int i = (int) n;
+ return n >= i ? i : i - 1;
+ }
+
+ public static int ceilFloat(float n) {
+ int i = (int) (n + 1);
+ return n >= i ? i : i - 1;
+ }
+
+ public static int randomRange(NukkitRandom random) {
+ return randomRange(random, 0);
+ }
+
+ public static int randomRange(NukkitRandom random, int start) {
+ return randomRange(random, 0, 0x7fffffff);
+ }
+
+ public static int randomRange(NukkitRandom random, int start, int end) {
+ return start + (random.nextInt() % (end + 1 - start));
+ }
+
+ public static double round(double d) {
+ return round(d, 0);
+ }
+
+ public static double round(double d, int precision) {
+ return ((double) Math.round(d * Math.pow(10, precision))) / Math.pow(10, precision);
+ }
+
+ public static double clamp(double check, double min, double max) {
+ return check > max ? max : (check < min ? min : check);
+ }
+
+ public static double getDirection(double d0, double d1) {
+ if (d0 < 0.0D) {
+ d0 = -d0;
+ }
+
+ if (d1 < 0.0D) {
+ d1 = -d1;
+ }
+
+ return d0 > d1 ? d0 : d1;
+ }
+} \ No newline at end of file
diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitRandom.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitRandom.java
new file mode 100644
index 0000000..013eb1f
--- /dev/null
+++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/utils/math/NukkitRandom.java
@@ -0,0 +1,79 @@
+package main.com.pyratron.pugmatt.bedrockconnect.utils.math;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.zip.CRC32;
+
+/**
+ * author: Angelic47 Nukkit Project
+ */
+public class NukkitRandom {
+
+ protected long seed;
+
+ // constructor
+ public NukkitRandom() {
+ this(-1);
+ }
+
+ public NukkitRandom(long seeds) {
+ if (seeds == -1) {
+ seeds = System.currentTimeMillis() / 1000L;
+ }
+ this.setSeed(seeds);
+ }
+
+ public void setSeed(long seeds) {
+ CRC32 crc32 = new CRC32();
+ ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
+ buffer.putInt((int) seeds);
+ crc32.update(buffer.array());
+ this.seed = crc32.getValue();
+ }
+
+ public int nextSignedInt() {
+ int t = (((int) ((this.seed * 65535) + 31337) >> 8) + 1337);
+ this.seed ^= t;
+ return t;
+ }
+
+ public int nextInt() {
+ return this.nextSignedInt() & 0x7fffffff;
+ }
+
+ public double nextDouble() {
+ return (double) this.nextInt() / 0x7fffffff;
+ }
+
+ public float nextFloat() {
+ return (float) this.nextInt() / 0x7fffffff;
+ }
+
+ public float nextSignedFloat() {
+ return (float) this.nextInt() / 0x7fffffff;
+ }
+
+ public double nextSignedDouble() {
+ return (double) this.nextSignedInt() / 0x7fffffff;
+ }
+
+ public boolean nextBoolean() {
+ return (this.nextSignedInt() & 0x01) == 0;
+ }
+
+ public int nextRange() {
+ return nextRange(0, 0x7fffffff);
+ }
+
+ public int nextRange(int start) {
+ return nextRange(start, 0x7fffffff);
+ }
+
+ public int nextRange(int start, int end) {
+ return start + (this.nextInt() % (end + 1 - start));
+ }
+
+ public int nextBoundedInt(int bound) {
+ return this.nextInt() % bound;
+ }
+} \ No newline at end of file