Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +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:
Ursprung
65db0fad6a
Commit
e6a93ad0c6
@ -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;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,43 +183,22 @@ 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) {
|
||||||
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) {
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||||
this.previousGamemode = buf.readByte();
|
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||||
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
// so separate it out.
|
||||||
CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
this.decode116Up(buf, version);
|
||||||
ListBinaryTag dimensionRegistryContainer = null;
|
} else {
|
||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
this.decodeLegacy(buf, version);
|
||||||
dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type")
|
}
|
||||||
.getList("value", BinaryTagTypes.COMPOUND);
|
}
|
||||||
this.biomeRegistry = registryContainer.getCompound("minecraft:worldgen/biome");
|
|
||||||
} else {
|
private void decodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||||
dimensionRegistryContainer = registryContainer.getList("dimension",
|
this.entityId = buf.readInt();
|
||||||
BinaryTagTypes.COMPOUND);
|
this.gamemode = buf.readByte();
|
||||||
}
|
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||||
ImmutableSet<DimensionData> readData =
|
this.gamemode &= ~0x08;
|
||||||
DimensionRegistry.fromGameData(dimensionRegistryContainer, version);
|
|
||||||
this.dimensionRegistry = new DimensionRegistry(readData, levelNames);
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
|
||||||
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) {
|
|
||||||
this.dimension = buf.readInt();
|
this.dimension = buf.readInt();
|
||||||
} else {
|
} else {
|
||||||
this.dimension = buf.readByte();
|
this.dimension = buf.readByte();
|
||||||
@ -230,14 +209,8 @@ public class JoinGame implements MinecraftPacket {
|
|||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
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) {
|
this.maxPlayers = buf.readUnsignedByte();
|
||||||
this.maxPlayers = ProtocolUtils.readVarInt(buf);
|
this.levelType = ProtocolUtils.readString(buf, 16);
|
||||||
} else {
|
|
||||||
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) {
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
|
||||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||||
}
|
}
|
||||||
@ -247,15 +220,76 @@ public class JoinGame implements MinecraftPacket {
|
|||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
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 isFlat = buf.readBoolean();
|
private void decode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||||
this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug);
|
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
|
@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);
|
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,29 +297,7 @@ 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) {
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 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) {
|
|
||||||
buf.writeInt(dimension);
|
buf.writeInt(dimension);
|
||||||
} else {
|
} else {
|
||||||
buf.writeByte(dimension);
|
buf.writeByte(dimension);
|
||||||
@ -296,17 +308,11 @@ public class JoinGame implements MinecraftPacket {
|
|||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
||||||
buf.writeLong(partialHashedSeed);
|
buf.writeLong(partialHashedSeed);
|
||||||
}
|
}
|
||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
|
buf.writeByte(maxPlayers);
|
||||||
ProtocolUtils.writeVarInt(buf, maxPlayers);
|
if (levelType == null) {
|
||||||
} else {
|
throw new IllegalStateException("No level type specified.");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
ProtocolUtils.writeString(buf, levelType);
|
||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
|
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
|
||||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||||
}
|
}
|
||||||
@ -316,10 +322,48 @@ public class JoinGame implements MinecraftPacket {
|
|||||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
|
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.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
|
@Override
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren