3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01: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.
Dieser Commit ist enthalten in:
Andrew Steinborn 2021-08-21 02:17:34 -04:00
Ursprung 65db0fad6a
Commit e6a93ad0c6
3 geänderte Dateien mit 145 neuen und 87 gelöschten Zeilen

Datei anzeigen

@ -44,6 +44,10 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
if (varintEnd == -1) { if (varintEnd == -1) {
// We tried to go beyond the end of the buffer. This is probably a good sign that the // 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. // 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; return;
} }
@ -54,7 +58,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
in.clear(); in.clear();
throw BAD_LENGTH_CACHED; throw BAD_LENGTH_CACHED;
} else if (readVarint == 0) { } 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); in.readerIndex(varintEnd + 1);
} else { } else {
int minimumRead = bytesRead + readVarint; int minimumRead = bytesRead + readVarint;

Datei anzeigen

@ -27,6 +27,15 @@ class VarintByteDecoder implements ByteProcessor {
@Override @Override
public boolean process(byte k) { 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; readVarint |= (k & 0x7F) << bytesRead++ * 7;
if (bytesRead > 3) { if (bytesRead > 3) {
result = DecodeResult.TOO_BIG; result = DecodeResult.TOO_BIG;
@ -54,6 +63,7 @@ class VarintByteDecoder implements ByteProcessor {
public enum DecodeResult { public enum DecodeResult {
SUCCESS, SUCCESS,
TOO_SHORT, TOO_SHORT,
TOO_BIG TOO_BIG,
RUN_OF_ZEROES
} }
} }

Datei anzeigen

@ -99,7 +99,7 @@ public class JoinGame implements MinecraftPacket {
return levelType; return levelType;
} }
public void setLevelType(String levelType) { public void setLevelType(@Nullable String levelType) {
this.levelType = levelType; this.levelType = levelType;
} }
@ -183,6 +183,46 @@ public class JoinGame implements MinecraftPacket {
@Override @Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { public void decode(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.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();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13_2) <= 0) {
this.difficulty = buf.readUnsignedByte();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
this.partialHashedSeed = buf.readLong();
}
this.maxPlayers = buf.readUnsignedByte();
this.levelType = ProtocolUtils.readString(buf, 16);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
this.viewDistance = ProtocolUtils.readVarInt(buf);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
this.reducedDebugInfo = buf.readBoolean();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
this.showRespawnScreen = buf.readBoolean();
}
}
private void decode116Up(ByteBuf buf, ProtocolVersion version) {
this.entityId = buf.readInt(); this.entityId = buf.readInt();
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
this.isHardcore = buf.readBoolean(); this.isHardcore = buf.readBoolean();
@ -192,13 +232,13 @@ public class JoinGame implements MinecraftPacket {
this.isHardcore = (this.gamemode & 0x08) != 0; this.isHardcore = (this.gamemode & 0x08) != 0;
this.gamemode &= ~0x08; this.gamemode &= ~0x08;
} }
String dimensionIdentifier = null;
String levelName = null;
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
this.previousGamemode = buf.readByte(); this.previousGamemode = buf.readByte();
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf)); ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
ListBinaryTag dimensionRegistryContainer = null; ListBinaryTag dimensionRegistryContainer;
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type") dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type")
.getList("value", BinaryTagTypes.COMPOUND); .getList("value", BinaryTagTypes.COMPOUND);
@ -210,6 +250,9 @@ public class JoinGame implements MinecraftPacket {
ImmutableSet<DimensionData> readData = ImmutableSet<DimensionData> readData =
DimensionRegistry.fromGameData(dimensionRegistryContainer, version); DimensionRegistry.fromGameData(dimensionRegistryContainer, version);
this.dimensionRegistry = new DimensionRegistry(readData, levelNames); this.dimensionRegistry = new DimensionRegistry(readData, levelNames);
String dimensionIdentifier;
String levelName = null;
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
CompoundBinaryTag currentDimDataTag = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); CompoundBinaryTag currentDimDataTag = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
dimensionIdentifier = ProtocolUtils.readString(buf); dimensionIdentifier = ProtocolUtils.readString(buf);
@ -219,43 +262,69 @@ public class JoinGame implements MinecraftPacket {
dimensionIdentifier = ProtocolUtils.readString(buf); dimensionIdentifier = ProtocolUtils.readString(buf);
levelName = ProtocolUtils.readString(buf); levelName = ProtocolUtils.readString(buf);
} }
} else if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
this.dimension = buf.readInt();
} else {
this.dimension = buf.readByte();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13_2) <= 0) {
this.difficulty = buf.readUnsignedByte();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
this.partialHashedSeed = buf.readLong(); this.partialHashedSeed = buf.readLong();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
this.maxPlayers = ProtocolUtils.readVarInt(buf); this.maxPlayers = ProtocolUtils.readVarInt(buf);
} else { } else {
this.maxPlayers = buf.readUnsignedByte(); this.maxPlayers = buf.readUnsignedByte();
} }
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) < 0) {
this.levelType = ProtocolUtils.readString(buf, 16);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
this.viewDistance = ProtocolUtils.readVarInt(buf); this.viewDistance = ProtocolUtils.readVarInt(buf);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
this.reducedDebugInfo = buf.readBoolean(); this.reducedDebugInfo = buf.readBoolean();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
this.showRespawnScreen = buf.readBoolean(); this.showRespawnScreen = buf.readBoolean();
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
boolean isDebug = buf.readBoolean(); boolean isDebug = buf.readBoolean();
boolean isFlat = buf.readBoolean(); boolean isFlat = buf.readBoolean();
this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug); this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug);
} }
}
@Override @Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { 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);
buf.writeByte(gamemode);
} else {
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
buf.writeInt(dimension);
} else {
buf.writeByte(dimension);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13_2) <= 0) {
buf.writeByte(difficulty);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
buf.writeLong(partialHashedSeed);
}
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);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
buf.writeBoolean(reducedDebugInfo);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
buf.writeBoolean(showRespawnScreen);
}
}
private void encode116Up(ByteBuf buf, ProtocolVersion version) {
buf.writeInt(entityId); buf.writeInt(entityId);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
buf.writeBoolean(isHardcore); buf.writeBoolean(isHardcore);
@ -263,7 +332,6 @@ public class JoinGame implements MinecraftPacket {
} else { } else {
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode); buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
} }
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
buf.writeByte(previousGamemode); buf.writeByte(previousGamemode);
ProtocolUtils.writeStringArray(buf, dimensionRegistry.getLevelNames().toArray(new String[0])); ProtocolUtils.writeStringArray(buf, dimensionRegistry.getLevelNames().toArray(new String[0]));
CompoundBinaryTag.Builder registryContainer = CompoundBinaryTag.builder(); CompoundBinaryTag.Builder registryContainer = CompoundBinaryTag.builder();
@ -285,42 +353,18 @@ public class JoinGame implements MinecraftPacket {
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier()); ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName()); ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
} }
} else if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
buf.writeInt(dimension);
} else {
buf.writeByte(dimension);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13_2) <= 0) {
buf.writeByte(difficulty);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
buf.writeLong(partialHashedSeed); buf.writeLong(partialHashedSeed);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
ProtocolUtils.writeVarInt(buf, maxPlayers); ProtocolUtils.writeVarInt(buf, maxPlayers);
} else { } else {
buf.writeByte(maxPlayers); 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);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
ProtocolUtils.writeVarInt(buf, viewDistance); ProtocolUtils.writeVarInt(buf, viewDistance);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
buf.writeBoolean(reducedDebugInfo); buf.writeBoolean(reducedDebugInfo);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
buf.writeBoolean(showRespawnScreen); buf.writeBoolean(showRespawnScreen);
}
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
buf.writeBoolean(dimensionInfo.isDebugType()); buf.writeBoolean(dimensionInfo.isDebugType());
buf.writeBoolean(dimensionInfo.isFlat()); buf.writeBoolean(dimensionInfo.isFlat());
} }
}
@Override @Override
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {