From 383429d71b4bc17e7bbafb58879058b338ee91fc Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 8 Sep 2019 15:46:10 -0500 Subject: [PATCH] Fix a few chunk errors This does not fix chunks on its own, they're still very much a work in progress, however this commit should hopefully resolve a few issues. The client might still crash due to some invalid mappings (most likely), but this should bring us one step closer. With hardcoded values for the chunks, the client wouldn't crash (which leads me to the conclusion stated above) and on the occasions that it would not time out, the chunks were empty. Co-authored-by: SupremeMortal --- .../network/translators/TranslatorsInit.java | 4 +- .../java/world/JavaChunkDataPacket.java | 55 ------------- .../java/world/JavaChunkDataTranslator.java | 59 ++++++++++++++ .../geysermc/connector/utils/ChunkUtils.java | 81 ++++++++++--------- .../org/geysermc/connector/utils/Toolbox.java | 2 +- 5 files changed, 104 insertions(+), 97 deletions(-) delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataPacket.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index fcef782d5..a2fb6ff2f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -100,7 +100,7 @@ import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPla import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator; -import org.geysermc.connector.network.translators.java.world.JavaChunkDataPacket; +import org.geysermc.connector.network.translators.java.world.JavaChunkDataTranslator; import org.geysermc.connector.network.translators.java.world.JavaNotifyClientTranslator; import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator; import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator; @@ -168,7 +168,7 @@ public class TranslatorsInit { Registry.registerJava(ServerPlayerHealthPacket.class, new JavaPlayerHealthTranslator()); Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator()); - Registry.registerJava(ServerChunkDataPacket.class, new JavaChunkDataPacket()); + Registry.registerJava(ServerChunkDataPacket.class, new JavaChunkDataTranslator()); Registry.registerJava(ServerEntityDestroyPacket.class, new JavaEntityDestroyTranslator()); Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator()); Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataPacket.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataPacket.java deleted file mode 100644 index a7656ed82..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataPacket.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.geysermc.connector.network.translators.java.world; - -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket; -import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.geysermc.connector.console.GeyserLogger; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.utils.ChunkUtils; -import org.geysermc.connector.world.chunk.ChunkSection; - -public class JavaChunkDataPacket extends PacketTranslator { - - @Override - public void translate(ServerChunkDataPacket packet, GeyserSession session) { - - try { - byte[] buffer = new byte[32]; - ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn()); - - int count = 0; - ChunkSection[] sections = chunkData.sections; - for (int i = sections.length - 1; i >= 0; i--) { - if (sections[i].isEmpty()) - continue; - - count = i + 1; - break; - } - - for (int i = 0; i < count; i++) { - ChunkUtils.putBytes(count, buffer, new byte[]{(byte) 0}); - ChunkSection section = chunkData.sections[i]; - - ByteBuf byteBuf = Unpooled.buffer(); - section.writeToNetwork(byteBuf); - byte[] byteData = byteBuf.array(); - ChunkUtils.putBytes(count, buffer, byteData); - } - - LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); - levelChunkPacket.setSubChunksLength(16); - levelChunkPacket.setCachingEnabled(true); - levelChunkPacket.setChunkX(packet.getColumn().getX()); - levelChunkPacket.setChunkZ(packet.getColumn().getZ()); - levelChunkPacket.setData(buffer); - session.getUpstream().sendPacket(levelChunkPacket); - } catch (Exception ex) { - ex.printStackTrace(); - } - - GeyserLogger.DEFAULT.info("Sent chunk packet!"); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java new file mode 100644 index 000000000..3b77619f3 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaChunkDataTranslator.java @@ -0,0 +1,59 @@ +package org.geysermc.connector.network.translators.java.world; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket; +import com.nukkitx.network.VarInts; +import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.geysermc.api.Geyser; +import org.geysermc.connector.console.GeyserLogger; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.ChunkUtils; +import org.geysermc.connector.world.chunk.ChunkSection; + +public class JavaChunkDataTranslator extends PacketTranslator { + + @Override + public void translate(ServerChunkDataPacket packet, GeyserSession session) { + // Not sure if this is safe or not, however without this the client usually times out + Geyser.getConnector().getGeneralThreadPool().execute(() -> { + try { + ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn()); + ByteBuf byteBuf = Unpooled.buffer(32); + int count = 0; + ChunkSection[] sections = chunkData.sections; + for (int i = sections.length - 1; i >= 0; i--) { + if (sections[i].isEmpty()) + continue; + + count = i + 1; + break; + } + + for (int i = 0; i < count; i++) { + ChunkSection section = chunkData.sections[i]; + section.writeToNetwork(byteBuf); + } + + byteBuf.writeBytes(chunkData.biomes); // Biomes - 256 bytes + byteBuf.writeByte(0); // Border blocks - Edu edition only + VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now + + byte[] payload = new byte[byteBuf.writerIndex()]; + byteBuf.readBytes(payload); + + LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); + levelChunkPacket.setSubChunksLength(count); + levelChunkPacket.setCachingEnabled(false); + levelChunkPacket.setChunkX(packet.getColumn().getX()); + levelChunkPacket.setChunkZ(packet.getColumn().getZ()); + levelChunkPacket.setData(payload); + session.getUpstream().sendPacket(levelChunkPacket); + } catch (Exception ex) { + ex.printStackTrace(); + } + GeyserLogger.DEFAULT.info("Sent chunk packet!"); + }); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 196adce80..9e7ad391d 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -8,12 +8,8 @@ import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.item.BedrockItem; import org.geysermc.connector.world.chunk.ChunkSection; -import java.util.Arrays; - public class ChunkUtils { - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - public static ChunkData translateToBedrock(Column column) { ChunkData chunkData = new ChunkData(); chunkData.sections = new ChunkSection[16]; @@ -21,6 +17,7 @@ public class ChunkUtils { chunkData.sections[i] = new ChunkSection(); } + /* for (int y = 0; y < 256; y++) { int chunkY = y >> 4; @@ -37,55 +34,61 @@ public class ChunkUtils { BlockStorage storage = chunk.getBlocks(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { - BlockState block = storage.get(x, y & 0xF, z); + BlockState block = storage.get(x, chunkY, z); + if (block == null) + block = new BlockState(0); + BedrockItem bedrockBlock = TranslatorsInit.getItemTranslator().getBedrockBlock(block); ChunkSection section = chunkData.sections[chunkY]; - org.geysermc.connector.world.chunk.BlockStorage blockStorage = new org.geysermc.connector.world.chunk.BlockStorage(); - blockStorage.setFullBlock(ChunkSection.blockPosition(x, y, z), bedrockBlock.getId()); + //org.geysermc.connector.world.chunk.BlockStorage blockStorage = new org.geysermc.connector.world.chunk.BlockStorage(); + int runtimeId = GlobalBlockPalette.getOrCreateRuntimeId(bedrockBlock.getId(), bedrockBlock.getData()); + section.setFullBlock(x, y >> 4, z, 0, runtimeId << 2 | bedrockBlock.getData()); - section.getBlockStorageArray()[0] = blockStorage; - section.getBlockStorageArray()[1] = blockStorage; + //section.getBlockStorageArray()[0] = blockStorage; + //section.getBlockStorageArray()[1] = blockStorage; } } } + */ + + for (int chunkY = 0; chunkY < 16; chunkY++) { + Chunk chunk = null; + try { + chunk = column.getChunks()[chunkY]; + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (chunk == null || chunk.isEmpty()) + continue; + + BlockStorage storage = chunk.getBlocks(); + ChunkSection section = chunkData.sections[chunkY]; + + section.getBlockStorageArray()[0] = new org.geysermc.connector.world.chunk.BlockStorage(); + section.getBlockStorageArray()[1] = new org.geysermc.connector.world.chunk.BlockStorage(); + + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState block = storage.get(x, y, z); + BedrockItem bedrockBlock = TranslatorsInit.getItemTranslator().getBedrockBlock(block); + + section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), bedrockBlock.getId() << 4 | bedrockBlock.getData()); + } + } + } + } return chunkData; } public static final class ChunkData { public ChunkSection[] sections; - } - public static void putBytes(int count, byte[] buffer, byte[] bytes) { - if (bytes == null) { - return; - } - - int minCapacity = count + bytes.length; - if ((minCapacity) - buffer.length > 0) { - int oldCapacity = buffer.length; - int newCapacity = oldCapacity << 1; - - if (newCapacity - minCapacity < 0) { - newCapacity = minCapacity; - } - - if (newCapacity - MAX_ARRAY_SIZE > 0) { - newCapacity = hugeCapacity(minCapacity); - } - - buffer = Arrays.copyOf(buffer, newCapacity); - } - - System.arraycopy(bytes, 0, buffer, count, bytes.length); - } - - private static int hugeCapacity(int minCapacity) { - if (minCapacity < 0) { // overflow - throw new OutOfMemoryError(); - } - return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; + public byte[] biomes = new byte[256]; + public byte[] blockEntities = new byte[0]; } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java index d94d97f20..1447c5726 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java @@ -40,7 +40,7 @@ public class Toolbox { ByteBuf b = Unpooled.buffer(); VarInts.writeUnsignedInt(b, entries.size()); for (Map e : entries) { - GlobalBlockPalette.registerMapping((int) e.get("id")); + GlobalBlockPalette.registerMapping((int) e.get("id") << 4 | (int) e.get("data")); BedrockUtils.writeString(b, (String) e.get("name")); b.writeShortLE((int) e.get("data")); b.writeShortLE((int) e.get("id"));