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