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.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());
|
||||
|
|
|
@ -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.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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class Toolbox {
|
|||
ByteBuf b = Unpooled.buffer();
|
||||
VarInts.writeUnsignedInt(b, entries.size());
|
||||
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"));
|
||||
b.writeShortLE((int) e.get("data"));
|
||||
b.writeShortLE((int) e.get("id"));
|
||||
|
|
Loading…
Reference in a new issue