Properly implement block entity IDs and add tests

This commit is contained in:
Camotoy 2021-11-14 12:05:39 -05:00
parent 8b7386a46a
commit ff76494a65
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
11 changed files with 144 additions and 41 deletions

View file

@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockFace;
import com.github.steveice10.mc.protocol.data.game.level.block.CommandBlockMode;
import com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror;
import com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.ChestValueType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.EndGatewayValueType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.GenericBlockValueType;
@ -597,21 +596,6 @@ public class MagicValues {
register(AnvilProperty.MAXIMUM_COST, 0);
register(BlockEntityType.MOB_SPAWNER, 1);
register(BlockEntityType.COMMAND_BLOCK, 2);
register(BlockEntityType.BEACON, 3);
register(BlockEntityType.SKULL, 4);
register(BlockEntityType.CONDUIT, 5);
register(BlockEntityType.BANNER, 6);
register(BlockEntityType.STRUCTURE_BLOCK, 7);
register(BlockEntityType.END_GATEWAY, 8);
register(BlockEntityType.SIGN, 9);
register(BlockEntityType.SHULKER_BOX, 10);
register(BlockEntityType.BED, 11);
register(BlockEntityType.JIGSAW_BLOCK, 12);
register(BlockEntityType.CAMPFIRE, 13);
register(BlockEntityType.BEEHIVE, 14);
register(GameEvent.INVALID_BED, 0);
register(GameEvent.STOP_RAIN, 1);
register(GameEvent.START_RAIN, 2);

View file

@ -2,18 +2,14 @@ package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.*;
import java.io.IOException;
@Data
@Setter(AccessLevel.NONE)
@AllArgsConstructor
@EqualsAndHashCode
public class ChunkSection {
private static final int MAX_PALETTE_BITS_PER_ENTRY = 8;
private static final int MAX_BIOME_BITS_PER_ENTRY = 2;
@ -26,7 +22,7 @@ public class ChunkSection {
private @NonNull DataPalette biomeData;
public ChunkSection() {
this(0, DataPalette.createEmpty(MAX_PALETTE_BITS_PER_ENTRY, DataPalette.CHUNK_SIZE), DataPalette.createEmpty(MAX_BIOME_BITS_PER_ENTRY, DataPalette.BIOME_SIZE));
this(0, DataPalette.createForChunk(), DataPalette.createForBiome());
}
public static ChunkSection read(NetInput in) throws IOException {

View file

@ -11,6 +11,7 @@ import java.io.IOException;
@Setter
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public class DataPalette {
static final int BIOME_SIZE = 64;
static final int CHUNK_SIZE = 4096;
@ -29,7 +30,7 @@ public class DataPalette {
}
public static DataPalette createForBiome() {
return createEmpty(MAX_BIOME_BITS_PER_ENTRY, CHUNK_SIZE);
return createEmpty(MAX_BIOME_BITS_PER_ENTRY, BIOME_SIZE);
}
public static DataPalette createEmpty(int maxBitsForType, int maxStorageSize) {
@ -52,14 +53,15 @@ public class DataPalette {
}
public static void write(NetOutput out, DataPalette palette) throws IOException {
out.writeByte(palette.storage.getBitsPerEntry());
if (palette.palette instanceof SingletonPalette) {
out.writeByte(0); // Bits per entry
out.writeVarInt(palette.palette.idToState(0));
out.writeVarInt(0); // Data length
return;
}
out.writeByte(palette.storage.getBitsPerEntry());
if (!(palette.palette instanceof GlobalPalette)) {
int paletteLength = palette.palette.size();
out.writeVarInt(paletteLength);

View file

@ -12,6 +12,6 @@ public class BlockEntityInfo {
private final int x;
private final int y;
private final int z;
private final int id;
private final BlockEntityType type;
private final @Nullable CompoundTag nbt;
}

View file

@ -1,18 +1,67 @@
package com.github.steveice10.mc.protocol.data.game.level.block;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
import javax.annotation.Nonnull;
import java.io.IOException;
public enum BlockEntityType {
FURNACE,
CHEST,
TRAPPED_CHEST,
ENDER_CHEST,
JUKEBOX,
DISPENSER,
DROPPER,
SIGN,
MOB_SPAWNER,
COMMAND_BLOCK,
PISTON,
BREWING_STAND,
ENCHANTING_TABLE,
END_PORTAL,
BEACON,
SKULL,
CONDUIT,
DAYLIGHT_DETECTOR,
HOPPER,
COMPARATOR,
BANNER,
STRUCTURE_BLOCK,
END_GATEWAY,
SIGN,
COMMAND_BLOCK,
SHULKER_BOX,
BED,
JIGSAW_BLOCK,
CONDUIT,
BARREL,
SMOKER,
BLAST_FURNACE,
LECTERN,
BELL,
JIGSAW,
CAMPFIRE,
BEEHIVE;
BEEHIVE,
SCULK_SENSOR;
private static final IntObjectMap<BlockEntityType> NETWORK_TO_BLOCK_ENTITY = new IntObjectHashMap<>();
static {
for (BlockEntityType type : values()) {
NETWORK_TO_BLOCK_ENTITY.put(type.ordinal(), type);
}
}
public static @Nonnull BlockEntityType read(NetInput in) throws IOException {
int networkId = in.readVarInt();
BlockEntityType type = NETWORK_TO_BLOCK_ENTITY.get(networkId);
if (type == null) {
throw new IllegalStateException("Cannot find type for network ID " + networkId);
}
return type;
}
public static void write(NetOutput out, @Nonnull BlockEntityType type) throws IOException {
out.writeVarInt(type.ordinal());
}
}

View file

@ -1,6 +1,5 @@
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.MagicValues;
import com.github.steveice10.mc.protocol.data.game.NBT;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
@ -25,14 +24,14 @@ public class ClientboundBlockEntityDataPacket implements Packet {
public ClientboundBlockEntityDataPacket(NetInput in) throws IOException {
this.position = Position.read(in);
this.type = MagicValues.key(BlockEntityType.class, in.readVarInt());
this.type = BlockEntityType.read(in);
this.nbt = NBT.read(in);
}
@Override
public void write(NetOutput out) throws IOException {
Position.write(out, this.position);
out.writeVarInt(MagicValues.value(Integer.class, this.type));
BlockEntityType.write(out, this.type);
NBT.write(out, this.nbt);
}
}

View file

@ -3,6 +3,7 @@ package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.game.NBT;
import com.github.steveice10.mc.protocol.data.game.level.LightUpdateData;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
@ -37,7 +38,7 @@ public class ClientboundLevelChunkWithLightPacket implements Packet {
int blockEntityX = (xz >> 4) & 15;
int blockEntityZ = xz & 15;
int blockEntityY = in.readShort();
int type = in.readVarInt();
BlockEntityType type = BlockEntityType.read(in);
CompoundTag tag = NBT.read(in);
this.blockEntities[i] = new BlockEntityInfo(blockEntityX, blockEntityY, blockEntityZ, type, tag);
}
@ -57,7 +58,7 @@ public class ClientboundLevelChunkWithLightPacket implements Packet {
for (BlockEntityInfo blockEntity : this.blockEntities) {
out.writeByte(((blockEntity.getX() & 15) << 4) | blockEntity.getZ() & 15);
out.writeShort(blockEntity.getY());
out.writeVarInt(blockEntity.getId());
BlockEntityType.write(out, blockEntity.getType());
NBT.write(out, blockEntity.getNbt());
}

View file

@ -0,0 +1,54 @@
package com.github.steveice10.mc.protocol.data;
import com.github.steveice10.mc.protocol.data.game.chunk.ChunkSection;
import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette;
import com.github.steveice10.packetlib.io.stream.StreamNetInput;
import com.github.steveice10.packetlib.io.stream.StreamNetOutput;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ChunkTest {
private final List<ChunkSection> chunkSectionsToTest = new ArrayList<>();
@Before
public void setup() {
chunkSectionsToTest.add(new ChunkSection());
ChunkSection section = new ChunkSection();
section.setBlock(0, 0, 0, 10);
chunkSectionsToTest.add(section);
SingletonPalette singletonPalette = new SingletonPalette(20);
DataPalette dataPalette = new DataPalette(singletonPalette, null, 8, 4096);
DataPalette biomePalette = new DataPalette(singletonPalette, null, 2, 64);
section = new ChunkSection(4096, dataPalette, biomePalette);
chunkSectionsToTest.add(section);
}
@Test
public void testChunkSectionEncoding() throws IOException {
for (ChunkSection section : chunkSectionsToTest) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(stream);
ChunkSection.write(out, section);
StreamNetInput in = new StreamNetInput(new ByteArrayInputStream(stream.toByteArray()));
ChunkSection decoded;
try {
decoded = ChunkSection.read(in);
} catch (Exception e) {
System.out.println(section);
e.printStackTrace();
throw e;
}
Assert.assertEquals("Decoded packet does not match original: " + section + " vs " + decoded, section, decoded);
}
}
}

View file

@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockFace;
import com.github.steveice10.mc.protocol.data.game.level.block.CommandBlockMode;
import com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror;
import com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.ChestValueType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.EndGatewayValueType;
import com.github.steveice10.mc.protocol.data.game.level.block.value.GenericBlockValueType;
@ -147,7 +146,6 @@ public class MagicValuesTest {
this.register(EnchantmentTableProperty.class, Integer.class);
this.register(FurnaceProperty.class, Integer.class);
this.register(AnvilProperty.class, Integer.class);
this.register(BlockEntityType.class, Integer.class);
this.register(GameEvent.class, Integer.class);
this.register(CommandBlockMode.class, Integer.class);
this.register(UpdateStructureBlockAction.class, Integer.class);

View file

@ -1,14 +1,33 @@
package com.github.steveice10.mc.protocol.data;
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.packetlib.io.stream.StreamNetInput;
import com.github.steveice10.packetlib.io.stream.StreamNetOutput;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Miscellaneous tests for reading and writing classes to/from the network
*/
public class NetworkDataTests {
@Test
public void testBlockEntities() throws IOException {
for (BlockEntityType type : BlockEntityType.values()) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(stream);
BlockEntityType.write(out, type);
StreamNetInput in = new StreamNetInput(new ByteArrayInputStream(stream.toByteArray()));
Assert.assertEquals(type, BlockEntityType.read(in));
}
}
@Test
public void testEffects() {
for (Effect effect : Effect.VALUES) {

View file

@ -2,6 +2,7 @@ package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.game.level.LightUpdateData;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.mc.protocol.packet.PacketTest;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.junit.Before;
@ -19,8 +20,8 @@ public class ClientboundLevelChunkWithLightPacketTest extends PacketTest {
new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), Collections.emptyList(), Collections.emptyList(), false)
),
new ClientboundLevelChunkWithLightPacket(1, 1,
new byte[256], new CompoundTag("HeightMaps"), new BlockEntityInfo[]{
new BlockEntityInfo(1, 0, 1, 0, null)
new byte[256], new CompoundTag("HeightMaps"), new BlockEntityInfo[] {
new BlockEntityInfo(1, 0, 1, BlockEntityType.CHEST, null)
}, new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), Collections.emptyList(), Collections.emptyList(), true)
)
);