forked from GeyserMC/Geyser
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 <suprememortal@users.noreply.github.com>
This commit is contained in:
parent
bd8a00b5eb
commit
383429d71b
5 changed files with 104 additions and 97 deletions
|
@ -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.JavaDisplayScoreboardTranslator;
|
||||||
import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator;
|
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.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.world.JavaNotifyClientTranslator;
|
||||||
import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
|
import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator;
|
||||||
import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
|
import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator;
|
||||||
|
@ -168,7 +168,7 @@ public class TranslatorsInit {
|
||||||
Registry.registerJava(ServerPlayerHealthPacket.class, new JavaPlayerHealthTranslator());
|
Registry.registerJava(ServerPlayerHealthPacket.class, new JavaPlayerHealthTranslator());
|
||||||
|
|
||||||
Registry.registerJava(ServerNotifyClientPacket.class, new JavaNotifyClientTranslator());
|
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(ServerEntityDestroyPacket.class, new JavaEntityDestroyTranslator());
|
||||||
Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator());
|
Registry.registerJava(ServerWindowItemsPacket.class, new JavaWindowItemsTranslator());
|
||||||
Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
|
Registry.registerJava(ServerOpenWindowPacket.class, new JavaOpenWindowTranslator());
|
||||||
|
|
|
@ -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<ServerChunkDataPacket> {
|
|
||||||
|
|
||||||
@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!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<ServerChunkDataPacket> {
|
||||||
|
|
||||||
|
@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!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,12 +8,8 @@ import org.geysermc.connector.network.translators.TranslatorsInit;
|
||||||
import org.geysermc.connector.network.translators.item.BedrockItem;
|
import org.geysermc.connector.network.translators.item.BedrockItem;
|
||||||
import org.geysermc.connector.world.chunk.ChunkSection;
|
import org.geysermc.connector.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class ChunkUtils {
|
public class ChunkUtils {
|
||||||
|
|
||||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
|
||||||
|
|
||||||
public static ChunkData translateToBedrock(Column column) {
|
public static ChunkData translateToBedrock(Column column) {
|
||||||
ChunkData chunkData = new ChunkData();
|
ChunkData chunkData = new ChunkData();
|
||||||
chunkData.sections = new ChunkSection[16];
|
chunkData.sections = new ChunkSection[16];
|
||||||
|
@ -21,6 +17,7 @@ public class ChunkUtils {
|
||||||
chunkData.sections[i] = new ChunkSection();
|
chunkData.sections[i] = new ChunkSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
for (int y = 0; y < 256; y++) {
|
for (int y = 0; y < 256; y++) {
|
||||||
int chunkY = y >> 4;
|
int chunkY = y >> 4;
|
||||||
|
|
||||||
|
@ -37,55 +34,61 @@ public class ChunkUtils {
|
||||||
BlockStorage storage = chunk.getBlocks();
|
BlockStorage storage = chunk.getBlocks();
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int x = 0; x < 16; x++) {
|
||||||
for (int z = 0; z < 16; z++) {
|
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);
|
BedrockItem bedrockBlock = TranslatorsInit.getItemTranslator().getBedrockBlock(block);
|
||||||
|
|
||||||
ChunkSection section = chunkData.sections[chunkY];
|
ChunkSection section = chunkData.sections[chunkY];
|
||||||
|
|
||||||
org.geysermc.connector.world.chunk.BlockStorage blockStorage = new org.geysermc.connector.world.chunk.BlockStorage();
|
//org.geysermc.connector.world.chunk.BlockStorage blockStorage = new org.geysermc.connector.world.chunk.BlockStorage();
|
||||||
blockStorage.setFullBlock(ChunkSection.blockPosition(x, y, z), bedrockBlock.getId());
|
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()[0] = blockStorage;
|
||||||
section.getBlockStorageArray()[1] = 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;
|
return chunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ChunkData {
|
public static final class ChunkData {
|
||||||
public ChunkSection[] sections;
|
public ChunkSection[] sections;
|
||||||
}
|
|
||||||
|
|
||||||
public static void putBytes(int count, byte[] buffer, byte[] bytes) {
|
public byte[] biomes = new byte[256];
|
||||||
if (bytes == null) {
|
public byte[] blockEntities = new byte[0];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class Toolbox {
|
||||||
ByteBuf b = Unpooled.buffer();
|
ByteBuf b = Unpooled.buffer();
|
||||||
VarInts.writeUnsignedInt(b, entries.size());
|
VarInts.writeUnsignedInt(b, entries.size());
|
||||||
for (Map<String, Object> e : entries) {
|
for (Map<String, Object> 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"));
|
BedrockUtils.writeString(b, (String) e.get("name"));
|
||||||
b.writeShortLE((int) e.get("data"));
|
b.writeShortLE((int) e.get("data"));
|
||||||
b.writeShortLE((int) e.get("id"));
|
b.writeShortLE((int) e.get("id"));
|
||||||
|
|
Loading…
Reference in a new issue