mutableVersions = new EnumMap<>(ProtocolVersion.class);
- for (ProtocolVersion version : ProtocolVersion.values()) {
- if (!version.isLegacy() && !version.isUnknown()) {
- mutableVersions.put(version, new ProtocolRegistry(version));
- }
- }
-
- this.versions = Collections.unmodifiableMap(mutableVersions);
- }
-
- ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) {
- ProtocolRegistry registry = versions.get(version);
- if (registry == null) {
- if (fallback) {
- return getProtocolRegistry(MINIMUM_VERSION);
- }
- throw new IllegalArgumentException("Could not find data for protocol version " + version);
- }
- return registry;
- }
-
- void register(Class
clazz, PacketCodec
codec,
- PacketMapping... mappings) {
- if (mappings.length == 0) {
- throw new IllegalArgumentException("At least one mapping must be provided.");
- }
-
- for (int i = 0; i < mappings.length; i++) {
- PacketMapping current = mappings[i];
- PacketMapping next = (i + 1 < mappings.length) ? mappings[i + 1] : current;
-
- ProtocolVersion from = current.protocolVersion;
- ProtocolVersion lastValid = current.lastValidProtocolVersion;
- if (lastValid != null) {
- if (next != current) {
- throw new IllegalArgumentException("Cannot add a mapping after last valid mapping");
- }
- if (from.greaterThan(lastValid)) {
- throw new IllegalArgumentException(
- "Last mapping version cannot be higher than highest mapping version");
- }
- }
- ProtocolVersion to = current == next ? lastValid != null
- ? lastValid : getLast(SUPPORTED_VERSIONS) : next.protocolVersion;
-
- ProtocolVersion lastInList = lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS);
-
- if (from.noLessThan(to) && from != lastInList) {
- throw new IllegalArgumentException(String.format(
- "Next mapping version (%s) should be lower then current (%s)", to, from));
- }
-
- for (ProtocolVersion protocol : EnumSet.range(from, to)) {
- if (protocol == to && next != current) {
- break;
- }
- ProtocolRegistry registry = this.versions.get(protocol);
- if (registry == null) {
- throw new IllegalArgumentException(
- "Unknown protocol version " + current.protocolVersion);
- }
-
- if (registry.packetIdToCodec.containsKey(current.id)) {
- throw new IllegalArgumentException(
- "Can not register class "
- + clazz.getSimpleName()
- + " with id "
- + current.id
- + " for "
- + registry.version
- + " because another packet is already registered");
- }
-
- if (registry.packetClassToId.containsKey(clazz)) {
- throw new IllegalArgumentException(
- clazz.getSimpleName() + " is already registered for version " + registry.version);
- }
-
- if (!current.encodeOnly) {
- registry.packetIdToCodec.put(current.id, codec);
- }
- registry.packetClassToCodec.put(clazz, codec);
- registry.packetClassToId.put(clazz, current.id);
- }
- }
- }
-
- /**
- * Protocol registry.
- */
- public class ProtocolRegistry {
-
- public final ProtocolVersion version;
- final IntObjectMap> packetIdToCodec =
- new IntObjectHashMap<>(16, 0.5f);
-
- final Map, PacketCodec extends MinecraftPacket>> packetClassToCodec =
- new HashMap<>(16, 0.5f);
- final Object2IntMap> packetClassToId =
- new Object2IntOpenHashMap<>(16, 0.5f);
-
- ProtocolRegistry(final ProtocolVersion version) {
- this.version = version;
- this.packetClassToId.defaultReturnValue(Integer.MIN_VALUE);
- }
-
- /**
- * Gets the codec for the specified packet {@code id}.
- *
- * @param id the packet ID
- * @return the packet codec, or {@code null} if the ID is not registered
- */
- public @Nullable PacketCodec extends MinecraftPacket> getCodec(final int id) {
- return this.packetIdToCodec.get(id);
- }
-
- /**
- * Gets the codec for the specified packet class.
- *
- * @param packetClass the packet class
- * @return the packet codec, or {@code null} if the class is not registered
- */
- @SuppressWarnings("unchecked")
- public @Nullable PacketCodec getCodec(
- final Class packetClass) {
- return (PacketCodec) this.packetClassToCodec.get(packetClass);
- }
-
- /**
- * Attempts to look up the packet ID for an {@code packet}.
- *
- * @param packet the packet to look up
- * @return the packet ID
- * @throws IllegalArgumentException if the packet ID is not found
- */
- public int getPacketId(final MinecraftPacket packet) {
- final int id = this.packetClassToId.getInt(packet.getClass());
- if (id == Integer.MIN_VALUE) {
- throw new IllegalArgumentException(String.format(
- "Unable to find id for packet of type %s in %s protocol %s phase %s",
- packet.getClass().getName(), PacketRegistry.this.direction,
- this.version, PacketRegistry.this.registry
- ));
- }
- return id;
- }
-
- /**
- * Checks if the registry contains a packet with the specified {@code id}.
- *
- * @param packet the packet to check
- * @return {@code true} if the packet is registered, {@code false} otherwise
- */
- public boolean containsPacket(final MinecraftPacket packet) {
- return this.packetClassToId.containsKey(packet.getClass());
- }
- }
- }
-
- /**
- * Packet mapping.
- */
- public static final class PacketMapping {
-
- private final int id;
- private final ProtocolVersion protocolVersion;
- private final boolean encodeOnly;
- private final @Nullable ProtocolVersion lastValidProtocolVersion;
-
- PacketMapping(int id, ProtocolVersion protocolVersion,
- @Nullable ProtocolVersion lastValidProtocolVersion,
- boolean packetDecoding) {
- this.id = id;
- this.protocolVersion = protocolVersion;
- this.lastValidProtocolVersion = lastValidProtocolVersion;
- this.encodeOnly = packetDecoding;
- }
-
- @Override
- public String toString() {
- return "PacketMapping{"
- + "id="
- + id
- + ", protocolVersion="
- + protocolVersion
- + ", encodeOnly="
- + encodeOnly
- + '}';
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- PacketMapping that = (PacketMapping) o;
- return id == that.id
- && protocolVersion == that.protocolVersion
- && encodeOnly == that.encodeOnly;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, protocolVersion, encodeOnly);
- }
- }
-
- /**
- * Creates a PacketMapping using the provided arguments.
- *
- * @param id Packet Id
- * @param version Protocol version
- * @param encodeOnly When true packet decoding will be disabled
- * @return PacketMapping with the provided arguments
- */
- @SuppressFBWarnings({"UPM_UNCALLED_PRIVATE_METHOD"})
- private static PacketMapping map(int id, ProtocolVersion version, boolean encodeOnly) {
- return map(id, version, null, encodeOnly);
- }
-
- /**
- * Creates a PacketMapping using the provided arguments.
- *
- * @param id Packet Id
- * @param version Protocol version
- * @param encodeOnly When true packet decoding will be disabled
- * @param lastValidProtocolVersion Last version this Mapping is valid at
- * @return PacketMapping with the provided arguments
- */
- private static PacketMapping map(int id, ProtocolVersion version,
- ProtocolVersion lastValidProtocolVersion, boolean encodeOnly) {
- return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly);
- }
-
}
\ No newline at end of file
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java
index 45b79b3dc..fad9f52eb 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java
@@ -20,8 +20,10 @@ package com.velocitypowered.proxy.protocol.netty;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
+import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
+import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import com.velocitypowered.proxy.util.except.QuietRuntimeException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
@@ -39,8 +41,9 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
+ "information, launch Velocity with -Dvelocity.packet-decode-logging=true to see more.");
private final ProtocolUtils.Direction direction;
+ private ProtocolVersion version;
private StateRegistry state;
- private StateRegistry.PacketRegistry.ProtocolRegistry registry;
+ private PacketRegistry registry;
/**
* Creates a new {@code MinecraftDecoder} decoding packets from the specified {@code direction}.
@@ -49,8 +52,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
*/
public MinecraftDecoder(ProtocolUtils.Direction direction) {
this.direction = Preconditions.checkNotNull(direction, "direction");
- this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry(
- direction, ProtocolVersion.MINIMUM_VERSION);
+ this.version = ProtocolVersion.MINIMUM_VERSION;
+ this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE;
}
@@ -82,11 +85,13 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
MinecraftPacket packet;
try {
- packet = codec.decode(buf, direction, registry.version);
+ packet = codec.decode(buf, direction, this.version);
} catch (Exception e) {
throw handleDecodeFailure(e, codec, packetId);
}
+ System.out.println(packet);
+
if (buf.isReadable()) {
throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex());
}
@@ -100,8 +105,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
private void doLengthSanityChecks(ByteBuf buf,
com.velocitypowered.proxy.protocol.PacketCodec extends MinecraftPacket> codec)
throws Exception {
- int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, registry.version);
- int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, registry.version);
+ int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, this.version);
+ int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, this.version);
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
throw handleOverflow(codec, expectedMaxLen, buf.readableBytes());
}
@@ -153,17 +158,18 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
}
private String getExtraConnectionDetail(int packetId) {
- return "Direction " + direction + " Protocol " + registry.version + " State " + state
+ return "Direction " + direction + " Protocol " + this.version + " State " + state
+ " ID 0x" + Integer.toHexString(packetId);
}
public void setProtocolVersion(ProtocolVersion protocolVersion) {
- this.registry = state.getProtocolRegistry(direction, protocolVersion);
+ this.version = protocolVersion;
+ this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(protocolVersion);
}
public void setState(StateRegistry state) {
this.state = state;
- this.setProtocolVersion(registry.version);
+ this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(this.version);
}
public ProtocolUtils.Direction getDirection() {
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
index 9e7344eb5..fa649327f 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
@@ -21,8 +21,10 @@ import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.PacketCodec;
+import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
+import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
@@ -33,8 +35,9 @@ import io.netty.handler.codec.MessageToByteEncoder;
public class MinecraftEncoder extends MessageToByteEncoder {
private final ProtocolUtils.Direction direction;
+ private ProtocolVersion version;
private StateRegistry state;
- private StateRegistry.PacketRegistry.ProtocolRegistry registry;
+ private PacketRegistry registry;
/**
* Creates a new {@code MinecraftEncoder} encoding packets for the specified {@code direction}.
@@ -43,8 +46,8 @@ public class MinecraftEncoder extends MessageToByteEncoder {
*/
public MinecraftEncoder(ProtocolUtils.Direction direction) {
this.direction = Preconditions.checkNotNull(direction, "direction");
- this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry(
- direction, ProtocolVersion.MINIMUM_VERSION);
+ this.version = ProtocolVersion.MINIMUM_VERSION;
+ this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE;
}
@@ -52,13 +55,14 @@ public class MinecraftEncoder extends MessageToByteEncoder {
@SuppressWarnings("unchecked")
protected void encode(ChannelHandlerContext ctx, MinecraftPacket msg, ByteBuf out) {
PacketCodec codec = (PacketCodec) this.registry.getCodec(msg.getClass());
+ System.out.println(msg);
if (codec == null) {
throw new IllegalArgumentException("No codec found for packet: " + msg.getClass());
}
int packetId = this.registry.getPacketId(msg);
ProtocolUtils.writeVarInt(out, packetId);
- codec.encode(msg, out, direction, registry.version);
+ codec.encode(msg, out, direction, version);
}
@Override
@@ -71,7 +75,7 @@ public class MinecraftEncoder extends MessageToByteEncoder {
int hint = -1;
if (codec != null) {
- hint = codec.encodeSizeHint(msg, direction, registry.version);
+ hint = codec.encodeSizeHint(msg, direction, version);
}
if (hint < 0) {
@@ -84,12 +88,13 @@ public class MinecraftEncoder extends MessageToByteEncoder {
}
public void setProtocolVersion(final ProtocolVersion protocolVersion) {
- this.registry = state.getProtocolRegistry(direction, protocolVersion);
+ this.version = protocolVersion;
+ this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(protocolVersion);
}
public void setState(StateRegistry state) {
this.state = state;
- this.setProtocolVersion(registry.version);
+ this.registry = ProtocolStates.lookup(state, this.direction).forVersion(version);
}
public ProtocolUtils.Direction getDirection() {
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java
index e7af83458..0cedb7aac 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java
@@ -21,8 +21,10 @@ import static io.netty.util.ByteProcessor.FIND_NON_NUL;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.PacketCodec;
+import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
+import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import com.velocitypowered.proxy.util.except.QuietDecoderException;
import com.velocitypowered.proxy.util.except.QuietRuntimeException;
import io.netty.buffer.ByteBuf;
@@ -50,7 +52,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
new QuietDecoderException("Unknown packet");
private final ProtocolUtils.Direction direction;
- private final StateRegistry.PacketRegistry.ProtocolRegistry registry;
+ private final PacketRegistry registry;
private StateRegistry state;
/**
@@ -60,8 +62,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
*/
public MinecraftVarintFrameDecoder(ProtocolUtils.Direction direction) {
this.direction = direction;
- this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry(
- direction, ProtocolVersion.MINIMUM_VERSION);
+ this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE;
}
@@ -110,9 +111,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
}
private boolean validateServerboundHandshakePacket(ByteBuf in, int length) throws Exception {
- StateRegistry.PacketRegistry.ProtocolRegistry registry =
- state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
-
final int index = in.readerIndex();
final int packetId = readRawVarInt21(in);
// Index hasn't changed, we've read nothing
@@ -130,8 +128,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
// the packet if needed, so, we'll take advantage of the existing methods
- int expectedMinLen = codec.decodeExpectedMinLength(in, direction, registry.version);
- int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, registry.version);
+ int expectedMinLen = codec.decodeExpectedMinLength(in, direction, ProtocolVersion.MINIMUM_VERSION);
+ int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, ProtocolVersion.MINIMUM_VERSION);
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
throw handleOverflow(expectedMaxLen, in.readableBytes());
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java
index 1affc13bc..5d76d6eba 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java
@@ -19,8 +19,9 @@ package com.velocitypowered.proxy.protocol.netty;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
+import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
-import com.velocitypowered.proxy.protocol.StateRegistry;
+import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
@@ -41,7 +42,7 @@ import org.jetbrains.annotations.NotNull;
*/
public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler {
- private final StateRegistry.PacketRegistry.ProtocolRegistry registry;
+ private final PacketRegistry registry;
private final Queue