diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java index 59d20f47..fb700f25 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java @@ -17,6 +17,10 @@ package com.comphenix.protocol; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; + import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -84,27 +88,38 @@ abstract class CommandBase implements CommandExecutor { } /** - * Parse a boolean value at a specific location. - * @param args - the argument array. - * @param parameterName - the parameter name. - * @param index - the argument index. + * Parse a boolean value at the head of the queue. + * @param arguments - the queue of arguments. + * @param parameterName - the parameter name we will match. * @return The parsed boolean, or NULL if not valid. */ - protected Boolean parseBoolean(String[] args, String parameterName, int index) { - if (index < args.length) { - String arg = args[index]; + protected Boolean parseBoolean(Deque arguments, String parameterName) { + Boolean result = null; + + if (!arguments.isEmpty()) { + String arg = arguments.peek(); if (arg.equalsIgnoreCase("true") || arg.equalsIgnoreCase("on")) - return true; + result = true; else if (arg.equalsIgnoreCase(parameterName)) - return true; + result = true; else if (arg.equalsIgnoreCase("false") || arg.equalsIgnoreCase("off")) - return false; - else - return null; - } else { - return null; + result = false; } + + if (result != null) + arguments.poll(); + return result; + } + + /** + * Create a queue from a sublist of a given array. + * @param args - the source array. + * @param start - the starting index. + * @return A queue that contains every element in the array, starting at the given index. + */ + protected Deque toQueue(String[] args, int start) { + return new ArrayDeque(Arrays.asList(args).subList(start, args.length)); } /** diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandFilter.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandFilter.java index 0147d8be..bbbcf323 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandFilter.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandFilter.java @@ -1,7 +1,7 @@ package com.comphenix.protocol; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -22,14 +22,11 @@ import org.bukkit.conversations.ConversationFactory; import org.bukkit.plugin.Plugin; import com.comphenix.protocol.MultipleLinesPrompt.MultipleConversationCanceller; -import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.events.PacketEvent; -import com.google.common.collect.DiscreteDomains; -import com.google.common.collect.Range; -import com.google.common.collect.Ranges; +import com.google.common.collect.Sets; /** * A command to apply JavaScript filtering to the packet command. @@ -71,19 +68,18 @@ public class CommandFilter extends CommandBase { private final String name; private final String predicate; - private final IntegerSet ranges; + private final Set packets; /** * Construct a new immutable filter. * @param name - the unique name of the filter. * @param predicate - the JavaScript predicate that will be used to filter packet events. - * @param packets - a list of valid packet ID that this filter applies to. + * @param packets - a list of packet types this filter applies to. */ - public Filter(String name, String predicate, Set packets) { + public Filter(String name, String predicate, Set packets) { this.name = name; this.predicate = predicate; - this.ranges = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1); - this.ranges.addAll(packets); + this.packets = Sets.newHashSet(packets); } /** @@ -106,8 +102,8 @@ public class CommandFilter extends CommandBase { * Retrieve a copy of the set of packets this filter applies to. * @return Set of packets this filter applies to. */ - public Set getRanges() { - return ranges.toSet(); + public Set getRanges() { + return Sets.newHashSet(packets); } /** @@ -116,7 +112,7 @@ public class CommandFilter extends CommandBase { * @return TRUE if it does, FALSE otherwise. */ private boolean isApplicable(PacketEvent event) { - return ranges.contains(event.getPacketID()); + return packets.contains(event.getPacketType()); } /** @@ -384,7 +380,11 @@ public class CommandFilter extends CommandBase { return true; } - final Set packets = parseRanges(args, 2); + // Prepare the input to the packet type parser + Deque rangeArguments = toQueue(args, 2); + + final PacketTypeParser parser = new PacketTypeParser(); + final Set packets = parser.parseTypes(rangeArguments, PacketTypeParser.DEFAULT_MAX_RANGE); sender.sendMessage("Enter filter program ('}' to complete or CANCEL):"); // Make sure we can use the conversable interface @@ -455,22 +455,6 @@ public class CommandFilter extends CommandBase { return true; } - private Set parseRanges(String[] args, int start) { - List> ranges = RangeParser.getRanges(args, 2, args.length - 1, Ranges.closed(0, 255)); - Set flatten = new HashSet(); - - if (ranges.isEmpty()) { - // Use every packet ID - ranges.add(Ranges.closed(0, 255)); - } - - // Finally, flatten it all - for (Range range : ranges) { - flatten.addAll(range.asSet(DiscreteDomains.integers())); - } - return flatten; - } - /** * Lookup a filter by its name. * @param name - the filter name. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java index 60c62025..f34b774d 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java @@ -18,8 +18,10 @@ package com.comphenix.protocol; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Arrays; +import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Set; @@ -34,26 +36,20 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import com.comphenix.protocol.concurrency.AbstractIntervalTree; +import com.comphenix.protocol.PacketType.Sender; +import com.comphenix.protocol.concurrency.PacketTypeSet; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; -import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.reflect.EquivalentConverter; -import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.PrettyPrinter; import com.comphenix.protocol.reflect.PrettyPrinter.ObjectPrinter; import com.comphenix.protocol.utility.ChatExtensions; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.wrappers.BukkitConverters; -import com.google.common.collect.DiscreteDomains; -import com.google.common.collect.Range; -import com.google.common.collect.Ranges; import com.google.common.collect.Sets; /** @@ -63,15 +59,7 @@ import com.google.common.collect.Sets; */ class CommandPacket extends CommandBase { public static final ReportType REPORT_CANNOT_SEND_MESSAGE = new ReportType("Cannot send chat message."); - - private interface DetailedPacketListener extends PacketListener { - /** - * Determine whether or not the given packet listener is detailed or not. - * @return TRUE if it is detailed, FALSE otherwise. - */ - public boolean isDetailed(); - } - + private enum SubCommand { ADD, REMOVE, NAMES, PAGE; } @@ -92,12 +80,18 @@ class CommandPacket extends CommandBase { private ChatExtensions chatter; + // The main parser + private PacketTypeParser typeParser = new PacketTypeParser(); + // Paged message private Map> pagedMessage = new WeakHashMap>(); - // Registered packet listeners - private AbstractIntervalTree clientListeners = createTree(ConnectionSide.CLIENT_SIDE); - private AbstractIntervalTree serverListeners = createTree(ConnectionSide.SERVER_SIDE); + // Current registered packet types + private PacketTypeSet packetTypes = new PacketTypeSet(); + private PacketTypeSet extendedTypes = new PacketTypeSet(); + + // The packet listener + private PacketListener listener; // Filter packet events private CommandFilter filter; @@ -110,58 +104,7 @@ class CommandPacket extends CommandBase { this.filter = filter; this.chatter = new ChatExtensions(manager); } - - /** - * Construct a packet listener interval tree. - * @return Construct the tree. - */ - private AbstractIntervalTree createTree(final ConnectionSide side) { - return new AbstractIntervalTree() { - @Override - protected Integer decrementKey(Integer key) { - return key != null ? key - 1 : null; - } - - @Override - protected Integer incrementKey(Integer key) { - return key != null ? key + 1 : null; - } - - @Override - protected void onEntryAdded(Entry added) { - // Ensure that the starting ID and the ending ID is correct - // This is necessary because the interval tree may change the range. - if (added != null) { - Range key = added.getKey(); - DetailedPacketListener listener = added.getValue(); - DetailedPacketListener corrected = createPacketListener( - side, key.lowerEndpoint(), key.upperEndpoint(), listener.isDetailed()); - - added.setValue(corrected); - - if (corrected != null) { - manager.addPacketListener(corrected); - } else { - // Never mind - remove(key.lowerEndpoint(), key.upperEndpoint()); - } - } - } - - @Override - protected void onEntryRemoved(Entry removed) { - // Remove the listener - if (removed != null) { - DetailedPacketListener listener = removed.getValue(); - - if (listener != null) { - manager.removePacketListener(listener); - } - } - } - }; - } - + /** * Send a message without invoking the packet listeners. * @param receiver - the player to send it to. @@ -223,8 +166,9 @@ class CommandPacket extends CommandBase { @Override protected boolean handleCommand(CommandSender sender, String[] args) { try { - SubCommand subCommand = parseCommand(args, 0); - + Deque arguments = new ArrayDeque(Arrays.asList(args)); + SubCommand subCommand = parseCommand(arguments); + // Commands with different parameters if (subCommand == SubCommand.PAGE) { int page = Integer.parseInt(args[1]); @@ -236,26 +180,18 @@ class CommandPacket extends CommandBase { return true; } - ConnectionSide side = parseSide(args, 1, ConnectionSide.BOTH); + Set types = typeParser.parseTypes(arguments, PacketTypeParser.DEFAULT_MAX_RANGE); + Boolean detailed = parseBoolean(arguments, "detailed"); - Integer lastIndex = args.length - 1; - Boolean detailed = parseBoolean(args, "detailed", lastIndex); - - // See if the last element is a boolean + if (arguments.size() > 0) { + throw new IllegalArgumentException("Insufficient arguments."); + } + + // The last element is optional if (detailed == null) { detailed = false; - } else { - lastIndex--; } - - // Make sure the packet IDs are valid - List> ranges = RangeParser.getRanges(args, 2, lastIndex, Ranges.closed(0, 255)); - if (ranges.isEmpty()) { - // Use every packet ID - ranges.add(Ranges.closed(0, 255)); - } - // Perform commands if (subCommand == SubCommand.ADD) { // The add command is dangerous - don't default on the connection side @@ -264,11 +200,11 @@ class CommandPacket extends CommandBase { return false; } - executeAddCommand(sender, side, detailed, ranges); + executeAddCommand(sender, types, detailed); } else if (subCommand == SubCommand.REMOVE) { - executeRemoveCommand(sender, side, detailed, ranges); + executeRemoveCommand(sender, types); } else if (subCommand == SubCommand.NAMES) { - executeNamesCommand(sender, side, ranges); + executeNamesCommand(sender, types); } } catch (NumberFormatException e) { @@ -279,36 +215,31 @@ class CommandPacket extends CommandBase { return true; } - - private void executeAddCommand(CommandSender sender, ConnectionSide side, Boolean detailed, List> ranges) { - for (Range range : ranges) { - DetailedPacketListener listener = addPacketListeners(side, range.lowerEndpoint(), range.upperEndpoint(), detailed); - sendMessageSilently(sender, ChatColor.BLUE + "Added listener " + getWhitelistInfo(listener)); + + private void executeAddCommand(CommandSender sender, Set addition, boolean detailed) { + packetTypes.addAll(addition); + + // Also mark these types as "detailed" + if (detailed) { + extendedTypes.addAll(addition); } + updatePacketListener(); + sendMessageSilently(sender, ChatColor.BLUE + "Added listener " + getWhitelistInfo(listener)); } - private void executeRemoveCommand(CommandSender sender, ConnectionSide side, Boolean detailed, List> ranges) { - int count = 0; - - // Remove each packet listener - for (Range range : ranges) { - count += removePacketListeners(side, range.lowerEndpoint(), range.upperEndpoint(), detailed).size(); - } - - sendMessageSilently(sender, ChatColor.BLUE + "Fully removed " + count + " listeners."); + private void executeRemoveCommand(CommandSender sender, Set removal) { + packetTypes.removeAll(removal); + extendedTypes.removeAll(removal); + updatePacketListener(); + sendMessageSilently(sender, ChatColor.BLUE + "Removing packet types."); } - private void executeNamesCommand(CommandSender sender, ConnectionSide side, List> ranges) { - Set named = getNamedPackets(side); + private void executeNamesCommand(CommandSender sender, Set types) { List messages = new ArrayList(); // Print the equivalent name of every given ID - for (Range range : ranges) { - for (int id : range.asSet(DiscreteDomains.integers())) { - if (named.contains(id)) { - messages.add(ChatColor.WHITE + "" + id + ": " + ChatColor.BLUE + Packets.getDeclaredName(id)); - } - } + for (PacketType type : types) { + messages.add(ChatColor.BLUE + type.toString()); } if (sender instanceof Player && messages.size() > 0 && messages.size() > PAGE_LINE_COUNT) { @@ -342,90 +273,58 @@ class CommandPacket extends CommandBase { else return "[None]"; } - - private Set getValidPackets(ConnectionSide side) throws FieldAccessException { - HashSet supported = Sets.newHashSet(); - if (side.isForClient()) - supported.addAll(Packets.Client.getSupported()); - else if (side.isForServer()) - supported.addAll(Packets.Server.getSupported()); + private Set filterTypes(Set types, Sender sender) { + Set result = Sets.newHashSet(); - return supported; - } - - private Set getNamedPackets(ConnectionSide side) { - - Set valids = null; - Set result = Sets.newHashSet(); - - try { - valids = getValidPackets(side); - } catch (FieldAccessException e) { - valids = Ranges.closed(0, 255).asSet(DiscreteDomains.integers()); + for (PacketType type : types) { + if (type.getSender() == sender) { + result.add(type); + } } - - // Check connection side - if (side.isForClient()) - result.addAll(Packets.Client.getRegistry().values()); - if (side.isForServer()) - result.addAll(Packets.Server.getRegistry().values()); - - // Remove invalid packets - result.retainAll(valids); return result; } + + public PacketListener createPacketListener(Set type) { + final ListeningWhitelist serverList = ListeningWhitelist.newBuilder(). + types(filterTypes(type, Sender.SERVER)). + gamePhaseBoth(). + monitor(). + build(); - public DetailedPacketListener createPacketListener(final ConnectionSide side, int idStart, int idStop, final boolean detailed) { - Set range = Ranges.closed(idStart, idStop).asSet(DiscreteDomains.integers()); - Set packets; + final ListeningWhitelist clientList = ListeningWhitelist.newBuilder(serverList). + types(filterTypes(type, Sender.CLIENT)). + build(); - try { - // Only use supported packet IDs - packets = new HashSet(getValidPackets(side)); - packets.retainAll(range); - - } catch (FieldAccessException e) { - // Don't filter anything then - packets = range; - } - - // Ignore empty sets - if (packets.isEmpty()) - return null; - - // Create the listener we will be using - final ListeningWhitelist whitelist = new ListeningWhitelist(ListenerPriority.MONITOR, packets, GamePhase.BOTH); - - return new DetailedPacketListener() { + return new PacketListener() { @Override public void onPacketSending(PacketEvent event) { - if (side.isForServer() && filter.filterEvent(event)) { + if (filter.filterEvent(event)) { printInformation(event); } } @Override public void onPacketReceiving(PacketEvent event) { - if (side.isForClient() && filter.filterEvent(event)) { + if (filter.filterEvent(event)) { printInformation(event); } } private void printInformation(PacketEvent event) { - String verb = side.isForClient() ? "Received" : "Sent"; - String format = side.isForClient() ? - "%s %s (%s) from %s" : - "%s %s (%s) to %s"; + String verb = event.isServerPacket() ? "Sent" : "Received"; + String format = event.isServerPacket() ? + "%s %s to %s" : + "%s %s from %s"; + String shortDescription = String.format(format, event.isCancelled() ? "Cancelled" : verb, - Packets.getDeclaredName(event.getPacketID()), - event.getPacketID(), + event.getPacketType(), event.getPlayer().getName() ); // Detailed will print the packet's content too - if (detailed) { + if (extendedTypes.contains(event.getPacketType())) { try { Object packet = event.getPacket().getHandle(); Class clazz = packet.getClass(); @@ -463,56 +362,34 @@ class CommandPacket extends CommandBase { @Override public ListeningWhitelist getSendingWhitelist() { - return side.isForServer() ? whitelist : ListeningWhitelist.EMPTY_WHITELIST; + return serverList; } @Override public ListeningWhitelist getReceivingWhitelist() { - return side.isForClient() ? whitelist : ListeningWhitelist.EMPTY_WHITELIST; + return clientList; } @Override public Plugin getPlugin() { return plugin; } - - @Override - public boolean isDetailed() { - return detailed; - } }; } - public DetailedPacketListener addPacketListeners(ConnectionSide side, int idStart, int idStop, boolean detailed) { - DetailedPacketListener listener = createPacketListener(side, idStart, idStop, detailed); - - // The trees will manage the listeners for us + public PacketListener updatePacketListener() { if (listener != null) { - if (side.isForClient()) - clientListeners.put(idStart, idStop, listener); - if (side.isForServer()) - serverListeners.put(idStart, idStop, listener); - return listener; - } else { - throw new IllegalArgumentException("No packets found in the range " + idStart + " - " + idStop + "."); + manager.removePacketListener(listener); } + + // Register a new listener instead + listener = createPacketListener(packetTypes.values()); + manager.addPacketListener(listener); + return listener; } - public Set.Entry> removePacketListeners( - ConnectionSide side, int idStart, int idStop, boolean detailed) { - - HashSet.Entry> result = Sets.newHashSet(); - - // The interval tree will automatically remove the listeners for us - if (side.isForClient()) - result.addAll(clientListeners.remove(idStart, idStop, true)); - if (side.isForServer()) - result.addAll(serverListeners.remove(idStart, idStop, true)); - return result; - } - - private SubCommand parseCommand(String[] args, int index) { - String text = args[index].toLowerCase(); + private SubCommand parseCommand(Deque arguments) { + String text = arguments.poll().toLowerCase(); // Parse this too if ("add".startsWith(text)) @@ -526,21 +403,4 @@ class CommandPacket extends CommandBase { else throw new IllegalArgumentException(text + " is not a valid sub command. Must be add or remove."); } - - private ConnectionSide parseSide(String[] args, int index, ConnectionSide defaultValue) { - if (index < args.length) { - String text = args[index].toLowerCase(); - - // Parse the side gracefully - if ("client".startsWith(text)) - return ConnectionSide.CLIENT_SIDE; - else if ("server".startsWith(text)) - return ConnectionSide.SERVER_SIDE; - else - throw new IllegalArgumentException(text + " is not a connection side."); - - } else { - return defaultValue; - } - } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java index 608f27d2..7ee56020 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java @@ -114,7 +114,7 @@ class CommandProtocol extends CommandBase { // Parse the boolean parameter if (args.length == 2) { - Boolean parsed = parseBoolean(args, "start", 2); + Boolean parsed = parseBoolean(toQueue(args, 2), "start"); if (parsed != null) { state = parsed; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java index ab5d6720..dfcf8cdb 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketType.java @@ -588,6 +588,16 @@ public class PacketType implements Serializable { throw new IllegalArgumentException("Cannot find legacy packet " + packetId); } + /** + * Determine if the given legacy packet exists. + * @param packetId - the legacy packet ID. + * @param preference - the sender preference. + * @return TRUE if it does, FALSE otherwise. + */ + public static boolean hasLegacy(int packetId) { + return getLookup().getFromLegacy(packetId) != null; + } + /** * Retrieve a packet type from a protocol, sender and packet ID. *

@@ -610,6 +620,17 @@ public class PacketType implements Serializable { "(Protocol: " + protocol + ", Sender: " + sender + ")"); } + /** + * Determine if the given packet exists. + * @param protocol - the protocol. + * @param sender - the sender. + * @param packetId - the packet ID. + * @return TRUE if it exists, FALSE otherwise. + */ + public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) { + return getLookup().getFromCurrent(protocol, sender, packetId) != null; + } + /** * Retrieve a packet type from a protocol, sender and packet ID. *

@@ -822,7 +843,10 @@ public class PacketType implements Serializable { @Override public String toString() { Class clazz = getPacketClass();; - return (clazz != null ? clazz.getSimpleName() : "UNREGISTERED") + - " [" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + "]"; + + if (clazz == null) + return "UNREGISTERED [" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + "]"; + else + return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]"; } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/PacketTypeParser.java b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketTypeParser.java new file mode 100644 index 00000000..81a30de9 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/PacketTypeParser.java @@ -0,0 +1,111 @@ +package com.comphenix.protocol; + +import java.util.Deque; +import java.util.List; +import java.util.Set; + +import com.comphenix.protocol.PacketType.Protocol; +import com.comphenix.protocol.PacketType.Sender; +import com.comphenix.protocol.events.ConnectionSide; +import com.google.common.collect.DiscreteDomains; +import com.google.common.collect.Lists; +import com.google.common.collect.Range; +import com.google.common.collect.Ranges; +import com.google.common.collect.Sets; + +class PacketTypeParser { + public final static Range DEFAULT_MAX_RANGE = Ranges.closed(0, 255); + + public Set parseTypes(Deque arguments, Range defaultRange) { + Sender side = null; + Protocol protocol = null; + Set result = Sets.newHashSet(); + + // Find these first + while (protocol == null || side == null) { + String arg = arguments.poll(); + + // Attempt to parse a side or protocol first + if (side == null) { + ConnectionSide connection = parseSide(arg); + + if (connection != null) { + side = connection.getSender(); + continue; + } + } + if (protocol == null) { + if ((protocol = parseProtocol(arg)) != null) { + continue; + } + } + throw new IllegalArgumentException("No side and protocol specified."); + } + + // Then we move on to parsing IDs (named packet types soon to come) + List> ranges = RangeParser.getRanges(arguments, DEFAULT_MAX_RANGE); + + // Supply a default integer range + if (ranges.size() == 0) { + ranges = Lists.newArrayList(); + ranges.add(defaultRange); + } + + for (Range range : ranges) { + for (Integer id : range.asSet(DiscreteDomains.integers())) { + // Deprecated packets + if (protocol == null) { + if (PacketType.hasLegacy(id)) { + result.add(PacketType.findLegacy(id, side)); + } + } else { + if (PacketType.hasCurrent(protocol, side, id)) { + result.add(PacketType.findCurrent(protocol, side, id)); + } + } + } + } + return result; + } + + /** + * Parse a connection sides from a string. + * @param text - the possible connection side. + * @return The connection side, or NULL if not found. + */ + public ConnectionSide parseSide(String text) { + if (text == null) + return null; + String candidate = text.toLowerCase(); + + // Parse the side gracefully + if ("client".startsWith(candidate)) + return ConnectionSide.CLIENT_SIDE; + else if ("server".startsWith(candidate)) + return ConnectionSide.SERVER_SIDE; + else + return null; + } + + /** + * Parse a protocol from a string. + * @param text - the possible protocol. + * @return The protocol, or NULL if not found. + */ + public Protocol parseProtocol(String text) { + if (text == null) + return null; + String candidate = text.toLowerCase(); + + if ("handshake".equals(candidate) || "handshaking".equals(candidate)) + return Protocol.HANDSHAKING; + else if ("login".equals(candidate)) + return Protocol.LOGIN; + else if ("play".equals(candidate) || "game".equals(candidate)) + return Protocol.PLAY; + else if ("status".equals(candidate)) + return Protocol.STATUS; + else + return null; + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java b/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java index f893f731..c5b730cc 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java @@ -17,7 +17,10 @@ package com.comphenix.protocol; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; import java.util.List; import com.google.common.collect.DiscreteDomains; @@ -37,7 +40,7 @@ class RangeParser { * @return The parsed ranges. */ public static List> getRanges(String text, Range legalRange) { - return getRanges(new String[] { text }, 0, 0, legalRange); + return getRanges(new ArrayDeque(Arrays.asList(text)), legalRange); } /** @@ -48,8 +51,8 @@ class RangeParser { * @param legalRange - range of legal values. * @return The parsed ranges. */ - public static List> getRanges(String[] args, int offset, int lastIndex, Range legalRange) { - List tokens = tokenizeInput(args, offset, lastIndex); + public static List> getRanges(Deque input, Range legalRange) { + List tokens = tokenizeInput(input); List> ranges = new ArrayList>(); for (int i = 0; i < tokens.size(); i++) { @@ -121,13 +124,13 @@ class RangeParser { return result; } - private static List tokenizeInput(String[] args, int offset, int lastIndex) { + private static List tokenizeInput(Deque input) { List tokens = new ArrayList(); // Tokenize the input - for (int i = offset; i <= lastIndex; i++) { - String text = args[i]; + while (!input.isEmpty()) { StringBuilder number = new StringBuilder(); + String text = input.peek(); for (int j = 0; j < text.length(); j++) { char current = text.charAt(j); @@ -145,13 +148,15 @@ class RangeParser { tokens.add(Character.toString(current)); } else { - throw new IllegalArgumentException("Illegal character '" + current + "' found."); + // We're no longer dealing with integers - quit + return tokens; } } // Add the number token, if it hasn't already if (number.length() > 0) tokens.add(number.toString()); + input.poll(); } return tokens; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java index c41cf89a..30b72ba8 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java @@ -40,6 +40,16 @@ public class PacketTypeSet { } } + /** + * Add the given types to the set of packet types. + * @param types - the types to add. + */ + public synchronized void addAll(Iterable types) { + for (PacketType type : types) { + addType(type); + } + } + /** * Remove a particular type to the set. * @param type - the type to remove. @@ -53,6 +63,16 @@ public class PacketTypeSet { } } + /** + * Remove the given types from the set. + * @param type - the types to remove. + */ + public synchronized void removeAll(Iterable types) { + for (PacketType type : types) { + removeType(type); + } + } + /** * Retrieve the packet class associated with a particular type. * @param type - the packet type. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java index 1c234aa4..1c62dbe4 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java @@ -295,9 +295,9 @@ public class ListeningWhitelist { */ public static class Builder { private ListenerPriority priority; - private Set types; + private Set types = Sets.newHashSet(); private GamePhase gamePhase; - private Set options; + private Set options = Sets.newHashSet(); /** * Construct a new listening whitelist template.