Ensure that server operators are informed about incompatibility.
Dieser Commit ist enthalten in:
Ursprung
9efb85e7c3
Commit
90970d1b9b
@ -86,6 +86,23 @@ public class ListeningWhitelist {
|
||||
return Objects.hashCode(priority, whitelist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any of the given IDs can be found in the whitelist.
|
||||
* @param whitelist - whitelist to test.
|
||||
* @param idList - list of packet IDs to find.
|
||||
* @return TRUE if any of the packets in the list can be found in the whitelist, FALSE otherwise.
|
||||
*/
|
||||
public static boolean containsAny(ListeningWhitelist whitelist, int... idList) {
|
||||
if (whitelist != null) {
|
||||
for (int i = 0; i < idList.length; i++) {
|
||||
if (whitelist.getWhitelist().contains(idList[i]))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj){
|
||||
if(obj instanceof ListeningWhitelist){
|
||||
|
@ -10,6 +10,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@ -83,11 +86,13 @@ class NetworkFieldInjector extends PlayerInjector {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
// Probably
|
||||
return true;
|
||||
public void checkListener(PacketListener listener) {
|
||||
// Unfortunately, we don't support chunk packets
|
||||
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(),
|
||||
Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK)) {
|
||||
throw new IllegalStateException("The NETWORK_FIELD_INJECTOR hook doesn't support map chunk listeners.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,10 @@ import java.util.Set;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
|
||||
/**
|
||||
* Injection method that overrides the NetworkHandler itself, and it's sendPacket-method.
|
||||
*
|
||||
@ -43,11 +47,12 @@ class NetworkObjectInjector extends PlayerInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
// We only support 1.3.0 at the moment. Fixing it require us to
|
||||
// add jMock, which would add another dependency.
|
||||
return networkManager != null &&
|
||||
networkManagerField.getType().isInterface();
|
||||
public void checkListener(PacketListener listener) {
|
||||
// Unfortunately, we don't support chunk packets
|
||||
if (ListeningWhitelist.containsAny(listener.getSendingWhitelist(),
|
||||
Packets.Server.MAP_CHUNK, Packets.Server.MAP_CHUNK_BULK)) {
|
||||
throw new IllegalStateException("The NETWORK_FIELD_INJECTOR hook doesn't support map chunk listeners.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,6 +12,7 @@ import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.instances.CollectionGenerator;
|
||||
@ -66,6 +67,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
|
||||
@Override
|
||||
public void injectManager() {
|
||||
|
||||
if (serverHandlerRef == null)
|
||||
throw new IllegalStateException("Cannot find server handler.");
|
||||
// Don't inject twice
|
||||
@ -144,8 +146,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInject() {
|
||||
// Probably always
|
||||
return true;
|
||||
public void checkListener(PacketListener listener) {
|
||||
// We support everything
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
NETWORK_MANAGER_OBJECT,
|
||||
|
||||
/**
|
||||
* Override the server handler object. Versatile, but slow.
|
||||
* Override the server handler object. Versatile, but a tad slower.
|
||||
*/
|
||||
NETWORK_SERVER_OBJECT;
|
||||
}
|
||||
@ -106,6 +106,9 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
// The default class loader
|
||||
private ClassLoader classLoader;
|
||||
|
||||
// The last successful player hook
|
||||
private PlayerInjector lastSuccessfulHook;
|
||||
|
||||
// Error logger
|
||||
private Logger logger;
|
||||
|
||||
@ -142,6 +145,13 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
*/
|
||||
public void setPlayerHook(PlayerInjectHooks playerHook) {
|
||||
this.playerHook = playerHook;
|
||||
|
||||
// Make sure the current listeners are compatible
|
||||
if (lastSuccessfulHook != null) {
|
||||
for (PacketListener listener : packetListeners) {
|
||||
checkListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Logger getLogger() {
|
||||
@ -176,6 +186,9 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
if (hasReceiving) {
|
||||
recievedListeners.addListener(listener, receiving);
|
||||
enablePacketFilters(ConnectionSide.CLIENT_SIDE, receiving.getWhitelist());
|
||||
|
||||
// We don't know if we've hooked any players yet
|
||||
checkListener(listener);
|
||||
}
|
||||
|
||||
// Inform our injected hooks
|
||||
@ -183,6 +196,20 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a listener is valid or not.
|
||||
* @param listener - listener to check.
|
||||
* @throws IllegalStateException If the given listener's whitelist cannot be fulfilled.
|
||||
*/
|
||||
public void checkListener(PacketListener listener) {
|
||||
try {
|
||||
if (lastSuccessfulHook != null)
|
||||
lastSuccessfulHook.checkListener(listener);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Registering listener " + PacketAdapter.getPluginName(listener) + " failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePacketListener(PacketListener listener) {
|
||||
if (listener == null)
|
||||
@ -367,15 +394,11 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
/**
|
||||
* Used to construct a player hook.
|
||||
* @param player - the player to hook.
|
||||
* @param hook - the hook type.
|
||||
* @return A new player hoook
|
||||
* @throws IllegalAccessException Unable to do our reflection magic.
|
||||
*/
|
||||
protected PlayerInjector getPlayerHookInstance(Player player) throws IllegalAccessException {
|
||||
return getHookInstance(player, playerHook);
|
||||
}
|
||||
|
||||
// Helper
|
||||
private PlayerInjector getHookInstance(Player player, PlayerInjectHooks hook) throws IllegalAccessException {
|
||||
protected PlayerInjector getHookInstance(Player player, PlayerInjectHooks hook) throws IllegalAccessException {
|
||||
// Construct the correct player hook
|
||||
switch (hook) {
|
||||
case NETWORK_HANDLER_FIELDS:
|
||||
@ -394,23 +417,45 @@ public final class PacketFilterManager implements ProtocolManager {
|
||||
* @param player - player to hook.
|
||||
*/
|
||||
protected void injectPlayer(Player player) {
|
||||
|
||||
PlayerInjector injector = null;
|
||||
PlayerInjectHooks currentHook = playerHook;
|
||||
boolean firstPlayer = lastSuccessfulHook == null;
|
||||
|
||||
// Don't inject if the class has closed
|
||||
if (!hasClosed && player != null && !playerInjection.containsKey(player)) {
|
||||
while (true) {
|
||||
try {
|
||||
PlayerInjector injector = getPlayerHookInstance(player);
|
||||
|
||||
injector = getHookInstance(player, currentHook);
|
||||
injector.injectManager();
|
||||
playerInjection.put(player, injector);
|
||||
connectionLookup.put(injector.getInputStream(false), player);
|
||||
break;
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
} catch (Exception e) {
|
||||
// Mark this injection attempt as a failure
|
||||
logger.log(Level.SEVERE, "Player hook " + currentHook.toString() + " failed.", e);
|
||||
|
||||
if (currentHook.ordinal() > 0) {
|
||||
// Choose the previous player hook type
|
||||
currentHook = PlayerInjectHooks.values()[currentHook.ordinal() - 1];
|
||||
logger.log(Level.INFO, "Switching to " + currentHook.toString() + " instead.");
|
||||
} else {
|
||||
// UTTER FAILURE
|
||||
playerInjection.put(player, null);
|
||||
logger.log(Level.SEVERE, "Unable to access fields.", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update values
|
||||
if (injector != null)
|
||||
lastSuccessfulHook = injector;
|
||||
if (currentHook != playerHook || firstPlayer)
|
||||
setPlayerHook(currentHook);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this protocol manager on Bukkit.
|
||||
* @param manager - Bukkit plugin manager that provides player join/leave events.
|
||||
|
@ -31,6 +31,7 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@ -205,10 +206,12 @@ abstract class PlayerInjector {
|
||||
public abstract void cleanupAll();
|
||||
|
||||
/**
|
||||
* Determine if we actually can inject.
|
||||
* @return TRUE if this injector is compatible with the current CraftBukkit version, FALSE otherwise.
|
||||
* Invoked before a new listener is registered.
|
||||
* <p>
|
||||
* The player injector should throw an exception if this listener cannot be properly supplied with packet events.
|
||||
* @param listener - the listener that is about to be registered.
|
||||
*/
|
||||
public abstract boolean canInject();
|
||||
public abstract void checkListener(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Allows a packet to be recieved by the listeners.
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren