Adding support for retrieving the protocol version.

This commit is contained in:
Kristian S. Stangeland 2014-09-05 01:57:29 +02:00
parent b901f029d2
commit f0fd904396
12 changed files with 160 additions and 2 deletions

View File

@ -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.
* <p>
* 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.
* <p>

View File

@ -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)

View File

@ -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;

View File

@ -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")

View File

@ -79,4 +79,9 @@ class ClosedInjector implements Injector {
public boolean isClosed() {
return true;
}
@Override
public int getProtocolVersion() {
return Integer.MIN_VALUE;
}
}

View File

@ -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.
* <p>

View File

@ -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();

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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<MinecraftVersion, Integer> lookup = createLookup();
private static NavigableMap<MinecraftVersion, Integer> createLookup() {
TreeMap<MinecraftVersion, Integer> 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<MinecraftVersion, Integer> result = lookup.floorEntry(version);
return result != null ? result.getValue() : Integer.MIN_VALUE;
}
}