After Minecraft 1.4.4, CraftBukkit no longer redirects MAP_CHUNK.

We can therefore relax the requirements in NetworkFieldInjector and
NetworkObjectInjetor.
This commit is contained in:
Kristian S. Stangeland 2013-03-12 00:52:09 +01:00
parent a798147e71
commit 3c97cffc09
12 changed files with 96 additions and 34 deletions

View File

@ -43,6 +43,7 @@ import com.comphenix.protocol.metrics.Updater;
import com.comphenix.protocol.metrics.Updater.UpdateResult; import com.comphenix.protocol.metrics.Updater.UpdateResult;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.utility.ChatExtensions; import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.MinecraftVersion;
/** /**
* The main entry point for ProtocolLib. * The main entry point for ProtocolLib.
@ -132,12 +133,15 @@ public class ProtocolLibrary extends JavaPlugin {
// Check for other versions // Check for other versions
checkConflictingVersions(); checkConflictingVersions();
// Handle unexpected Minecraft versions
MinecraftVersion version = verifyMinecraftVersion();
// Set updater // Set updater
updater = new Updater(this, logger, "protocollib", getFile(), "protocol.info"); updater = new Updater(this, logger, "protocollib", getFile(), "protocol.info");
unhookTask = new DelayedSingleTask(this); unhookTask = new DelayedSingleTask(this);
protocolManager = new PacketFilterManager( protocolManager = new PacketFilterManager(
getClassLoader(), getServer(), unhookTask, detailedReporter); getClassLoader(), getServer(), version, unhookTask, detailedReporter);
// Setup error reporter // Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager); detailedReporter.addGlobalParameter("manager", protocolManager);
@ -249,9 +253,6 @@ public class ProtocolLibrary extends JavaPlugin {
logger.info("Structure compiler thread has been disabled."); logger.info("Structure compiler thread has been disabled.");
} }
// Handle unexpected Minecraft versions
verifyMinecraftVersion();
// Set up command handlers // Set up command handlers
registerCommand(CommandProtocol.NAME, commandProtocol); registerCommand(CommandProtocol.NAME, commandProtocol);
registerCommand(CommandPacket.NAME, commandPacket); registerCommand(CommandPacket.NAME, commandPacket);
@ -282,7 +283,7 @@ public class ProtocolLibrary extends JavaPlugin {
} }
// Used to check Minecraft version // Used to check Minecraft version
private void verifyMinecraftVersion() { private MinecraftVersion verifyMinecraftVersion() {
try { try {
MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION); MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION);
MinecraftVersion maximum = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION); MinecraftVersion maximum = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION);
@ -296,9 +297,14 @@ public class ProtocolLibrary extends JavaPlugin {
if (current.compareTo(maximum) > 0) if (current.compareTo(maximum) > 0)
logger.warning("Version " + current + " has not yet been tested! Proceed with caution."); logger.warning("Version " + current + " has not yet been tested! Proceed with caution.");
} }
return current;
} catch (Exception e) { } catch (Exception e) {
reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e); reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e);
} }
// Unknown version
return null;
} }
private void checkConflictingVersions() { private void checkConflictingVersions() {

View File

@ -61,6 +61,7 @@ import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -149,9 +150,15 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
/** /**
* Only create instances of this class if protocol lib is disabled. * Only create instances of this class if protocol lib is disabled.
* @param unhookTask
*/ */
public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, ErrorReporter reporter) { public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, ErrorReporter reporter) {
this(classLoader, server, new MinecraftVersion(server), unhookTask, reporter);
}
/**
* Only create instances of this class if protocol lib is disabled.
*/
public PacketFilterManager(ClassLoader classLoader, Server server, MinecraftVersion mcVersion, DelayedSingleTask unhookTask, ErrorReporter reporter) {
if (reporter == null) if (reporter == null)
throw new IllegalArgumentException("reporter cannot be NULL."); throw new IllegalArgumentException("reporter cannot be NULL.");
if (classLoader == null) if (classLoader == null)
@ -201,6 +208,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
classLoader(classLoader). classLoader(classLoader).
packetListeners(packetListeners). packetListeners(packetListeners).
injectionFilter(isInjectionNecessary). injectionFilter(isInjectionNecessary).
version(mcVersion).
buildHandler(); buildHandler();
this.packetInjector = PacketInjectorBuilder.newBuilder(). this.packetInjector = PacketInjectorBuilder.newBuilder().
@ -561,7 +569,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
return; return;
} }
playerInjection.processPacket(sender, mcPacket); playerInjection.recieveClientPacket(sender, mcPacket);
} }
@Override @Override

View File

@ -39,6 +39,7 @@ import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
@ -56,6 +57,12 @@ class NetworkFieldInjector extends PlayerInjector {
// Nothing // Nothing
} }
// After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.),
// CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue.
// Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets
// will be slightly processed).
private MinecraftVersion safeVersion = new MinecraftVersion("1.4.4");
// Packets to ignore // Packets to ignore
private Set<Object> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Object, Boolean>()); private Set<Object> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Object, Boolean>());
@ -99,7 +106,6 @@ class NetworkFieldInjector extends PlayerInjector {
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
if (networkManager != null) { if (networkManager != null) {
try { try {
if (!filtered) { if (!filtered) {
@ -122,14 +128,19 @@ class NetworkFieldInjector extends PlayerInjector {
} }
@Override @Override
public UnsupportedListener checkListener(PacketListener listener) { public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) {
int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK }; if (version != null && version.compareTo(safeVersion) > 0) {
// Unfortunately, we don't support chunk packets
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) {
return new UnsupportedListener("The NETWORK_FIELD_INJECTOR hook doesn't support map chunk listeners.", unsupported);
} else {
return null; return null;
} else {
int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK };
// Unfortunately, we don't support chunk packets
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) {
return new UnsupportedListener("The NETWORK_FIELD_INJECTOR hook doesn't support map chunk listeners.", unsupported);
} else {
return null;
}
} }
} }

View File

@ -40,6 +40,7 @@ import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.utility.MinecraftVersion;
/** /**
* Injection method that overrides the NetworkHandler itself, and its queue-method. * Injection method that overrides the NetworkHandler itself, and its queue-method.
@ -53,6 +54,12 @@ public class NetworkObjectInjector extends PlayerInjector {
// Used to construct proxy objects // Used to construct proxy objects
private ClassLoader classLoader; private ClassLoader classLoader;
// After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.),
// CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue.
// Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets
// will be slightly processed).
private MinecraftVersion safeVersion = new MinecraftVersion("1.4.4");
// Shared callback filter - avoid creating a new class every time // Shared callback filter - avoid creating a new class every time
private volatile static CallbackFilter callbackFilter; private volatile static CallbackFilter callbackFilter;
@ -117,14 +124,19 @@ public class NetworkObjectInjector extends PlayerInjector {
} }
@Override @Override
public UnsupportedListener checkListener(PacketListener listener) { public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) {
int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK }; if (version != null && version.compareTo(safeVersion) > 0) {
// Unfortunately, we don't support chunk packets
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) {
return new UnsupportedListener("The NETWORK_OBJECT_INJECTOR hook doesn't support map chunk listeners.", unsupported);
} else {
return null; return null;
} else {
int[] unsupported = { Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK };
// Unfortunately, we don't support chunk packets
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(), unsupported)) {
return new UnsupportedListener("The NETWORK_OBJECT_INJECTOR hook doesn't support map chunk listeners.", unsupported);
} else {
return null;
}
} }
} }

View File

@ -40,6 +40,7 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.reflect.instances.ExistingGenerator; import com.comphenix.protocol.reflect.instances.ExistingGenerator;
import com.comphenix.protocol.utility.MinecraftMethods; import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
/** /**
* Represents a player hook into the NetServerHandler class. * Represents a player hook into the NetServerHandler class.
@ -326,7 +327,7 @@ class NetworkServerInjector extends PlayerInjector {
} }
@Override @Override
public UnsupportedListener checkListener(PacketListener listener) { public UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener) {
// We support everything // We support everything
return null; return null;
} }

View File

@ -126,11 +126,12 @@ public interface PlayerInjectionHandler {
* @throws IllegalAccessException If the reflection machinery failed. * @throws IllegalAccessException If the reflection machinery failed.
* @throws InvocationTargetException If the underlying method caused an error. * @throws InvocationTargetException If the underlying method caused an error.
*/ */
public abstract void processPacket(Player player, Object mcPacket) public abstract void recieveClientPacket(Player player, Object mcPacket)
throws IllegalAccessException, InvocationTargetException; throws IllegalAccessException, InvocationTargetException;
/** /**
* Determine if the given listeners are valid. * Determine if the given listeners are valid.
* @param version - the current Minecraft version, or NULL if unknown.
* @param listeners - listeners to check. * @param listeners - listeners to check.
*/ */
public abstract void checkListener(Set<PacketListener> listeners); public abstract void checkListener(Set<PacketListener> listeners);
@ -139,6 +140,7 @@ public interface PlayerInjectionHandler {
* Determine if a listener is valid or not. * Determine if a listener is valid or not.
* <p> * <p>
* If not, a warning will be printed to the console. * If not, a warning will be printed to the console.
* @param version - the current Minecraft version, or NULL if unknown.
* @param listener - listener to check. * @param listener - listener to check.
*/ */
public abstract void checkListener(PacketListener listener); public abstract void checkListener(PacketListener listener);

View File

@ -43,6 +43,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
abstract class PlayerInjector implements SocketInjector { abstract class PlayerInjector implements SocketInjector {
@ -508,11 +509,13 @@ abstract class PlayerInjector implements SocketInjector {
* Invoked before a new listener is registered. * Invoked before a new listener is registered.
* <p> * <p>
* The player injector should only return a non-null value if some or all of the packet IDs are unsupported. * The player injector should only return a non-null value if some or all of the packet IDs are unsupported.
* @param version
* *
* @param version - the current Minecraft version, or NULL if unknown.
* @param listener - the listener that is about to be registered. * @param listener - the listener that is about to be registered.
* @return A error message with the unsupported packet IDs, or NULL if this listener is valid. * @return A error message with the unsupported packet IDs, or NULL if this listener is valid.
*/ */
public abstract UnsupportedListener checkListener(PacketListener listener); public abstract UnsupportedListener checkListener(MinecraftVersion version, PacketListener listener);
/** /**
* Allows a packet to be sent by the listeners. * Allows a packet to be sent by the listeners.

View File

@ -14,6 +14,7 @@ import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PacketFilterManager; import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -37,6 +38,7 @@ public class PlayerInjectorBuilder {
protected ListenerInvoker invoker; protected ListenerInvoker invoker;
protected Set<PacketListener> packetListeners; protected Set<PacketListener> packetListeners;
protected Server server; protected Server server;
protected MinecraftVersion version;
/** /**
* Set the class loader to use during class generation. * Set the class loader to use during class generation.
@ -107,6 +109,16 @@ public class PlayerInjectorBuilder {
return this; return this;
} }
/**
* Set the current Minecraft version.
* @param server - the current Minecraft version, or NULL if unknown.
* @return This builder, for chaining.
*/
public PlayerInjectorBuilder version(MinecraftVersion version) {
this.version = version;
return this;
}
/** /**
* Called before an object is created with this builder. * Called before an object is created with this builder.
*/ */
@ -140,6 +152,6 @@ public class PlayerInjectorBuilder {
return new ProxyPlayerInjectionHandler( return new ProxyPlayerInjectionHandler(
classLoader, reporter, injectionFilter, classLoader, reporter, injectionFilter,
invoker, packetListeners, server); invoker, packetListeners, server, version);
} }
} }

View File

@ -45,6 +45,7 @@ import com.comphenix.protocol.injector.server.AbstractInputStreamLookup;
import com.comphenix.protocol.injector.server.InputStreamLookupBuilder; import com.comphenix.protocol.injector.server.InputStreamLookupBuilder;
import com.comphenix.protocol.injector.server.SocketInjector; import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
@ -91,6 +92,9 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
// Used to invoke events // Used to invoke events
private ListenerInvoker invoker; private ListenerInvoker invoker;
// Current Minecraft version
private MinecraftVersion version;
// Enabled packet filters // Enabled packet filters
private IntegerSet sendingFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1); private IntegerSet sendingFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1);
@ -105,13 +109,14 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
public ProxyPlayerInjectionHandler( public ProxyPlayerInjectionHandler(
ClassLoader classLoader, ErrorReporter reporter, Predicate<GamePhase> injectionFilter, ClassLoader classLoader, ErrorReporter reporter, Predicate<GamePhase> injectionFilter,
ListenerInvoker invoker, Set<PacketListener> packetListeners, Server server) { ListenerInvoker invoker, Set<PacketListener> packetListeners, Server server, MinecraftVersion version) {
this.classLoader = classLoader; this.classLoader = classLoader;
this.reporter = reporter; this.reporter = reporter;
this.invoker = invoker; this.invoker = invoker;
this.injectionFilter = injectionFilter; this.injectionFilter = injectionFilter;
this.packetListeners = packetListeners; this.packetListeners = packetListeners;
this.version = version;
this.inputStreamLookup = InputStreamLookupBuilder.newBuilder(). this.inputStreamLookup = InputStreamLookupBuilder.newBuilder().
server(server). server(server).
@ -501,14 +506,14 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
} }
/** /**
* Process a packet as if it were sent by the given player. * Recieve a packet as if it were sent by the given player.
* @param player - the sender. * @param player - the sender.
* @param mcPacket - the packet to process. * @param mcPacket - the packet to process.
* @throws IllegalAccessException If the reflection machinery failed. * @throws IllegalAccessException If the reflection machinery failed.
* @throws InvocationTargetException If the underlying method caused an error. * @throws InvocationTargetException If the underlying method caused an error.
*/ */
@Override @Override
public void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
PlayerInjector injector = getInjector(player); PlayerInjector injector = getInjector(player);
// Process the given packet, or simply give up // Process the given packet, or simply give up
@ -619,7 +624,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
@Override @Override
public void checkListener(PacketListener listener) { public void checkListener(PacketListener listener) {
if (lastSuccessfulHook != null) { if (lastSuccessfulHook != null) {
UnsupportedListener result = lastSuccessfulHook.checkListener(listener); UnsupportedListener result = lastSuccessfulHook.checkListener(version, listener);
// We won't prevent the listener, as it may still have valid packets // We won't prevent the listener, as it may still have valid packets
if (result != null) { if (result != null) {

View File

@ -74,7 +74,7 @@ class DummyPlayerHandler implements PlayerInjectionHandler {
} }
@Override @Override
public void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
injector.processPacket(player, mcPacket); injector.processPacket(player, mcPacket);
} }

View File

@ -15,7 +15,7 @@
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol; package com.comphenix.protocol.utility;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -31,7 +31,7 @@ import com.google.common.collect.Ordering;
* *
* @author Kristian * @author Kristian
*/ */
class MinecraftVersion implements Comparable<MinecraftVersion> { public class MinecraftVersion implements Comparable<MinecraftVersion> {
/** /**
* Regular expression used to parse version strings. * Regular expression used to parse version strings.
*/ */

View File

@ -21,6 +21,8 @@ import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import com.comphenix.protocol.utility.MinecraftVersion;
public class MinecraftVersionTest { public class MinecraftVersionTest {
@Test @Test