From f0fd904396a48ae327ac5198de504225adef8f47 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Fri, 5 Sep 2014 01:57:29 +0200 Subject: [PATCH] Adding support for retrieving the protocol version. --- .../comphenix/protocol/ProtocolManager.java | 10 ++- .../injector/DelayedPacketManager.java | 8 +++ .../injector/PacketFilterManager.java | 5 ++ .../injector/netty/ChannelInjector.java | 11 ++++ .../injector/netty/ClosedInjector.java | 5 ++ .../protocol/injector/netty/Injector.java | 6 ++ .../injector/netty/NettyProtocolInjector.java | 5 ++ .../player/PlayerInjectionHandler.java | 8 +++ .../player/ProxyPlayerInjectionHandler.java | 10 ++- .../injector/spigot/DummyPlayerHandler.java | 8 +++ .../protocol/reflect/accessors/Accessors.java | 21 ++++++ .../utility/MinecraftProtocolVersion.java | 65 +++++++++++++++++++ 12 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java index 52ce735c..e75ccd4a 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java @@ -41,7 +41,15 @@ import com.google.common.collect.ImmutableSet; * @author Kristian */ public interface ProtocolManager extends PacketStream { - + /** + * Retrieve the protocol version of a given player. + *

+ * This only really makes sense of a server that support clients of multiple Minecraft versions, such as Spigot #1628. + * @param player - the player. + * @return The associated protocol version, or {@link Integer#MIN_VALUE} if unknown. + */ + public int getProtocolVersion(Player player); + /** * Send a packet to the given player. *

diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java index 779f9d8b..e67be77f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java @@ -84,6 +84,14 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager { return delegate; } + @Override + public int getProtocolVersion(Player player) { + if (delegate != null) + return delegate.getProtocolVersion(player); + else + return Integer.MIN_VALUE; + } + @Override public MinecraftVersion getMinecraftVersion() { if (delegate != null) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index 937e287d..2199344f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -316,6 +316,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok return new PacketFilterBuilder(); } + @Override + public int getProtocolVersion(Player player) { + return playerInjection.getProtocolVersion(player); + } + @Override public MinecraftVersion getMinecraftVersion() { return minecraftVersion; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java index 79bfeb3d..fdfe560f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java @@ -48,6 +48,7 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.utility.MinecraftFields; import com.comphenix.protocol.utility.MinecraftMethods; +import com.comphenix.protocol.utility.MinecraftProtocolVersion; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Preconditions; import com.google.common.collect.MapMaker; @@ -60,6 +61,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector { public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet."); public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet."); public static final ReportType REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD = new ReportType("Cannot execute code in channel thread."); + public static final ReportType REPORT_CANNOT_FIND_GET_VERSION = new ReportType("Cannot find getVersion() in NetworkMananger"); /** * Indicates that a packet has bypassed packet listeners. @@ -158,6 +160,15 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector { getFieldByType("channel", Channel.class), networkManager, true); } + + /** + * Get the version of the current protocol. + * @return The version. + */ + @Override + public int getProtocolVersion() { + return MinecraftProtocolVersion.getCurrentVersion(); + } @Override @SuppressWarnings("unchecked") diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java index c65c97d2..ad61d630 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java @@ -79,4 +79,9 @@ class ClosedInjector implements Injector { public boolean isClosed() { return true; } + + @Override + public int getProtocolVersion() { + return Integer.MIN_VALUE; + } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java index 6059019f..81063bb6 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java @@ -10,6 +10,12 @@ import com.comphenix.protocol.events.NetworkMarker; * @author Kristian */ interface Injector { + /** + * Retrieve the current protocol version of the player. + * @return Protocol version. + */ + public abstract int getProtocolVersion(); + /** * Inject the current channel. *

diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java index ca169954..be71bbd6 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java @@ -301,6 +301,11 @@ public class NettyProtocolInjector implements ChannelListener { return new AbstractPlayerHandler(sendingFilters) { private ChannelListener listener = NettyProtocolInjector.this; + @Override + public int getProtocolVersion(Player player) { + return injectionFactory.fromPlayer(player, listener).getProtocolVersion(); + } + @Override public void updatePlayer(Player player) { injectionFactory.fromPlayer(player, listener).inject(); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java index 99acc7c2..eb8f5076 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java @@ -5,6 +5,7 @@ import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.net.InetSocketAddress; import java.util.Set; + import org.bukkit.entity.Player; import com.comphenix.protocol.PacketType; @@ -34,6 +35,13 @@ public interface PlayerInjectionHandler { BAIL_OUT; } + /** + * Retrieve the protocol version of the given player. + * @param player - the player. + * @return The protocol version, or {@link Integer#MIN_VALUE}. + */ + public abstract int getProtocolVersion(Player player); + /** * Retrieves how the server packets are read. * @return Injection method for reading server packets. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java index d4389724..c081ee0a 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java @@ -26,6 +26,7 @@ import java.net.Socket; import java.net.SocketAddress; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; @@ -35,6 +36,7 @@ import org.bukkit.Server; import org.bukkit.entity.Player; import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.PacketType.Sender; import com.comphenix.protocol.Packets; import com.comphenix.protocol.concurrency.BlockingHashMap; @@ -57,10 +59,10 @@ import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; import com.comphenix.protocol.injector.server.BukkitSocketInjector; import com.comphenix.protocol.injector.server.InputStreamLookupBuilder; import com.comphenix.protocol.injector.server.SocketInjector; +import com.comphenix.protocol.utility.MinecraftProtocolVersion; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.SafeCacheBuilder; - import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.collect.Maps; @@ -147,6 +149,12 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler { this.serverInjection = new InjectedServerConnection(reporter, inputStreamLookup, server, netLoginInjector); serverInjection.injectList(); } + + @Override + public int getProtocolVersion(Player player) { + // Just use the server version + return MinecraftProtocolVersion.getCurrentVersion(); + } /** * Retrieves how the server packets are read. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java index a713d09e..d92c77f9 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java @@ -7,10 +7,12 @@ import java.net.InetSocketAddress; import org.bukkit.entity.Player; import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.concurrency.PacketTypeSet; import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.utility.MinecraftProtocolVersion; /** * Dummy player handler that simply delegates to its parent Spigot packet injector. @@ -20,6 +22,12 @@ import com.comphenix.protocol.events.PacketEvent; class DummyPlayerHandler extends AbstractPlayerHandler { private SpigotPacketInjector injector; + @Override + public int getProtocolVersion(Player player) { + // Just use the server version + return MinecraftProtocolVersion.getCurrentVersion(); + } + public DummyPlayerHandler(SpigotPacketInjector injector, PacketTypeSet sendingFilters) { super(sendingFilters); this.injector = injector; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/accessors/Accessors.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/accessors/Accessors.java index d650e453..bd94432e 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/accessors/Accessors.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/accessors/Accessors.java @@ -4,6 +4,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; + import com.comphenix.protocol.reflect.ExactReflection; import com.comphenix.protocol.reflect.FuzzyReflection; import com.google.common.base.Joiner; @@ -197,6 +198,26 @@ public final class Accessors { return new SynchronizedFieldAccessor(accessor); } + /** + * Retrieve a method accessor that always return a constant value, regardless if input. + * @param returnValue - the constant return value. + * @param method - the method. + * @return A constant method accessor. + */ + public static MethodAccessor getConstantAccessor(final Object returnValue, final Method method) { + return new MethodAccessor() { + @Override + public Object invoke(Object target, Object... args) { + return returnValue; + } + + @Override + public Method getMethod() { + return method; + } + }; + } + /** * Retrieve a method accessor for a method with the given name and signature. * @param instanceClass - the parent class. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java new file mode 100644 index 00000000..865b6d27 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java @@ -0,0 +1,65 @@ +package com.comphenix.protocol.utility; + +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; + +import com.comphenix.protocol.ProtocolLibrary; +import com.google.common.collect.Maps; + +/** + * A lookup of the associated protocol version of a given Minecraft server. + * @author Kristian + */ +public class MinecraftProtocolVersion { + private static final NavigableMap lookup = createLookup(); + + private static NavigableMap createLookup() { + TreeMap map = Maps.newTreeMap(); + + // Source: http://wiki.vg/Protocol_version_numbers + // Doesn't include pre-releases + map.put(new MinecraftVersion(1, 0, 0), 22); + map.put(new MinecraftVersion(1, 1, 0), 23); + map.put(new MinecraftVersion(1, 2, 2), 28); + map.put(new MinecraftVersion(1, 2, 4), 29); + map.put(new MinecraftVersion(1, 3, 1), 39); + map.put(new MinecraftVersion(1, 4, 2), 47); + map.put(new MinecraftVersion(1, 4, 3), 48); + map.put(new MinecraftVersion(1, 4, 4), 49); + map.put(new MinecraftVersion(1, 4, 6), 51); + map.put(new MinecraftVersion(1, 5, 0), 60); + map.put(new MinecraftVersion(1, 5, 2), 61); + map.put(new MinecraftVersion(1, 6, 0), 72); + map.put(new MinecraftVersion(1, 6, 1), 73); + map.put(new MinecraftVersion(1, 6, 2), 74); + map.put(new MinecraftVersion(1, 6, 4), 78); + + // After Netty + map.put(new MinecraftVersion(1, 7, 1), 4); + map.put(new MinecraftVersion(1, 7, 6), 5); + map.put(new MinecraftVersion(1, 8, 0), 47); + + // Unknown number + map.put(new MinecraftVersion(1, 8, 1), Integer.MIN_VALUE); + return map; + } + + /** + * Retrieve the version of the Minecraft protocol for the current version of Minecraft. + * @return The version number. + */ + public static int getCurrentVersion() { + return getVersion(ProtocolLibrary.getProtocolManager().getMinecraftVersion()); + } + + /** + * Retrieve the version of the Minecraft protocol for this version of Minecraft. + * @param version - the version. + * @return The version number. + */ + public static int getVersion(MinecraftVersion version) { + Entry result = lookup.floorEntry(version); + return result != null ? result.getValue() : Integer.MIN_VALUE; + } +}