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