mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-24 03:25:29 +01:00
Added the ability to determine if any client or server packet is valid.
Also, added a warning when a plugin attempts to listen for a packet ID that doesn't exist in the current Minecraft version.
This commit is contained in:
parent
f8bd36bf3c
commit
6053b9e64b
@ -1,5 +1,9 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.IntEnum;
|
||||
|
||||
/**
|
||||
@ -92,6 +96,25 @@ public final class Packets {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given packet is a valid server packet in the current version of Minecraft.
|
||||
* @param packetID - the packet to test.
|
||||
* @return TRUE if this packet is supported, FALSE otherwise.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
public static boolean isSupported(int packetID) throws FieldAccessException {
|
||||
return PacketFilterManager.getServerPackets().contains(packetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every client packet the current version of Minecraft is aware of.
|
||||
* @return Every supported server packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getSupported() throws FieldAccessException {
|
||||
return PacketFilterManager.getServerPackets();
|
||||
}
|
||||
|
||||
// We only allow a single instance of this class
|
||||
private Server() {
|
||||
super();
|
||||
@ -146,6 +169,25 @@ public final class Packets {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given packet is a valid client packet in the current version of Minecraft.
|
||||
* @param packetID - the packet to test.
|
||||
* @return TRUE if this packet is supported, FALSE otherwise.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static boolean isSupported(int packetID) throws FieldAccessException {
|
||||
return PacketFilterManager.getClientPackets().contains(packetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every client packet the current version of Minecraft is aware of.
|
||||
* @return Every supported client packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getSupported() throws FieldAccessException {
|
||||
return PacketFilterManager.getClientPackets();
|
||||
}
|
||||
|
||||
// Like above
|
||||
private Client() {
|
||||
super();
|
||||
|
@ -19,13 +19,17 @@ package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.server.Packet;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Static registries in Minecraft.
|
||||
@ -35,9 +39,16 @@ import com.google.common.base.Objects;
|
||||
@SuppressWarnings("rawtypes")
|
||||
class MinecraftRegistry {
|
||||
|
||||
// Fuzzy reflection
|
||||
private static FuzzyReflection packetRegistry;
|
||||
|
||||
// The packet class to packet ID translator
|
||||
private static Map<Class, Integer> packetToID;
|
||||
|
||||
// Whether or not certain packets are sent by the client or the server
|
||||
private static Set<Integer> serverPackets;
|
||||
private static Set<Integer> clientPackets;
|
||||
|
||||
// New proxy values
|
||||
private static Map<Integer, Class> overwrittenPackets = new HashMap<Integer, Class>();
|
||||
|
||||
@ -49,7 +60,7 @@ class MinecraftRegistry {
|
||||
// Initialize it, if we haven't already
|
||||
if (packetToID == null) {
|
||||
try {
|
||||
Field packetsField = FuzzyReflection.fromClass(Packet.class, true).getFieldByType("packetsField", Map.class);
|
||||
Field packetsField = getPacketRegistry().getFieldByType("packetsField", Map.class);
|
||||
packetToID = (Map<Class, Integer>) FieldUtils.readStaticField(packetsField, true);
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
@ -60,14 +71,80 @@ class MinecraftRegistry {
|
||||
return packetToID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the cached fuzzy reflection instance allowing access to the packet registry.
|
||||
* @return Reflected packet registry.
|
||||
*/
|
||||
private static FuzzyReflection getPacketRegistry() {
|
||||
if (packetRegistry == null)
|
||||
packetRegistry = FuzzyReflection.fromClass(Packet.class, true);
|
||||
return packetRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the injected proxy classes handlig each packet ID.
|
||||
* @return Injected classes.
|
||||
*/
|
||||
public static Map<Integer, Class> getOverwrittenPackets() {
|
||||
return overwrittenPackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the vanilla classes handling each packet ID.
|
||||
* @return Vanilla classes.
|
||||
*/
|
||||
public static Map<Integer, Class> getPreviousPackets() {
|
||||
return previousValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported server packet.
|
||||
* @return An immutable set of every known server packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getServerPackets() throws FieldAccessException {
|
||||
initializeSets();
|
||||
return serverPackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported client packet.
|
||||
* @return An immutable set of every known client packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getClientPackets() throws FieldAccessException {
|
||||
initializeSets();
|
||||
return clientPackets;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void initializeSets() throws FieldAccessException {
|
||||
if (serverPackets == null || clientPackets == null) {
|
||||
List<Field> sets = getPacketRegistry().getFieldListByType(Set.class);
|
||||
|
||||
try {
|
||||
if (sets.size() > 1) {
|
||||
serverPackets = (Set<Integer>) FieldUtils.readStaticField(sets.get(0), true);
|
||||
clientPackets = (Set<Integer>) FieldUtils.readStaticField(sets.get(1), true);
|
||||
|
||||
// Impossible
|
||||
if (serverPackets == null || clientPackets == null)
|
||||
throw new FieldAccessException("Packet sets are in an illegal state.");
|
||||
|
||||
// NEVER allow callers to modify the underlying sets
|
||||
serverPackets = ImmutableSet.copyOf(serverPackets);
|
||||
clientPackets = ImmutableSet.copyOf(clientPackets);
|
||||
|
||||
} else {
|
||||
throw new FieldAccessException("Cannot retrieve packet client/server sets.");
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Cannot access field.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given packet ID.
|
||||
* @param packetID - the packet ID.
|
||||
|
@ -107,6 +107,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
// The async packet handler
|
||||
private AsyncFilterManager asyncFilterManager;
|
||||
|
||||
// Valid server and client packets
|
||||
private Set<Integer> serverPackets;
|
||||
private Set<Integer> clientPackets;
|
||||
|
||||
|
||||
/**
|
||||
* Only create instances of this class if protocol lib is disabled.
|
||||
*/
|
||||
@ -123,6 +128,15 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
this.playerInjection = new PlayerInjectionHandler(classLoader, logger, this, server);
|
||||
this.packetInjector = new PacketInjector(classLoader, this, playerInjection);
|
||||
this.asyncFilterManager = new AsyncFilterManager(logger, server.getScheduler(), this);
|
||||
|
||||
// Attempt to load the list of server and client packets
|
||||
try {
|
||||
this.serverPackets = MinecraftRegistry.getServerPackets();
|
||||
this.clientPackets = MinecraftRegistry.getClientPackets();
|
||||
} catch (FieldAccessException e) {
|
||||
logger.log(Level.WARNING, "Cannot load server and client packet list.", e);
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.log(Level.SEVERE, "Unable to initialize packet injector.", e);
|
||||
}
|
||||
@ -180,7 +194,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
if (hasSending) {
|
||||
verifyWhitelist(listener, sending);
|
||||
sendingListeners.addListener(listener, sending);
|
||||
enablePacketFilters(ConnectionSide.SERVER_SIDE, sending.getWhitelist());
|
||||
enablePacketFilters(listener, ConnectionSide.SERVER_SIDE, sending.getWhitelist());
|
||||
|
||||
// Make sure this is possible
|
||||
playerInjection.checkListener(listener);
|
||||
@ -188,7 +202,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
if (hasReceiving) {
|
||||
verifyWhitelist(listener, receiving);
|
||||
recievedListeners.addListener(listener, receiving);
|
||||
enablePacketFilters(ConnectionSide.CLIENT_SIDE, receiving.getWhitelist());
|
||||
enablePacketFilters(listener, ConnectionSide.CLIENT_SIDE, receiving.getWhitelist());
|
||||
}
|
||||
|
||||
// Inform our injected hooks
|
||||
@ -304,18 +318,39 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
* <p>
|
||||
* Note that all packets are disabled by default.
|
||||
*
|
||||
* @param listener - the listener that requested to enable these filters.
|
||||
* @param side - which side the event will arrive from.
|
||||
* @param packets - the packet id(s).
|
||||
*/
|
||||
private void enablePacketFilters(ConnectionSide side, Iterable<Integer> packets) {
|
||||
private void enablePacketFilters(PacketListener listener, ConnectionSide side, Iterable<Integer> packets) {
|
||||
if (side == null)
|
||||
throw new IllegalArgumentException("side cannot be NULL.");
|
||||
|
||||
// Note the difference between unsupported and valid.
|
||||
// Every packet ID between and including 0 - 255 is valid, but only a subset is supported.
|
||||
|
||||
for (int packetID : packets) {
|
||||
if (side.isForServer())
|
||||
playerInjection.addPacketHandler(packetID);
|
||||
if (side.isForClient() && packetInjector != null)
|
||||
packetInjector.addPacketHandler(packetID);
|
||||
// Only register server packets that are actually supported by Minecraft
|
||||
if (side.isForServer()) {
|
||||
if (serverPackets != null && serverPackets.contains(packetID))
|
||||
playerInjection.addPacketHandler(packetID);
|
||||
else
|
||||
logger.warning(String.format(
|
||||
"[%s] Unsupported server packet ID in current Minecraft version: %s",
|
||||
PacketAdapter.getPluginName(listener), packetID
|
||||
));
|
||||
}
|
||||
|
||||
// As above, only for client packets
|
||||
if (side.isForClient() && packetInjector != null) {
|
||||
if (clientPackets != null && clientPackets.contains(packetID))
|
||||
packetInjector.addPacketHandler(packetID);
|
||||
else
|
||||
logger.warning(String.format(
|
||||
"[%s] Unsupported client packet ID in current Minecraft version: %s",
|
||||
PacketAdapter.getPluginName(listener), packetID
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,6 +596,24 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported server packet.
|
||||
* @return An immutable set of every known server packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getServerPackets() throws FieldAccessException {
|
||||
return MinecraftRegistry.getServerPackets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported client packet.
|
||||
* @return An immutable set of every known client packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getClientPackets() throws FieldAccessException {
|
||||
return MinecraftRegistry.getClientPackets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current plugin class loader.
|
||||
* @return Class loader.
|
||||
@ -574,6 +627,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
return hasClosed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when ProtocolLib is closing.
|
||||
*/
|
||||
public void close() {
|
||||
// Guard
|
||||
if (hasClosed)
|
||||
|
@ -117,6 +117,10 @@ class PacketInjector {
|
||||
Map<Class, Integer> registry = MinecraftRegistry.getPacketToID();
|
||||
Class old = MinecraftRegistry.getPacketClassFromID(packetID);
|
||||
|
||||
// If this packet is not known
|
||||
if (old == null) {
|
||||
throw new IllegalStateException("Packet ID " + packetID + " is not a valid packet ID in this version.");
|
||||
}
|
||||
// Check for previous injections
|
||||
if (!old.getName().startsWith("net.minecraft.")) {
|
||||
throw new IllegalStateException("Packet " + packetID + " has already been injected.");
|
||||
|
Loading…
Reference in New Issue
Block a user