Initial update to 1.18 protocol

This commit is contained in:
Camotoy 2021-11-13 23:48:38 -05:00
parent b3fb245b5b
commit d527164d4c
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
20 changed files with 481 additions and 345 deletions

View file

@ -5,7 +5,7 @@
<groupId>com.github.steveice10</groupId>
<artifactId>mcprotocollib</artifactId>
<version>1.17.1-3-SNAPSHOT</version>
<version>1.18-pre-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MCProtocolLib</name>

View file

@ -12,12 +12,12 @@ public final class MinecraftConstants {
/**
* Current supported game version.
*/
public static final String GAME_VERSION = "1.17.1";
public static final String GAME_VERSION = "1.18-pre1";
/**
* Current supported protocol version.
*/
public static final int PROTOCOL_VERSION = 756;
public static final int PROTOCOL_VERSION = (1 << 30) | 49;
// General Key Constants

View file

@ -344,7 +344,7 @@ public class MinecraftProtocol extends PacketProtocol {
clientboundPackets.register(0x1F, ClientboundHorseScreenOpenPacket.class, ClientboundHorseScreenOpenPacket::new);
clientboundPackets.register(0x20, ClientboundInitializeBorderPacket.class, ClientboundInitializeBorderPacket::new);
clientboundPackets.register(0x21, ClientboundKeepAlivePacket.class, ClientboundKeepAlivePacket::new);
clientboundPackets.register(0x22, ClientboundLevelChunkPacket.class, ClientboundLevelChunkPacket::new);
clientboundPackets.register(0x22, ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkWithLightPacket::new);
clientboundPackets.register(0x23, ClientboundLevelEventPacket.class, ClientboundLevelEventPacket::new);
clientboundPackets.register(0x24, ClientboundLevelParticlesPacket.class, ClientboundLevelParticlesPacket::new);
clientboundPackets.register(0x25, ClientboundLightUpdatePacket.class, ClientboundLightUpdatePacket::new);
@ -397,22 +397,23 @@ public class MinecraftProtocol extends PacketProtocol {
clientboundPackets.register(0x54, ClientboundSetPassengersPacket.class, ClientboundSetPassengersPacket::new);
clientboundPackets.register(0x55, ClientboundSetPlayerTeamPacket.class, ClientboundSetPlayerTeamPacket::new);
clientboundPackets.register(0x56, ClientboundSetScorePacket.class, ClientboundSetScorePacket::new);
clientboundPackets.register(0x57, ClientboundSetSubtitleTextPacket.class, ClientboundSetSubtitleTextPacket::new);
clientboundPackets.register(0x58, ClientboundSetTimePacket.class, ClientboundSetTimePacket::new);
clientboundPackets.register(0x59, ClientboundSetTitleTextPacket.class, ClientboundSetTitleTextPacket::new);
clientboundPackets.register(0x5A, ClientboundSetTitlesAnimationPacket.class, ClientboundSetTitlesAnimationPacket::new);
clientboundPackets.register(0x5B, ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new);
clientboundPackets.register(0x5C, ClientboundSoundPacket.class, ClientboundSoundPacket::new);
clientboundPackets.register(0x5D, ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new);
clientboundPackets.register(0x5E, ClientboundTabListPacket.class, ClientboundTabListPacket::new);
clientboundPackets.register(0x5F, ClientboundTagQueryPacket.class, ClientboundTagQueryPacket::new);
clientboundPackets.register(0x60, ClientboundTakeItemEntityPacket.class, ClientboundTakeItemEntityPacket::new);
clientboundPackets.register(0x61, ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::new);
clientboundPackets.register(0x62, ClientboundUpdateAdvancementsPacket.class, ClientboundUpdateAdvancementsPacket::new);
clientboundPackets.register(0x63, ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::new);
clientboundPackets.register(0x64, ClientboundUpdateMobEffectPacket.class, ClientboundUpdateMobEffectPacket::new);
clientboundPackets.register(0x65, ClientboundUpdateRecipesPacket.class, ClientboundUpdateRecipesPacket::new);
clientboundPackets.register(0x66, ClientboundUpdateTagsPacket.class, ClientboundUpdateTagsPacket::new);
clientboundPackets.register(0x57, ClientboundSetSimulationDistancePacket.class, ClientboundSetSimulationDistancePacket::new);
clientboundPackets.register(0x58, ClientboundSetSubtitleTextPacket.class, ClientboundSetSubtitleTextPacket::new);
clientboundPackets.register(0x59, ClientboundSetTimePacket.class, ClientboundSetTimePacket::new);
clientboundPackets.register(0x5A, ClientboundSetTitleTextPacket.class, ClientboundSetTitleTextPacket::new);
clientboundPackets.register(0x5B, ClientboundSetTitlesAnimationPacket.class, ClientboundSetTitlesAnimationPacket::new);
clientboundPackets.register(0x5C, ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new);
clientboundPackets.register(0x5D, ClientboundSoundPacket.class, ClientboundSoundPacket::new);
clientboundPackets.register(0x5E, ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new);
clientboundPackets.register(0x5F, ClientboundTabListPacket.class, ClientboundTabListPacket::new);
clientboundPackets.register(0x60, ClientboundTagQueryPacket.class, ClientboundTagQueryPacket::new);
clientboundPackets.register(0x61, ClientboundTakeItemEntityPacket.class, ClientboundTakeItemEntityPacket::new);
clientboundPackets.register(0x62, ClientboundTeleportEntityPacket.class, ClientboundTeleportEntityPacket::new);
clientboundPackets.register(0x63, ClientboundUpdateAdvancementsPacket.class, ClientboundUpdateAdvancementsPacket::new);
clientboundPackets.register(0x64, ClientboundUpdateAttributesPacket.class, ClientboundUpdateAttributesPacket::new);
clientboundPackets.register(0x65, ClientboundUpdateMobEffectPacket.class, ClientboundUpdateMobEffectPacket::new);
clientboundPackets.register(0x66, ClientboundUpdateRecipesPacket.class, ClientboundUpdateRecipesPacket::new);
clientboundPackets.register(0x67, ClientboundUpdateTagsPacket.class, ClientboundUpdateTagsPacket::new);
serverboundPackets.register(0x00, ServerboundAcceptTeleportationPacket.class, ServerboundAcceptTeleportationPacket::new);
serverboundPackets.register(0x01, ServerboundBlockEntityTagQuery.class, ServerboundBlockEntityTagQuery::new);

View file

@ -1,16 +1,8 @@
package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.ListPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.MapPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette;
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.NonNull;
import lombok.Setter;
import lombok.*;
import java.io.IOException;
@ -18,117 +10,48 @@ import java.io.IOException;
@Setter(AccessLevel.NONE)
@AllArgsConstructor
public class Chunk {
private static final int CHUNK_SIZE = 4096;
private static final int MIN_PALETTE_BITS_PER_ENTRY = 4;
private static final int MAX_PALETTE_BITS_PER_ENTRY = 8;
private static final int GLOBAL_PALETTE_BITS_PER_ENTRY = 14;
private static final int MAX_BIOME_BITS_PER_ENTRY = 2;
private static final int AIR = 0;
private int blockCount;
private @NonNull Palette palette;
private @NonNull BitStorage storage;
private @NonNull DataPalette chunkData;
@Getter
private @NonNull DataPalette biomeData;
public Chunk() {
this(0, new ListPalette(MIN_PALETTE_BITS_PER_ENTRY), new BitStorage(MIN_PALETTE_BITS_PER_ENTRY, CHUNK_SIZE));
this(0, DataPalette.createEmpty(MAX_PALETTE_BITS_PER_ENTRY, DataPalette.CHUNK_SIZE), DataPalette.createEmpty(MAX_BIOME_BITS_PER_ENTRY, DataPalette.BIOME_SIZE));
}
public static Chunk read(NetInput in) throws IOException {
int blockCount = in.readShort();
int bitsPerEntry = in.readUnsignedByte();
Palette palette = readPalette(bitsPerEntry, in);
BitStorage storage = new BitStorage(bitsPerEntry, CHUNK_SIZE, in.readLongs(in.readVarInt()));
return new Chunk(blockCount, palette, storage);
DataPalette chunkPalette = DataPalette.read(in, MAX_PALETTE_BITS_PER_ENTRY, DataPalette.CHUNK_SIZE);
DataPalette biomePalette = DataPalette.read(in, MAX_BIOME_BITS_PER_ENTRY, DataPalette.BIOME_SIZE);
return new Chunk(blockCount, chunkPalette, biomePalette);
}
public static void write(NetOutput out, Chunk chunk) throws IOException {
out.writeShort(chunk.blockCount);
out.writeByte(chunk.storage.getBitsPerEntry());
if (!(chunk.palette instanceof GlobalPalette)) {
int paletteLength = chunk.palette.size();
out.writeVarInt(paletteLength);
for (int i = 0; i < paletteLength; i++) {
out.writeVarInt(chunk.palette.idToState(i));
}
}
long[] data = chunk.storage.getData();
out.writeVarInt(data.length);
out.writeLongs(data);
DataPalette.write(out, chunk.chunkData);
DataPalette.write(out, chunk.biomeData);
}
public int get(int x, int y, int z) {
int id = this.storage.get(index(x, y, z));
return this.palette.idToState(id);
public int getBlock(int x, int y, int z) {
return this.chunkData.get(x, y, z);
}
public void set(int x, int y, int z, @NonNull int state) {
int id = this.palette.stateToId(state);
if (id == -1) {
this.resizePalette();
id = this.palette.stateToId(state);
}
int index = index(x, y, z);
int curr = this.storage.get(index);
public void setBlock(int x, int y, int z, int state) {
int curr = this.chunkData.set(x, y, z, state);
if (state != AIR && curr == AIR) {
this.blockCount++;
} else if (state == AIR && curr != AIR) {
this.blockCount--;
}
this.storage.set(index, id);
}
public boolean isEmpty() {
public boolean isBlockCountEmpty() {
return this.blockCount == 0;
}
private int sanitizeBitsPerEntry(int bitsPerEntry) {
if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
return Math.max(MIN_PALETTE_BITS_PER_ENTRY, bitsPerEntry);
} else {
return GLOBAL_PALETTE_BITS_PER_ENTRY;
}
}
private void resizePalette() {
Palette oldPalette = this.palette;
BitStorage oldData = this.storage;
int bitsPerEntry = sanitizeBitsPerEntry(oldData.getBitsPerEntry() + 1);
this.palette = createPalette(bitsPerEntry);
this.storage = new BitStorage(bitsPerEntry, CHUNK_SIZE);
for (int i = 0; i < CHUNK_SIZE; i++) {
this.storage.set(i, this.palette.stateToId(oldPalette.idToState(oldData.get(i))));
}
}
private static Palette createPalette(int bitsPerEntry) {
if (bitsPerEntry <= MIN_PALETTE_BITS_PER_ENTRY) {
return new ListPalette(bitsPerEntry);
} else if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
return new MapPalette(bitsPerEntry);
} else {
return new GlobalPalette();
}
}
private static Palette readPalette(int bitsPerEntry, NetInput in) throws IOException {
if (bitsPerEntry <= MIN_PALETTE_BITS_PER_ENTRY) {
return new ListPalette(bitsPerEntry, in);
} else if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
return new MapPalette(bitsPerEntry, in);
} else {
return new GlobalPalette();
}
}
private static int index(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
}

View file

@ -1,34 +0,0 @@
package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import lombok.Data;
import lombok.NonNull;
import java.util.Arrays;
@Data
public class Column {
private final int x;
private final int z;
private final @NonNull Chunk[] chunks;
private final @NonNull CompoundTag[] tileEntities;
private final @NonNull CompoundTag heightMaps;
private final @NonNull int[] biomeData;
/**
* @deprecated Non-full chunks no longer exist since 1.17.
*/
@Deprecated
public Column(int x, int z, @NonNull Chunk[] chunks, @NonNull CompoundTag[] tileEntities, @NonNull CompoundTag heightMaps) {
this(x, z, chunks, tileEntities, heightMaps, new int[1024]);
}
public Column(int x, int z, @NonNull Chunk[] chunks, @NonNull CompoundTag[] tileEntities, @NonNull CompoundTag heightMaps, @NonNull int[] biomeData) {
this.x = x;
this.z = z;
this.chunks = Arrays.copyOf(chunks, chunks.length);
this.biomeData = biomeData != null ? Arrays.copyOf(biomeData, biomeData.length) : null;
this.tileEntities = tileEntities != null ? tileEntities : new CompoundTag[0];
this.heightMaps = heightMaps;
}
}

View file

@ -0,0 +1,157 @@
package com.github.steveice10.mc.protocol.data.game.chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.*;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import lombok.*;
import java.io.IOException;
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode
public class DataPalette {
static final int BIOME_SIZE = 64;
static final int CHUNK_SIZE = 4096;
private static final int MAX_BIOME_BITS_PER_ENTRY = 2;
private static final int MIN_PALETTE_BITS_PER_ENTRY = 4;
private static final int MAX_PALETTE_BITS_PER_ENTRY = 8;
private static final int GLOBAL_PALETTE_BITS_PER_ENTRY = 14;
private @NonNull Palette palette;
private BitStorage storage;
private final int maxBitsForType;
private final int maxStorageSize;
public static DataPalette createForChunk() {
return createEmpty(MAX_PALETTE_BITS_PER_ENTRY, CHUNK_SIZE);
}
public static DataPalette createForBiome() {
return createEmpty(MAX_BIOME_BITS_PER_ENTRY, CHUNK_SIZE);
}
public static DataPalette createEmpty(int maxBitsForType, int maxStorageSize) {
return new DataPalette(new ListPalette(MIN_PALETTE_BITS_PER_ENTRY),
new BitStorage(MIN_PALETTE_BITS_PER_ENTRY, maxBitsForType), maxBitsForType, maxStorageSize);
}
public static DataPalette read(NetInput in, int maxBitsForType, int maxSizeForType) throws IOException {
int bitsPerEntry = in.readByte();
Palette palette = readPalette(bitsPerEntry, maxBitsForType, in);
BitStorage storage;
if (!(palette instanceof SingletonPalette)) {
storage = new BitStorage(bitsPerEntry, maxSizeForType, in.readLongs(in.readVarInt()));
} else {
in.readVarInt();
storage = null;
}
return new DataPalette(palette, storage, maxBitsForType, maxSizeForType);
}
public static void write(NetOutput out, DataPalette palette) throws IOException {
out.writeByte(palette.storage.getBitsPerEntry());
if (palette.palette instanceof SingletonPalette) {
out.writeVarInt(palette.palette.idToState(0));
out.writeVarInt(0); // Data length
return;
}
if (!(palette.palette instanceof GlobalPalette)) {
int paletteLength = palette.palette.size();
out.writeVarInt(paletteLength);
for (int i = 0; i < paletteLength; i++) {
out.writeVarInt(palette.palette.idToState(i));
}
}
long[] data = palette.storage.getData();
out.writeVarInt(data.length);
out.writeLongs(data);
}
public int get(int x, int y, int z) {
if (storage != null) {
int id = this.storage.get(index(x, y, z));
return this.palette.idToState(id);
} else {
return this.palette.idToState(0);
}
}
/**
* @return the old value present in the storage.
*/
public int set(int x, int y, int z, int state) {
int id = this.palette.stateToId(state);
if (id == -1) {
resize();
id = this.palette.stateToId(state);
}
int index = index(x, y, z);
int curr = this.storage.get(index);
this.storage.set(index, id);
return curr;
}
private static Palette readPalette(int bitsPerEntry, int maxBitsPerEntry, NetInput in) throws IOException {
if (bitsPerEntry > maxBitsPerEntry) {
return new GlobalPalette();
}
if (bitsPerEntry == 0) {
return new SingletonPalette(in);
}
if (bitsPerEntry <= MIN_PALETTE_BITS_PER_ENTRY) {
return new ListPalette(bitsPerEntry, in);
} else {
return new MapPalette(bitsPerEntry, in);
}
}
private int sanitizeBitsPerEntry(int bitsPerEntry) {
if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
return Math.max(MIN_PALETTE_BITS_PER_ENTRY, bitsPerEntry);
} else {
return GLOBAL_PALETTE_BITS_PER_ENTRY;
}
}
private void resize() {
Palette oldPalette = this.palette;
BitStorage oldData = this.storage;
int bitsPerEntry = sanitizeBitsPerEntry(oldPalette instanceof SingletonPalette ? 1 : oldData.getBitsPerEntry() + 1);
this.palette = createPalette(bitsPerEntry);
this.storage = new BitStorage(bitsPerEntry, maxStorageSize);
if (oldPalette instanceof SingletonPalette) {
for (int i = 0; i < maxStorageSize; i++) {
// TODO necessary?
this.storage.set(i, 0);
}
} else {
for (int i = 0; i < maxStorageSize; i++) {
this.storage.set(i, this.palette.stateToId(oldPalette.idToState(oldData.get(i))));
}
}
}
private static Palette createPalette(int bitsPerEntry) {
if (bitsPerEntry <= MIN_PALETTE_BITS_PER_ENTRY) {
return new ListPalette(bitsPerEntry);
} else if (bitsPerEntry <= MAX_PALETTE_BITS_PER_ENTRY) {
return new MapPalette(bitsPerEntry);
} else {
return new GlobalPalette();
}
}
private static int index(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
}

View file

@ -0,0 +1,43 @@
package com.github.steveice10.mc.protocol.data.game.chunk.palette;
import com.github.steveice10.packetlib.io.NetInput;
import lombok.EqualsAndHashCode;
import java.io.IOException;
/**
* A palette containing one state.
*/
@EqualsAndHashCode
public class SingletonPalette implements Palette {
private final int state;
public SingletonPalette(int state) {
this.state = state;
}
public SingletonPalette(NetInput in) throws IOException {
this.state = in.readVarInt();
}
@Override
public int size() {
return 1;
}
@Override
public int stateToId(int state) {
if (this.state == state) {
return 0;
}
return -1;
}
@Override
public int idToState(int id) {
if (id == 0) {
return this.state;
}
return 0;
}
}

View file

@ -0,0 +1,82 @@
package com.github.steveice10.mc.protocol.data.game.level;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
@Data
@AllArgsConstructor
public class LightUpdateData {
private final @NonNull BitSet skyYMask;
private final @NonNull BitSet blockYMask;
private final @NonNull BitSet emptySkyYMask;
private final @NonNull BitSet emptyBlockYMask;
private final @NonNull List<byte[]> skyUpdates;
private final @NonNull List<byte[]> blockUpdates;
private final boolean trustEdges;
public static LightUpdateData read(NetInput in) throws IOException {
return new LightUpdateData(in);
}
private LightUpdateData(NetInput in) throws IOException {
this.trustEdges = in.readBoolean();
this.skyYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.blockYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.emptySkyYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.emptyBlockYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
int skyUpdateSize = in.readVarInt();
skyUpdates = new ArrayList<>(skyUpdateSize);
for (int i = 0; i < skyUpdateSize; i++) {
skyUpdates.add(in.readBytes(in.readVarInt()));
}
int blockUpdateSize = in.readVarInt();
blockUpdates = new ArrayList<>(blockUpdateSize);
for (int i = 0; i < blockUpdateSize; i++) {
blockUpdates.add(in.readBytes(in.readVarInt()));
}
}
public static void write(NetOutput out, LightUpdateData data) throws IOException {
data.write(out);
}
private void write(NetOutput out) throws IOException {
out.writeBoolean(this.trustEdges);
writeBitSet(out, this.skyYMask);
writeBitSet(out, this.blockYMask);
writeBitSet(out, this.emptySkyYMask);
writeBitSet(out, this.emptyBlockYMask);
out.writeVarInt(this.skyUpdates.size());
for (byte[] array : this.skyUpdates) {
out.writeVarInt(array.length);
out.writeBytes(array);
}
out.writeVarInt(this.blockUpdates.size());
for (byte[] array : this.blockUpdates) {
out.writeVarInt(array.length);
out.writeBytes(array);
}
}
private void writeBitSet(NetOutput out, BitSet bitSet) throws IOException {
long[] array = bitSet.toLongArray();
out.writeVarInt(array.length);
for (long content : array) {
out.writeLong(content);
}
}
}

View file

@ -0,0 +1,17 @@
package com.github.steveice10.mc.protocol.data.game.level.block;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.annotation.Nullable;
@Data
@AllArgsConstructor
public class BlockEntityInfo {
private final int x;
private final int y;
private final int z;
private final int id;
private final @Nullable CompoundTag nbt;
}

View file

@ -32,6 +32,7 @@ public class ClientboundLoginPacket implements Packet {
private final long hashedSeed;
private final int maxPlayers;
private final int viewDistance;
private final int simulationDistance;
private final boolean reducedDebugInfo;
private final boolean enableRespawnScreen;
private final boolean debug;
@ -55,6 +56,7 @@ public class ClientboundLoginPacket implements Packet {
this.hashedSeed = in.readLong();
this.maxPlayers = in.readVarInt();
this.viewDistance = in.readVarInt();
this.simulationDistance = in.readVarInt();
this.reducedDebugInfo = in.readBoolean();
this.enableRespawnScreen = in.readBoolean();
this.debug = in.readBoolean();
@ -80,6 +82,7 @@ public class ClientboundLoginPacket implements Packet {
out.writeLong(this.hashedSeed);
out.writeVarInt(this.maxPlayers);
out.writeVarInt(this.viewDistance);
out.writeVarInt(this.simulationDistance);
out.writeBoolean(this.reducedDebugInfo);
out.writeBoolean(this.enableRespawnScreen);
out.writeBoolean(this.debug);

View file

@ -25,14 +25,14 @@ public class ClientboundBlockEntityDataPacket implements Packet {
public ClientboundBlockEntityDataPacket(NetInput in) throws IOException {
this.position = Position.read(in);
this.type = MagicValues.key(UpdatedTileType.class, in.readUnsignedByte());
this.type = MagicValues.key(UpdatedTileType.class, in.readVarInt());
this.nbt = NBT.read(in);
}
@Override
public void write(NetOutput out) throws IOException {
Position.write(out, this.position);
out.writeByte(MagicValues.value(Integer.class, this.type));
out.writeVarInt(MagicValues.value(Integer.class, this.type));
NBT.write(out, this.nbt);
}
}

View file

@ -1,89 +0,0 @@
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.chunk.Chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import com.github.steveice10.packetlib.io.stream.StreamNetInput;
import com.github.steveice10.packetlib.io.stream.StreamNetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import lombok.With;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.BitSet;
@Data
@With
@AllArgsConstructor
public class ClientboundLevelChunkPacket implements Packet {
private final @NonNull Column column;
public ClientboundLevelChunkPacket(NetInput in) throws IOException {
int x = in.readInt();
int z = in.readInt();
BitSet chunkMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
CompoundTag heightMaps = NBT.read(in);
int[] biomeData = new int[in.readVarInt()];
for (int index = 0; index < biomeData.length; index++) {
biomeData[index] = in.readVarInt();
}
byte[] data = in.readBytes(in.readVarInt());
NetInput dataIn = new StreamNetInput(new ByteArrayInputStream(data));
Chunk[] chunks = new Chunk[chunkMask.size()];
for (int index = 0; index < chunks.length; index++) {
if (chunkMask.get(index)) {
chunks[index] = Chunk.read(dataIn);
}
}
CompoundTag[] tileEntities = new CompoundTag[in.readVarInt()];
for (int i = 0; i < tileEntities.length; i++) {
tileEntities[i] = NBT.read(in);
}
this.column = new Column(x, z, chunks, tileEntities, heightMaps, biomeData);
}
@Override
public void write(NetOutput out) throws IOException {
ByteArrayOutputStream dataBytes = new ByteArrayOutputStream();
NetOutput dataOut = new StreamNetOutput(dataBytes);
BitSet bitSet = new BitSet();
Chunk[] chunks = this.column.getChunks();
for (int index = 0; index < chunks.length; index++) {
Chunk chunk = chunks[index];
if (chunk != null && !chunk.isEmpty()) {
bitSet.set(index);
Chunk.write(dataOut, chunk);
}
}
out.writeInt(this.column.getX());
out.writeInt(this.column.getZ());
long[] longArray = bitSet.toLongArray();
out.writeVarInt(longArray.length);
for (long content : longArray) {
out.writeLong(content);
}
NBT.write(out, this.column.getHeightMaps());
out.writeVarInt(this.column.getBiomeData().length);
for (int biomeData : this.column.getBiomeData()) {
out.writeVarInt(biomeData);
}
out.writeVarInt(dataBytes.size());
out.writeBytes(dataBytes.toByteArray(), dataBytes.size());
out.writeVarInt(this.column.getTileEntities().length);
for (CompoundTag tag : this.column.getTileEntities()) {
NBT.write(out, tag);
}
}
}

View file

@ -0,0 +1,66 @@
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.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import lombok.With;
import java.io.IOException;
@Data
@With
@AllArgsConstructor
public class ClientboundLevelChunkWithLightPacket implements Packet {
private final int x;
private final int z;
private final @NonNull byte[] chunkData;
private final @NonNull CompoundTag heightMaps;
private final @NonNull BlockEntityInfo[] blockEntities;
private final @NonNull LightUpdateData lightData;
public ClientboundLevelChunkWithLightPacket(NetInput in) throws IOException {
this.x = in.readInt();
this.z = in.readInt();
this.heightMaps = NBT.read(in);
this.chunkData = in.readBytes(in.readVarInt());
this.blockEntities = new BlockEntityInfo[in.readVarInt()];
for (int i = 0; i < blockEntities.length; i++) {
byte xz = in.readByte();
int blockEntityX = (xz >> 4) & 15;
int blockEntityZ = xz & 15;
int blockEntityY = in.readShort();
int type = in.readVarInt();
CompoundTag tag = NBT.read(in);
blockEntities[i] = new BlockEntityInfo(blockEntityX, blockEntityY, blockEntityZ, type, tag);
}
this.lightData = LightUpdateData.read(in);
}
@Override
public void write(NetOutput out) throws IOException {
out.writeInt(this.x);
out.writeInt(this.z);
NBT.write(out, this.heightMaps);
out.writeVarInt(this.chunkData.length);
out.writeBytes(this.chunkData);
out.writeVarInt(this.blockEntities.length);
for (BlockEntityInfo blockEntity : this.blockEntities) {
out.writeByte(((blockEntity.getX() & 15) << 4) | blockEntity.getZ() & 15);
out.writeShort(blockEntity.getY());
out.writeVarInt(blockEntity.getId());
NBT.write(out, blockEntity.getNbt());
}
LightUpdateData.write(out, this.lightData);
}
}

View file

@ -1,32 +1,26 @@
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.game.level.LightUpdateData;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.With;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
@Data
@With
@AllArgsConstructor
public class ClientboundLightUpdatePacket implements Packet {
private final int x;
private final int z;
private final @NonNull BitSet skyYMask;
private final @NonNull BitSet blockYMask;
private final @NonNull BitSet emptySkyYMask;
private final @NonNull BitSet emptyBlockYMask;
private final @NonNull List<byte[]> skyUpdates;
private final @NonNull List<byte[]> blockUpdates;
private final boolean trustEdges;
private final @Nonnull LightUpdateData lightData;
public ClientboundLightUpdatePacket(int x, int z, @NonNull BitSet skyYMask, @NonNull BitSet blockYMask,
@NonNull BitSet emptySkyYMask, @NonNull BitSet emptyBlockYMask,
@ -43,72 +37,19 @@ public class ClientboundLightUpdatePacket implements Packet {
}
this.x = x;
this.z = z;
this.skyYMask = skyYMask;
this.blockYMask = blockYMask;
this.emptySkyYMask = emptySkyYMask;
this.emptyBlockYMask = emptyBlockYMask;
this.skyUpdates = skyUpdates;
this.blockUpdates = blockUpdates;
this.trustEdges = trustEdges;
this.lightData = new LightUpdateData(skyYMask, blockYMask, emptySkyYMask, emptyBlockYMask, skyUpdates, blockUpdates, trustEdges);
}
public ClientboundLightUpdatePacket(NetInput in) throws IOException {
this.x = in.readVarInt();
this.z = in.readVarInt();
this.trustEdges = in.readBoolean();
this.skyYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.blockYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.emptySkyYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
this.emptyBlockYMask = BitSet.valueOf(in.readLongs(in.readVarInt()));
int skyUpdateSize = in.readVarInt();
skyUpdates = new ArrayList<>(skyUpdateSize);
for (int i = 0; i < skyUpdateSize; i++) {
skyUpdates.add(in.readBytes(in.readVarInt()));
}
int blockUpdateSize = in.readVarInt();
blockUpdates = new ArrayList<>(blockUpdateSize);
for (int i = 0; i < blockUpdateSize; i++) {
blockUpdates.add(in.readBytes(in.readVarInt()));
}
this.lightData = LightUpdateData.read(in);
}
@Override
public void write(NetOutput out) throws IOException {
out.writeVarInt(this.x);
out.writeVarInt(this.z);
out.writeBoolean(this.trustEdges);
writeBitSet(out, this.skyYMask);
writeBitSet(out, this.blockYMask);
writeBitSet(out, this.emptySkyYMask);
writeBitSet(out, this.emptyBlockYMask);
out.writeVarInt(this.skyUpdates.size());
for (byte[] array : this.skyUpdates) {
out.writeVarInt(array.length);
out.writeBytes(array);
}
out.writeVarInt(this.blockUpdates.size());
for (byte[] array : this.blockUpdates) {
out.writeVarInt(array.length);
out.writeBytes(array);
}
}
@Override
public boolean isPriority() {
return false;
}
private void writeBitSet(NetOutput out, BitSet bitSet) throws IOException {
long[] array = bitSet.toLongArray();
out.writeVarInt(array.length);
for (long content : array) {
out.writeLong(content);
}
LightUpdateData.write(out, this.lightData);
}
}

View file

@ -0,0 +1,26 @@
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.With;
import java.io.IOException;
@Data
@With
@AllArgsConstructor
public class ClientboundSetSimulationDistancePacket implements Packet {
private final int simulationDistance;
public ClientboundSetSimulationDistancePacket(NetInput in) throws IOException {
this.simulationDistance = in.readVarInt();
}
@Override
public void write(NetOutput out) throws IOException {
out.writeVarInt(this.simulationDistance);
}
}

View file

@ -27,6 +27,10 @@ public class ServerboundClientInformationPacket implements Packet {
private final @NonNull List<SkinPart> visibleParts;
private final @NonNull HandPreference mainHand;
private final boolean textFilteringEnabled;
/**
* Whether the client permits being shown in server ping responses.
*/
private final boolean allowsListing;
public ServerboundClientInformationPacket(NetInput in) throws IOException {
this.locale = in.readString();
@ -45,6 +49,7 @@ public class ServerboundClientInformationPacket implements Packet {
this.mainHand = MagicValues.key(HandPreference.class, in.readVarInt());
this.textFilteringEnabled = in.readBoolean();
this.allowsListing = in.readBoolean();
}
@Override
@ -63,5 +68,6 @@ public class ServerboundClientInformationPacket implements Packet {
out.writeVarInt(MagicValues.value(Integer.class, this.mainHand));
out.writeBoolean(this.textFilteringEnabled);
out.writeBoolean(allowsListing);
}
}

View file

@ -49,7 +49,7 @@ public class MinecraftProtocolTest {
Component.text("Hello world!"),
null
);
private static final ClientboundLoginPacket JOIN_GAME_PACKET = new ClientboundLoginPacket(0, false, GameMode.SURVIVAL, GameMode.SURVIVAL, 1, new String[]{"minecraft:world"}, getDimensionTag(), getOverworldTag(), "minecraft:world", 100, 0, 16, false, false, false, false);
private static final ClientboundLoginPacket JOIN_GAME_PACKET = new ClientboundLoginPacket(0, false, GameMode.SURVIVAL, GameMode.SURVIVAL, 1, new String[]{"minecraft:world"}, getDimensionTag(), getOverworldTag(), "minecraft:world", 100, 0, 16, 16, false, false, false, false);
private static Server server;

View file

@ -38,7 +38,7 @@ public abstract class PacketTest {
return constructor.newInstance(in);
} catch (NoSuchMethodError e) {
throw new IllegalStateException("Packet \"" + clazz.getName() + "\" does not have a no-params constructor for instantiation.");
throw new IllegalStateException("Packet \"" + clazz.getName() + "\" does not have a NetInput constructor for instantiation.");
} catch (Exception e) {
throw new IllegalStateException("Failed to instantiate packet \"" + clazz.getName() + "\".", e);
}

View file

@ -1,38 +0,0 @@
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
import com.github.steveice10.mc.protocol.packet.PacketTest;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.junit.Before;
public class ClientboundLevelChunkPacketTest extends PacketTest {
@Before
public void setup() {
Chunk chunk = new Chunk();
chunk.set(0, 0, 0, 10);
this.setPackets(
new ClientboundLevelChunkPacket(
new Column(0, 0, new Chunk[]{
null, null, null, null, null, null, null, chunk,
null, chunk, null, null, null, chunk, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null
}, new CompoundTag[0], new CompoundTag("HeightMaps"), new int[1024])
),
new ClientboundLevelChunkPacket(
new Column(1, 1, new Chunk[]{
chunk, chunk, chunk, chunk, chunk, chunk, chunk, chunk,
chunk, chunk, chunk, chunk, chunk, chunk, chunk, chunk, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null
}, new CompoundTag[]{
new CompoundTag("TileEntity")
}, new CompoundTag("HeightMaps"), new int[1024])
)
);
}
}

View file

@ -0,0 +1,32 @@
package com.github.steveice10.mc.protocol.packet.ingame.clientbound.level;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
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.packet.PacketTest;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.junit.Before;
import java.io.IOException;
import java.util.BitSet;
import java.util.Collections;
public class ClientboundLevelChunkWithLightPacketTest extends PacketTest {
@Before
public void setup() throws IOException {
Chunk chunk = new Chunk();
chunk.setBlock(0, 0, 0, 10);
this.setPackets(
new ClientboundLevelChunkWithLightPacket(0, 0,
new byte[0], new CompoundTag("HeightMaps"), new BlockEntityInfo[0],
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 LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), Collections.emptyList(), Collections.emptyList(), true)
)
);
}
}