mirror of
https://github.com/PaperMC/Velocity.git
synced 2024-11-27 06:30:35 +08:00
Clean up JoinGame packet encoding/decoding
Specifically, the JoinGame packet handling is now split between pre-1.16 encodings of the packet and post-1.16 handlings of the packet. This packet is one of the most amorphous packets in the entire Minecraft protocol, from Velocity's perspective.
This commit is contained in:
parent
65db0fad6a
commit
e6a93ad0c6
@ -44,6 +44,10 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
if (varintEnd == -1) {
|
||||
// We tried to go beyond the end of the buffer. This is probably a good sign that the
|
||||
// buffer was too short to hold a proper varint.
|
||||
if (reader.getResult() == DecodeResult.RUN_OF_ZEROES) {
|
||||
// Special case where the entire packet is just a run of zeroes. We ignore them all.
|
||||
in.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -54,7 +58,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
in.clear();
|
||||
throw BAD_LENGTH_CACHED;
|
||||
} else if (readVarint == 0) {
|
||||
// skip over the empty packet and ignore it
|
||||
// skip over the empty packet(s) and ignore it
|
||||
in.readerIndex(varintEnd + 1);
|
||||
} else {
|
||||
int minimumRead = bytesRead + readVarint;
|
||||
|
@ -27,6 +27,15 @@ class VarintByteDecoder implements ByteProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(byte k) {
|
||||
if (k == 0 && bytesRead == 0) {
|
||||
// tentatively say it's invalid, but there's a possibility of redemption
|
||||
result = DecodeResult.RUN_OF_ZEROES;
|
||||
return true;
|
||||
}
|
||||
if (result == DecodeResult.RUN_OF_ZEROES) {
|
||||
result = DecodeResult.SUCCESS;
|
||||
return false;
|
||||
}
|
||||
readVarint |= (k & 0x7F) << bytesRead++ * 7;
|
||||
if (bytesRead > 3) {
|
||||
result = DecodeResult.TOO_BIG;
|
||||
@ -54,6 +63,7 @@ class VarintByteDecoder implements ByteProcessor {
|
||||
public enum DecodeResult {
|
||||
SUCCESS,
|
||||
TOO_SHORT,
|
||||
TOO_BIG
|
||||
TOO_BIG,
|
||||
RUN_OF_ZEROES
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ public class JoinGame implements MinecraftPacket {
|
||||
return levelType;
|
||||
}
|
||||
|
||||
public void setLevelType(String levelType) {
|
||||
public void setLevelType(@Nullable String levelType) {
|
||||
this.levelType = levelType;
|
||||
}
|
||||
|
||||
@ -183,43 +183,22 @@ public class JoinGame implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
this.isHardcore = buf.readBoolean();
|
||||
this.gamemode = buf.readByte();
|
||||
} else {
|
||||
this.gamemode = buf.readByte();
|
||||
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||
this.gamemode &= ~0x08;
|
||||
}
|
||||
String dimensionIdentifier = null;
|
||||
String levelName = null;
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
this.previousGamemode = buf.readByte();
|
||||
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
ListBinaryTag dimensionRegistryContainer = null;
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type")
|
||||
.getList("value", BinaryTagTypes.COMPOUND);
|
||||
this.biomeRegistry = registryContainer.getCompound("minecraft:worldgen/biome");
|
||||
} else {
|
||||
dimensionRegistryContainer = registryContainer.getList("dimension",
|
||||
BinaryTagTypes.COMPOUND);
|
||||
}
|
||||
ImmutableSet<DimensionData> readData =
|
||||
DimensionRegistry.fromGameData(dimensionRegistryContainer, version);
|
||||
this.dimensionRegistry = new DimensionRegistry(readData, levelNames);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
CompoundBinaryTag currentDimDataTag = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
this.currentDimensionData = DimensionData.decodeBaseCompoundTag(currentDimDataTag, version)
|
||||
.annotateWith(dimensionIdentifier, null);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
} else if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
this.decode116Up(buf, version);
|
||||
} else {
|
||||
this.decodeLegacy(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
this.gamemode = buf.readByte();
|
||||
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||
this.gamemode &= ~0x08;
|
||||
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
|
||||
this.dimension = buf.readInt();
|
||||
} else {
|
||||
this.dimension = buf.readByte();
|
||||
@ -230,14 +209,8 @@ public class JoinGame implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
this.maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
this.maxPlayers = buf.readUnsignedByte();
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) < 0) {
|
||||
this.levelType = ProtocolUtils.readString(buf, 16);
|
||||
}
|
||||
this.maxPlayers = buf.readUnsignedByte();
|
||||
this.levelType = ProtocolUtils.readString(buf, 16);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
|
||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
@ -247,15 +220,76 @@ public class JoinGame implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
||||
this.showRespawnScreen = buf.readBoolean();
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug);
|
||||
}
|
||||
|
||||
private void decode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
this.isHardcore = buf.readBoolean();
|
||||
this.gamemode = buf.readByte();
|
||||
} else {
|
||||
this.gamemode = buf.readByte();
|
||||
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||
this.gamemode &= ~0x08;
|
||||
}
|
||||
|
||||
this.previousGamemode = buf.readByte();
|
||||
|
||||
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
|
||||
CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
ListBinaryTag dimensionRegistryContainer;
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type")
|
||||
.getList("value", BinaryTagTypes.COMPOUND);
|
||||
this.biomeRegistry = registryContainer.getCompound("minecraft:worldgen/biome");
|
||||
} else {
|
||||
dimensionRegistryContainer = registryContainer.getList("dimension",
|
||||
BinaryTagTypes.COMPOUND);
|
||||
}
|
||||
ImmutableSet<DimensionData> readData =
|
||||
DimensionRegistry.fromGameData(dimensionRegistryContainer, version);
|
||||
this.dimensionRegistry = new DimensionRegistry(readData, levelNames);
|
||||
|
||||
String dimensionIdentifier;
|
||||
String levelName = null;
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
CompoundBinaryTag currentDimDataTag = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
this.currentDimensionData = DimensionData.decodeBaseCompoundTag(currentDimDataTag, version)
|
||||
.annotateWith(dimensionIdentifier, null);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
this.maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
this.maxPlayers = buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
this.reducedDebugInfo = buf.readBoolean();
|
||||
this.showRespawnScreen = buf.readBoolean();
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
this.encode116Up(buf, version);
|
||||
} else {
|
||||
this.encodeLegacy(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(entityId);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
buf.writeBoolean(isHardcore);
|
||||
@ -263,29 +297,7 @@ public class JoinGame implements MinecraftPacket {
|
||||
} else {
|
||||
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
buf.writeByte(previousGamemode);
|
||||
ProtocolUtils.writeStringArray(buf, dimensionRegistry.getLevelNames().toArray(new String[0]));
|
||||
CompoundBinaryTag.Builder registryContainer = CompoundBinaryTag.builder();
|
||||
ListBinaryTag encodedDimensionRegistry = dimensionRegistry.encodeRegistry(version);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
CompoundBinaryTag.Builder dimensionRegistryEntry = CompoundBinaryTag.builder();
|
||||
dimensionRegistryEntry.putString("type", "minecraft:dimension_type");
|
||||
dimensionRegistryEntry.put("value", encodedDimensionRegistry);
|
||||
registryContainer.put("minecraft:dimension_type", dimensionRegistryEntry.build());
|
||||
registryContainer.put("minecraft:worldgen/biome", biomeRegistry);
|
||||
} else {
|
||||
registryContainer.put("dimension", encodedDimensionRegistry);
|
||||
}
|
||||
ProtocolUtils.writeCompoundTag(buf, registryContainer.build());
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
ProtocolUtils.writeCompoundTag(buf, currentDimensionData.serializeDimensionDetails());
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||
}
|
||||
} else if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
|
||||
buf.writeInt(dimension);
|
||||
} else {
|
||||
buf.writeByte(dimension);
|
||||
@ -296,17 +308,11 @@ public class JoinGame implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
||||
buf.writeLong(partialHashedSeed);
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
ProtocolUtils.writeVarInt(buf, maxPlayers);
|
||||
} else {
|
||||
buf.writeByte(maxPlayers);
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) < 0) {
|
||||
if (levelType == null) {
|
||||
throw new IllegalStateException("No level type specified.");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, levelType);
|
||||
buf.writeByte(maxPlayers);
|
||||
if (levelType == null) {
|
||||
throw new IllegalStateException("No level type specified.");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, levelType);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
|
||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||
}
|
||||
@ -316,10 +322,48 @@ public class JoinGame implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
||||
buf.writeBoolean(showRespawnScreen);
|
||||
}
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(dimensionInfo.isFlat());
|
||||
}
|
||||
|
||||
private void encode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(entityId);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
buf.writeBoolean(isHardcore);
|
||||
buf.writeByte(gamemode);
|
||||
} else {
|
||||
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
|
||||
}
|
||||
buf.writeByte(previousGamemode);
|
||||
ProtocolUtils.writeStringArray(buf, dimensionRegistry.getLevelNames().toArray(new String[0]));
|
||||
CompoundBinaryTag.Builder registryContainer = CompoundBinaryTag.builder();
|
||||
ListBinaryTag encodedDimensionRegistry = dimensionRegistry.encodeRegistry(version);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
CompoundBinaryTag.Builder dimensionRegistryEntry = CompoundBinaryTag.builder();
|
||||
dimensionRegistryEntry.putString("type", "minecraft:dimension_type");
|
||||
dimensionRegistryEntry.put("value", encodedDimensionRegistry);
|
||||
registryContainer.put("minecraft:dimension_type", dimensionRegistryEntry.build());
|
||||
registryContainer.put("minecraft:worldgen/biome", biomeRegistry);
|
||||
} else {
|
||||
registryContainer.put("dimension", encodedDimensionRegistry);
|
||||
}
|
||||
ProtocolUtils.writeCompoundTag(buf, registryContainer.build());
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
ProtocolUtils.writeCompoundTag(buf, currentDimensionData.serializeDimensionDetails());
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||
}
|
||||
buf.writeLong(partialHashedSeed);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
||||
ProtocolUtils.writeVarInt(buf, maxPlayers);
|
||||
} else {
|
||||
buf.writeByte(maxPlayers);
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||
buf.writeBoolean(reducedDebugInfo);
|
||||
buf.writeBoolean(showRespawnScreen);
|
||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(dimensionInfo.isFlat());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user