diff --git a/pom.xml b/pom.xml
index aaf7cc360..198d6b463 100644
--- a/pom.xml
+++ b/pom.xml
@@ -310,6 +310,10 @@
junit*
+
+ io.netty
+ *
+
diff --git a/src/main/java/com/comphenix/protocol/PacketStream.java b/src/main/java/com/comphenix/protocol/PacketStream.java
index 5df88d6d7..8d9a7c2e9 100644
--- a/src/main/java/com/comphenix/protocol/PacketStream.java
+++ b/src/main/java/com/comphenix/protocol/PacketStream.java
@@ -17,98 +17,87 @@
package com.comphenix.protocol;
-import java.lang.reflect.InvocationTargetException;
-
-import org.bukkit.entity.Player;
-
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.netty.WirePacket;
+import org.bukkit.entity.Player;
/**
* Represents a object capable of sending or receiving packets.
- *
+ *
* @author Kristian
*/
public interface PacketStream {
+
/**
* Send a packet to the given player.
+ *
* @param receiver - the reciever.
- * @param packet - packet to send.
- * @throws InvocationTargetException - if an error occured when sending the packet.
+ * @param packet - packet to send.
*/
- public void sendServerPacket(Player receiver, PacketContainer packet)
- throws InvocationTargetException;
+ void sendServerPacket(Player receiver, PacketContainer packet);
/**
* Send a packet to the given player.
+ *
* @param receiver - the reciever.
- * @param packet - packet to send.
- * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException - if an error occured when sending the packet.
+ * @param packet - packet to send.
+ * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
*/
- public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
- throws InvocationTargetException;
-
+ void sendServerPacket(Player receiver, PacketContainer packet, boolean filters);
+
/**
* Send a packet to the given player.
+ *
* @param receiver - the receiver.
- * @param packet - packet to send.
- * @param marker - the network marker to use.
- * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException - if an error occured when sending the packet.
+ * @param packet - packet to send.
+ * @param marker - the network marker to use.
+ * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
*/
- public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters)
- throws InvocationTargetException;
+ void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters);
/**
* Send a wire packet to the given player.
+ *
* @param receiver - the receiver.
- * @param id - packet id.
- * @param bytes - packet bytes.
- * @throws InvocationTargetException if an error occured when sending the packet.
+ * @param id - packet id.
+ * @param bytes - packet bytes.
*/
- public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException;
+ void sendWirePacket(Player receiver, int id, byte[] bytes);
/**
* Send a wire packet to the given player.
+ *
* @param receiver - the receiver.
- * @param packet - packet to send.
- * @throws InvocationTargetException if an error occured when sending the packet.
+ * @param packet - packet to send.
*/
- public void sendWirePacket(Player receiver, WirePacket packet) throws InvocationTargetException;
+ void sendWirePacket(Player receiver, WirePacket packet);
/**
* Simulate recieving a certain packet from a given player.
+ *
* @param sender - the sender.
* @param packet - the packet that was sent.
- * @throws InvocationTargetException If the reflection machinery failed.
- * @throws IllegalAccessException If the underlying method caused an error.
*/
- public void recieveClientPacket(Player sender, PacketContainer packet)
- throws IllegalAccessException, InvocationTargetException;
+ void receiveClientPacket(Player sender, PacketContainer packet);
/**
* Simulate recieving a certain packet from a given player.
- * @param sender - the sender.
- * @param packet - the packet that was sent.
+ *
+ * @param sender - the sender.
+ * @param packet - the packet that was sent.
* @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException If the reflection machinery failed.
- * @throws IllegalAccessException If the underlying method caused an error.
*/
- public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
- throws IllegalAccessException, InvocationTargetException;
-
+ void receiveClientPacket(Player sender, PacketContainer packet, boolean filters);
+
/**
* Simulate recieving a certain packet from a given player.
- * @param sender - the sender.
- * @param packet - the packet that was sent.
- * @param marker - the network marker to use.
+ *
+ * @param sender - the sender.
+ * @param packet - the packet that was sent.
+ * @param marker - the network marker to use.
* @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException If the reflection machinery failed.
- * @throws IllegalAccessException If the underlying method caused an error.
*/
- public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters)
- throws IllegalAccessException, InvocationTargetException;
+ void receiveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters);
}
diff --git a/src/main/java/com/comphenix/protocol/ProtocolConfig.java b/src/main/java/com/comphenix/protocol/ProtocolConfig.java
index 7710f0f91..bab936894 100644
--- a/src/main/java/com/comphenix/protocol/ProtocolConfig.java
+++ b/src/main/java/com/comphenix/protocol/ProtocolConfig.java
@@ -1,43 +1,39 @@
/**
- * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
- * Copyright (C) 2012 Kristian S. Stangeland
- *
- * This program is free software; you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA
+ * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2012 Kristian S.
+ * Stangeland
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.comphenix.protocol;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
-
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
-import com.comphenix.protocol.injector.PlayerInjectHooks;
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.io.Files;
-
/**
* Represents the configuration of ProtocolLib.
- *
+ *
* @author Kristian
*/
public class ProtocolConfig {
+
private static final String LAST_UPDATE_FILE = "lastupdate";
private static final String SECTION_GLOBAL = "global";
@@ -98,7 +94,7 @@ public void reloadConfig() {
/**
* Load the last update time stamp from the file system.
- *
+ *
* @return Last update time stamp.
*/
private long loadLastUpdate() {
@@ -119,7 +115,7 @@ private long loadLastUpdate() {
/**
* Store the given time stamp.
- *
+ *
* @param value - time stamp to store.
*/
private void saveLastUpdate(long value) {
@@ -128,8 +124,9 @@ private void saveLastUpdate(long value) {
// The data folder must exist
dataFile.getParentFile().mkdirs();
- if (dataFile.exists())
+ if (dataFile.exists()) {
dataFile.delete();
+ }
try {
Files.write(Long.toString(value), dataFile, Charsets.UTF_8);
@@ -140,7 +137,7 @@ private void saveLastUpdate(long value) {
/**
* Retrieve the file that is used to store the update time stamp.
- *
+ *
* @return File storing the update time stamp.
*/
private File getLastUpdateFile() {
@@ -149,7 +146,7 @@ private File getLastUpdateFile() {
/**
* Load data sections.
- *
+ *
* @param copyDefaults - whether or not to copy configuration defaults.
*/
private void loadSections(boolean copyDefaults) {
@@ -167,8 +164,9 @@ private void loadSections(boolean copyDefaults) {
if (copyDefaults && (!getFile().exists() || global == null || updater == null)) {
loadingSections = true;
- if (config != null)
+ if (config != null) {
config.options().copyDefaults(true);
+ }
plugin.saveDefaultConfig();
plugin.reloadConfig();
loadingSections = false;
@@ -180,7 +178,7 @@ private void loadSections(boolean copyDefaults) {
/**
* Set a particular configuration key value pair.
- *
+ *
* @param section - the configuration root.
* @param path - the path to the key.
* @param value - the value to set.
@@ -210,7 +208,7 @@ private T getUpdaterValue(String path, T def) {
/**
* Retrieve a reference to the configuration file.
- *
+ *
* @return Configuration file on disk.
*/
public File getFile() {
@@ -219,7 +217,7 @@ public File getFile() {
/**
* Determine if detailed error reporting is enabled. Default FALSE.
- *
+ *
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isDetailedErrorReporting() {
@@ -228,7 +226,7 @@ public boolean isDetailedErrorReporting() {
/**
* Set whether or not detailed error reporting is enabled.
- *
+ *
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDetailedErrorReporting(boolean value) {
@@ -237,7 +235,7 @@ public void setDetailedErrorReporting(boolean value) {
/**
* Retrieve whether or not ProtocolLib should determine if a new version has been released.
- *
+ *
* @return TRUE if it should do this automatically, FALSE otherwise.
*/
public boolean isAutoNotify() {
@@ -246,7 +244,7 @@ public boolean isAutoNotify() {
/**
* Set whether or not ProtocolLib should determine if a new version has been released.
- *
+ *
* @param value - TRUE to do this automatically, FALSE otherwise.
*/
public void setAutoNotify(boolean value) {
@@ -256,7 +254,7 @@ public void setAutoNotify(boolean value) {
/**
* Retrieve whether or not ProtocolLib should automatically download the new version.
- *
+ *
* @return TRUE if it should, FALSE otherwise.
*/
public boolean isAutoDownload() {
@@ -265,7 +263,7 @@ public boolean isAutoDownload() {
/**
* Set whether or not ProtocolLib should automatically download the new version.
- *
+ *
* @param value - TRUE if it should. FALSE otherwise.
*/
public void setAutoDownload(boolean value) {
@@ -277,7 +275,7 @@ public void setAutoDownload(boolean value) {
* Determine whether or not debug mode is enabled.
*
* This grants access to the filter command.
- *
+ *
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isDebug() {
@@ -286,7 +284,7 @@ public boolean isDebug() {
/**
* Set whether or not debug mode is enabled.
- *
+ *
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDebug(boolean value) {
@@ -296,7 +294,7 @@ public void setDebug(boolean value) {
/**
* Retrieve an immutable list of every suppressed report type.
- *
+ *
* @return Every suppressed report type.
*/
public ImmutableList getSuppressedReports() {
@@ -305,7 +303,7 @@ public ImmutableList getSuppressedReports() {
/**
* Set the list of suppressed report types,
- *
+ *
* @param reports - suppressed report types.
*/
public void setSuppressedReports(List reports) {
@@ -315,7 +313,7 @@ public void setSuppressedReports(List reports) {
/**
* Retrieve the amount of time to wait until checking for a new update.
- *
+ *
* @return The amount of time to wait.
*/
public long getAutoDelay() {
@@ -327,20 +325,21 @@ public long getAutoDelay() {
* Set the amount of time to wait until checking for a new update.
*
* This time must be greater than 59 seconds.
- *
+ *
* @param delaySeconds - the amount of time to wait.
*/
public void setAutoDelay(long delaySeconds) {
// Silently fix the delay
- if (delaySeconds < DEFAULT_UPDATER_DELAY)
+ if (delaySeconds < DEFAULT_UPDATER_DELAY) {
delaySeconds = DEFAULT_UPDATER_DELAY;
+ }
setConfig(updater, UPDATER_DELAY, delaySeconds);
modCount++;
}
/**
* The version of Minecraft to ignore the built-in safety feature.
- *
+ *
* @return The version to ignore ProtocolLib's satefy.
*/
public String getIgnoreVersionCheck() {
@@ -351,7 +350,7 @@ public String getIgnoreVersionCheck() {
* Sets under which version of Minecraft the version safety feature will be ignored.
*
* This is useful if a server operator has tested and verified that a version of ProtocolLib works, but doesn't want or can't upgrade to a newer version.
- *
+ *
* @param ignoreVersion - the version of Minecraft where the satefy will be disabled.
*/
public void setIgnoreVersionCheck(String ignoreVersion) {
@@ -361,7 +360,7 @@ public void setIgnoreVersionCheck(String ignoreVersion) {
/**
* Retrieve whether or not metrics is enabled.
- *
+ *
* @return TRUE if metrics is enabled, FALSE otherwise.
*/
public boolean isMetricsEnabled() {
@@ -372,7 +371,7 @@ public boolean isMetricsEnabled() {
* Set whether or not metrics is enabled.
*
* This setting will take effect next time ProtocolLib is started.
- *
+ *
* @param enabled - whether or not metrics is enabled.
*/
public void setMetricsEnabled(boolean enabled) {
@@ -382,7 +381,7 @@ public void setMetricsEnabled(boolean enabled) {
/**
* Retrieve whether or not the background compiler for structure modifiers is enabled or not.
- *
+ *
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isBackgroundCompilerEnabled() {
@@ -393,7 +392,7 @@ public boolean isBackgroundCompilerEnabled() {
* Set whether or not the background compiler for structure modifiers is enabled or not.
*
* This setting will take effect next time ProtocolLib is started.
- *
+ *
* @param enabled - TRUE if is enabled/running, FALSE otherwise.
*/
public void setBackgroundCompilerEnabled(boolean enabled) {
@@ -403,7 +402,7 @@ public void setBackgroundCompilerEnabled(boolean enabled) {
/**
* Retrieve the last time we updated, in seconds since 1970.01.01 00:00.
- *
+ *
* @return Last update time.
*/
public long getAutoLastTime() {
@@ -414,7 +413,7 @@ public long getAutoLastTime() {
* Set the last time we updated, in seconds since 1970.01.01 00:00.
*
* Note that this is not considered to modify the configuration, so the modification count will not be incremented.
- *
+ *
* @param lastTimeSeconds - new last update time.
*/
public void setAutoLastTime(long lastTimeSeconds) {
@@ -424,7 +423,7 @@ public void setAutoLastTime(long lastTimeSeconds) {
/**
* Retrieve the unique name of the script engine to use for filtering.
- *
+ *
* @return Script engine to use.
*/
public String getScriptEngineName() {
@@ -435,7 +434,7 @@ public String getScriptEngineName() {
* Set the unique name of the script engine to use for filtering.
*
* This setting will take effect next time ProtocolLib is started.
- *
+ *
* @param name - name of the script engine to use.
*/
public void setScriptEngineName(String name) {
@@ -443,45 +442,9 @@ public void setScriptEngineName(String name) {
modCount++;
}
- /**
- * Retrieve the default injection method.
- *
- * @return Default method.
- */
- public PlayerInjectHooks getDefaultMethod() {
- return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
- }
-
- /**
- * Retrieve the injection method that has been set in the configuration, or use a default value.
- *
- * @return Injection method to use.
- * @throws IllegalArgumentException If the configuration option is malformed.
- */
- public PlayerInjectHooks getInjectionMethod() throws IllegalArgumentException {
- String text = global.getString(INJECTION_METHOD);
-
- // Default hook if nothing has been set
- PlayerInjectHooks hook = getDefaultMethod();
-
- if (text != null)
- hook = PlayerInjectHooks.valueOf(text.toUpperCase(Locale.ENGLISH).replace(" ", "_"));
- return hook;
- }
-
- /**
- * Set the starting injection method to use.
- *
- * @return Injection method.
- */
- public void setInjectionMethod(PlayerInjectHooks hook) {
- setConfig(global, INJECTION_METHOD, hook.name());
- modCount++;
- }
-
/**
* Retrieve the number of modifications made to this configuration.
- *
+ *
* @return The number of modifications.
*/
public int getModificationCount() {
@@ -492,10 +455,12 @@ public int getModificationCount() {
* Save the current configuration file.
*/
public void saveAll() {
- if (valuesChanged)
+ if (valuesChanged) {
saveLastUpdate(lastUpdateTime);
- if (configChanged)
+ }
+ if (configChanged) {
plugin.saveConfig();
+ }
// And we're done
valuesChanged = false;
diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java
index 04e18069d..34c7ecbc2 100644
--- a/src/main/java/com/comphenix/protocol/ProtocolLib.java
+++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java
@@ -1,49 +1,50 @@
/**
- * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
- * Copyright (C) 2012 Kristian S. Stangeland
- *
- * This program is free software; you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA
+ * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2012 Kristian S.
+ * Stangeland
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.comphenix.protocol;
-import java.io.File;
-import java.io.IOException;
-import java.util.Set;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import com.comphenix.protocol.async.AsyncFilterManager;
-import com.comphenix.protocol.error.*;
-import com.comphenix.protocol.injector.DelayedSingleTask;
+import com.comphenix.protocol.error.BasicErrorReporter;
+import com.comphenix.protocol.error.DelegatedErrorReporter;
+import com.comphenix.protocol.error.DetailedErrorReporter;
+import com.comphenix.protocol.error.ErrorReporter;
+import com.comphenix.protocol.error.Report;
+import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.InternalManager;
import com.comphenix.protocol.injector.PacketFilterManager;
-import com.comphenix.protocol.injector.PlayerInjectHooks;
import com.comphenix.protocol.metrics.Statistics;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.updater.Updater;
import com.comphenix.protocol.updater.Updater.UpdateType;
-import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.ByteBuddyFactory;
-import com.comphenix.protocol.utility.NettyVersion;
+import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.MinecraftVersion;
+import com.comphenix.protocol.utility.NettyVersion;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.bukkit.Server;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
@@ -57,111 +58,91 @@
* @author Kristian
*/
public class ProtocolLib extends JavaPlugin {
+
// Every possible error or warning report type
- public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
- public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType("Cannot delete old ProtocolLib configuration.");
- public static final ReportType REPORT_CANNOT_PARSE_INJECTION_METHOD = new ReportType("Cannot parse injection method. Using default.");
+ public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType(
+ "Cannot delete old ProtocolLib configuration.");
public static final ReportType REPORT_PLUGIN_LOAD_ERROR = new ReportType("Cannot load ProtocolLib.");
+ public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
public static final ReportType REPORT_PLUGIN_ENABLE_ERROR = new ReportType("Cannot enable ProtocolLib.");
- public static final ReportType REPORT_METRICS_IO_ERROR = new ReportType("Unable to enable metrics due to network problems.");
- public static final ReportType REPORT_METRICS_GENERIC_ERROR = new ReportType("Unable to enable metrics due to network problems.");
+ public static final ReportType REPORT_METRICS_IO_ERROR = new ReportType(
+ "Unable to enable metrics due to network problems.");
+ public static final ReportType REPORT_METRICS_GENERIC_ERROR = new ReportType(
+ "Unable to enable metrics due to network problems.");
- public static final ReportType REPORT_CANNOT_PARSE_MINECRAFT_VERSION = new ReportType("Unable to retrieve current Minecraft version. Assuming %s");
- public static final ReportType REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS = new ReportType("Unable to detect conflicting plugin versions.");
+ public static final ReportType REPORT_CANNOT_PARSE_MINECRAFT_VERSION = new ReportType(
+ "Unable to retrieve current Minecraft version. Assuming %s");
+ public static final ReportType REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS = new ReportType(
+ "Unable to detect conflicting plugin versions.");
public static final ReportType REPORT_CANNOT_REGISTER_COMMAND = new ReportType("Cannot register command %s: %s");
- public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType("Unable to create packet timeout task.");
+ public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType(
+ "Unable to create packet timeout task.");
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot perform automatic updates.");
- // Update information
- static final String BUKKIT_DEV_SLUG = "protocollib";
- static final int BUKKIT_DEV_ID = 45564;
-
- // Different commands
- private enum ProtocolCommand {
- FILTER,
- PACKET,
- PROTOCOL,
- LOGGING;
- }
-
/**
* The number of milliseconds per second.
*/
- static final long MILLI_PER_SECOND = 1000;
+ static final long MILLI_PER_SECOND = TimeUnit.SECONDS.toMillis(1);
+ private static final int ASYNC_MANAGER_DELAY = 1;
private static final String PERMISSION_INFO = "protocol.info";
- // There should only be one protocol manager, so we'll make it static
- private static InternalManager protocolManager;
+ public static boolean UPDATES_DISABLED = false;
- // Error reporter
- private static ErrorReporter reporter = new BasicErrorReporter();
-
- // Strongly typed configuration
+ // these fields are only existing once, we can make them static
+ private static Logger logger;
private static ProtocolConfig config;
- // Metrics and statistics
- private Statistics statistics;
+ private static InternalManager protocolManager;
+ private static ErrorReporter reporter = new BasicErrorReporter();
- // Structure compiler
+ private Statistics statistics;
private BackgroundCompiler backgroundCompiler;
- // Used to clean up server packets that have expired, but mostly required to simulate
- // recieving client packets.
private int packetTask = -1;
private int tickCounter = 0;
- private static final int ASYNC_MANAGER_DELAY = 1;
-
- // Used to unhook players after a delay
- private DelayedSingleTask unhookTask;
-
- // Settings/options
private int configExpectedMod = -1;
- // Updater
+ // updater
private Updater updater;
- public static boolean UPDATES_DISABLED;
-
- // Logger
- private static Logger logger;
private Handler redirectHandler;
- // Commands
+ // commands
private CommandProtocol commandProtocol;
private CommandPacket commandPacket;
private CommandFilter commandFilter;
private PacketLogging packetLogging;
- // Whether or not disable is not needed
+ // Whether disabling field resetting is needed
private boolean skipDisable;
@Override
public void onLoad() {
// Logging
- logger = getLogger();
+ logger = this.getLogger();
ProtocolLogger.init(this);
// Initialize enhancer factory
- ByteBuddyFactory.getInstance().setClassLoader(getClassLoader());
+ ByteBuddyFactory.getInstance().setClassLoader(this.getClassLoader());
// Add global parameters
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
- reporter = getFilteredReporter(detailedReporter);
+ reporter = this.getFilteredReporter(detailedReporter);
// Configuration
- saveDefaultConfig();
- reloadConfig();
+ this.saveDefaultConfig();
+ this.reloadConfig();
try {
config = new ProtocolConfig(this);
- } catch (Exception e) {
- reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e));
+ } catch (Exception exception) {
+ reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(exception));
// Load it again
- if (deleteConfig()) {
+ if (this.deleteConfig()) {
config = new ProtocolConfig(this);
} else {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_DELETE_CONFIG));
@@ -171,11 +152,11 @@ public void onLoad() {
// Print the state of the debug mode
if (config.isDebug()) {
logger.warning("Debug mode is enabled!");
- logger.info("Detected netty version: " + NettyVersion.getVersion());
+ logger.info("Detected netty version: " + NettyVersion.getVersion());
} else {
NettyVersion.getVersion(); // this will cache the version
}
-
+
// And the state of the error reporter
if (config.isDetailedErrorReporting()) {
detailedReporter.setDetailedReporting(true);
@@ -184,52 +165,33 @@ public void onLoad() {
try {
// Check for other versions
- checkConflictingVersions();
+ this.checkConflictingVersions();
// Handle unexpected Minecraft versions
- MinecraftVersion version = verifyMinecraftVersion();
+ MinecraftVersion version = this.verifyMinecraftVersion();
// Set updater - this will not perform any update automatically
- updater = Updater.create(this, BUKKIT_DEV_ID, getFile(), UpdateType.NO_DOWNLOAD, true);
+ this.updater = Updater.create(this, 0, this.getFile(), UpdateType.NO_DOWNLOAD, true);
- unhookTask = new DelayedSingleTask(this);
+ // api init
protocolManager = PacketFilterManager.newBuilder()
- .classLoader(getClassLoader())
- .server(getServer())
+ .server(this.getServer())
.library(this)
.minecraftVersion(version)
- .unhookTask(unhookTask)
.reporter(reporter)
.build();
-
- // Initialize the API
ProtocolLibrary.init(this, config, protocolManager, reporter);
// Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager);
- // Update injection hook
- try {
- PlayerInjectHooks hook = config.getInjectionMethod();
-
- // Only update the hook if it's different
- if (!protocolManager.getPlayerHook().equals(hook)) {
- logger.info("Changing player hook from " + protocolManager.getPlayerHook() + " to " + hook);
- protocolManager.setPlayerHook(hook);
- }
- } catch (IllegalArgumentException e) {
- reporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e));
- }
-
// Send logging information to player listeners too
- initializeCommands();
- setupBroadcastUsers(PERMISSION_INFO);
+ this.initializeCommands();
+ this.setupBroadcastUsers(PERMISSION_INFO);
- } catch (OutOfMemoryError e) {
- throw e;
- } catch (Throwable e) {
+ } catch (Exception e) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager));
- disablePlugin();
+ this.disablePlugin();
}
}
@@ -241,18 +203,18 @@ private void initializeCommands() {
for (ProtocolCommand command : ProtocolCommand.values()) {
try {
switch (command) {
- case PROTOCOL:
- commandProtocol = new CommandProtocol(reporter, this, updater, config);
- break;
- case FILTER:
- commandFilter = new CommandFilter(reporter, this, config);
- break;
- case PACKET:
- commandPacket = new CommandPacket(reporter, this, logger, commandFilter, protocolManager);
- break;
- case LOGGING:
- packetLogging = new PacketLogging(this, protocolManager);
- break;
+ case PROTOCOL:
+ this.commandProtocol = new CommandProtocol(reporter, this, this.updater, config);
+ break;
+ case FILTER:
+ this.commandFilter = new CommandFilter(reporter, this, config);
+ break;
+ case PACKET:
+ this.commandPacket = new CommandPacket(reporter, this, logger, this.commandFilter, protocolManager);
+ break;
+ case LOGGING:
+ this.packetLogging = new PacketLogging(this, protocolManager);
+ break;
}
} catch (OutOfMemoryError e) {
throw e;
@@ -267,6 +229,7 @@ private void initializeCommands() {
/**
* Retrieve a error reporter that may be filtered by the configuration.
+ *
* @return The new default error reporter.
*/
private ErrorReporter getFilteredReporter(ErrorReporter reporter) {
@@ -280,19 +243,20 @@ protected Report filterReport(Object sender, Report report, boolean detailed) {
String canonicalName = ReportType.getReportName(sender, report.getType());
String reportName = Iterables.getLast(Splitter.on("#").split(canonicalName)).toUpperCase();
- if (config != null && config.getModificationCount() != lastModCount) {
+ if (config != null && config.getModificationCount() != this.lastModCount) {
// Update our cached set again
- reports = Sets.newHashSet(config.getSuppressedReports());
- lastModCount = config.getModificationCount();
+ this.reports = Sets.newHashSet(config.getSuppressedReports());
+ this.lastModCount = config.getModificationCount();
}
// Cancel reports either on the full canonical name, or just the report name
- if (reports.contains(canonicalName) || reports.contains(reportName))
+ if (this.reports.contains(canonicalName) || this.reports.contains(reportName)) {
return null;
+ }
} catch (Exception e) {
// Only report this with a minor message
- logger.warning("Error filtering reports: " + e.toString());
+ logger.warning("Error filtering reports: " + e);
}
// Don't filter anything
return report;
@@ -316,16 +280,17 @@ public void reloadConfig() {
private void setupBroadcastUsers(final String permission) {
// Guard against multiple calls
- if (redirectHandler != null)
+ if (this.redirectHandler != null) {
return;
+ }
// Broadcast information to every user too
- redirectHandler = new Handler() {
+ this.redirectHandler = new Handler() {
@Override
public void publish(LogRecord record) {
// Only display warnings and above
if (record.getLevel().intValue() >= Level.WARNING.intValue()) {
- commandPacket.broadcastMessageSilently(record.getMessage(), permission);
+ ProtocolLib.this.commandPacket.broadcastMessageSilently(record.getMessage(), permission);
}
}
@@ -340,23 +305,19 @@ public void close() throws SecurityException {
}
};
- logger.addHandler(redirectHandler);
+ logger.addHandler(this.redirectHandler);
}
@Override
public void onEnable() {
try {
- Server server = getServer();
+ Server server = this.getServer();
PluginManager manager = server.getPluginManager();
- // Don't do anything else!
- if (manager == null)
- return;
-
// Silly plugin reloaders!
if (protocolManager == null) {
Logger directLogging = Logger.getLogger("Minecraft");
- String[] message = new String[] {
+ String[] message = new String[]{
" ProtocolLib does not support plugin reloaders! ", " Please use the built-in reload command! "
};
@@ -365,17 +326,17 @@ public void onEnable() {
directLogging.severe(line);
}
- disablePlugin();
+ this.disablePlugin();
return;
}
// Check for incompatible plugins
- checkForIncompatibility(manager);
+ this.checkForIncompatibility(manager);
// Initialize background compiler
- if (backgroundCompiler == null && config.isBackgroundCompilerEnabled()) {
- backgroundCompiler = new BackgroundCompiler(getClassLoader(), reporter);
- BackgroundCompiler.setInstance(backgroundCompiler);
+ if (this.backgroundCompiler == null && config.isBackgroundCompilerEnabled()) {
+ this.backgroundCompiler = new BackgroundCompiler(this.getClassLoader(), reporter);
+ BackgroundCompiler.setInstance(this.backgroundCompiler);
logger.info("Started structure compiler thread.");
} else {
@@ -383,41 +344,40 @@ public void onEnable() {
}
// Set up command handlers
- registerCommand(CommandProtocol.NAME, commandProtocol);
- registerCommand(CommandPacket.NAME, commandPacket);
- registerCommand(CommandFilter.NAME, commandFilter);
- registerCommand(PacketLogging.NAME, packetLogging);
+ this.registerCommand(CommandProtocol.NAME, this.commandProtocol);
+ this.registerCommand(CommandPacket.NAME, this.commandPacket);
+ this.registerCommand(CommandFilter.NAME, this.commandFilter);
+ this.registerCommand(PacketLogging.NAME, this.packetLogging);
// Player login and logout events
protocolManager.registerEvents(manager, this);
// Worker that ensures that async packets are eventually sent
// It also performs the update check.
- createPacketTask(server);
+ this.createPacketTask(server);
} catch (OutOfMemoryError e) {
throw e;
} catch (Throwable e) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_ENABLE_ERROR).error(e));
- disablePlugin();
+ this.disablePlugin();
return;
}
// Try to enable statistics
try {
if (config.isMetricsEnabled()) {
- statistics = new Statistics(this);
+ this.statistics = new Statistics(this);
}
} catch (OutOfMemoryError e) {
throw e;
} catch (IOException e) {
- reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_IO_ERROR).error(e).callerParam(statistics));
+ reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_IO_ERROR).error(e).callerParam(this.statistics));
} catch (Throwable e) {
- reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_GENERIC_ERROR).error(e).callerParam(statistics));
+ reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_GENERIC_ERROR).error(e).callerParam(
+ this.statistics));
}
}
- // Plugin authors: Notify me to remove these
-
private void checkForIncompatibility(PluginManager manager) {
for (String plugin : ProtocolLibrary.INCOMPATIBLE) {
if (manager.getPlugin(plugin) != null) {
@@ -434,26 +394,31 @@ private void checkForIncompatibility(PluginManager manager) {
}
}
+ // Plugin authors: Notify me to remove these
+
// Used to check Minecraft version
private MinecraftVersion verifyMinecraftVersion() {
MinecraftVersion minimum = new MinecraftVersion(ProtocolLibrary.MINIMUM_MINECRAFT_VERSION);
MinecraftVersion maximum = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION);
try {
- MinecraftVersion current = new MinecraftVersion(getServer());
+ MinecraftVersion current = new MinecraftVersion(this.getServer());
// Skip certain versions
if (!config.getIgnoreVersionCheck().equals(current.getVersion())) {
// We'll just warn the user for now
- if (current.compareTo(minimum) < 0)
+ if (current.compareTo(minimum) < 0) {
logger.warning("Version " + current + " is lower than the minimum " + minimum);
- if (current.compareTo(maximum) > 0)
+ }
+ if (current.compareTo(maximum) > 0) {
logger.warning("Version " + current + " has not yet been tested! Proceed with caution.");
+ }
}
return current;
} catch (Exception e) {
- reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_PARSE_MINECRAFT_VERSION).error(e).messageParam(maximum));
+ reporter.reportWarning(this,
+ Report.newBuilder(REPORT_CANNOT_PARSE_MINECRAFT_VERSION).error(e).messageParam(maximum));
// Unknown version - just assume it is the latest
return maximum;
@@ -462,16 +427,16 @@ private MinecraftVersion verifyMinecraftVersion() {
private void checkConflictingVersions() {
Pattern ourPlugin = Pattern.compile("ProtocolLib-(.*)\\.jar");
- MinecraftVersion currentVersion = new MinecraftVersion(getDescription().getVersion());
+ MinecraftVersion currentVersion = new MinecraftVersion(this.getDescription().getVersion());
MinecraftVersion newestVersion = null;
// Skip the file that contains this current instance however
- File loadedFile = getFile();
+ File loadedFile = this.getFile();
try {
// Scan the plugin folder for newer versions of ProtocolLib
// The plugin folder isn't always plugins/
- File pluginFolder = getDataFolder().getParentFile();
+ File pluginFolder = this.getDataFolder().getParentFile();
File[] candidates = pluginFolder.listFiles();
if (candidates != null) {
@@ -499,7 +464,7 @@ private void checkConflictingVersions() {
// See if the newest version is actually higher
if (newestVersion != null && currentVersion.compareTo(newestVersion) < 0) {
// We don't need to set internal classes or instances to NULL - that would break the other loaded plugin
- skipDisable = true;
+ this.skipDisable = true;
throw new IllegalStateException(String.format(
"Detected a newer version of ProtocolLib (%s) in plugin folder than the current (%s). Disabling.",
@@ -510,10 +475,11 @@ private void checkConflictingVersions() {
private void registerCommand(String name, CommandExecutor executor) {
try {
// Ignore these - they must have printed an error already
- if (executor == null)
+ if (executor == null) {
return;
+ }
- PluginCommand command = getCommand(name);
+ PluginCommand command = this.getCommand(name);
// Try to load the command
if (command != null) {
@@ -522,7 +488,8 @@ private void registerCommand(String name, CommandExecutor executor) {
throw new RuntimeException("plugin.yml might be corrupt.");
}
} catch (RuntimeException e) {
- reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e));
+ reporter.reportWarning(this,
+ Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e));
}
}
@@ -530,44 +497,42 @@ private void registerCommand(String name, CommandExecutor executor) {
* Disable the current plugin.
*/
private void disablePlugin() {
- getServer().getPluginManager().disablePlugin(this);
+ this.getServer().getPluginManager().disablePlugin(this);
}
private void createPacketTask(Server server) {
try {
- if (packetTask >= 0)
+ if (this.packetTask >= 0) {
throw new IllegalStateException("Packet task has already been created");
+ }
// Attempt to create task
- packetTask = server.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
- @Override
- public void run() {
- AsyncFilterManager manager = (AsyncFilterManager) protocolManager.getAsynchronousManager();
+ this.packetTask = server.getScheduler().scheduleSyncRepeatingTask(this, () -> {
+ AsyncFilterManager manager = (AsyncFilterManager) protocolManager.getAsynchronousManager();
- // We KNOW we're on the main thread at the moment
- manager.sendProcessedPackets(tickCounter++, true);
+ // We KNOW we're on the main thread at the moment
+ manager.sendProcessedPackets(ProtocolLib.this.tickCounter++, true);
- // House keeping
- updateConfiguration();
+ // House keeping
+ ProtocolLib.this.updateConfiguration();
- // Check for updates too
- if (!UPDATES_DISABLED && (tickCounter % 20) == 0) {
- checkUpdates();
- }
+ // Check for updates too
+ if (!UPDATES_DISABLED && (ProtocolLib.this.tickCounter % 20) == 0) {
+ ProtocolLib.this.checkUpdates();
}
}, ASYNC_MANAGER_DELAY, ASYNC_MANAGER_DELAY);
} catch (OutOfMemoryError e) {
throw e;
} catch (Throwable e) {
- if (packetTask == -1) {
+ if (this.packetTask == -1) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CREATE_TIMEOUT_TASK).error(e));
}
}
}
private void updateConfiguration() {
- if (config != null && config.getModificationCount() != configExpectedMod) {
- configExpectedMod = config.getModificationCount();
+ if (config != null && config.getModificationCount() != this.configExpectedMod) {
+ this.configExpectedMod = config.getModificationCount();
// Update the debug flag
protocolManager.setDebug(config.isDebug());
@@ -577,19 +542,20 @@ private void updateConfiguration() {
private void checkUpdates() {
// Ignore milliseconds - it's pointless
long currentTime = System.currentTimeMillis() / MILLI_PER_SECOND;
-
+
try {
long updateTime = config.getAutoLastTime() + config.getAutoDelay();
// Should we update?
- if (currentTime > updateTime && !updater.isChecking()) {
+ if (currentTime > updateTime && !this.updater.isChecking()) {
// Initiate the update as if it came from the console
- if (config.isAutoDownload())
- commandProtocol.updateVersion(getServer().getConsoleSender(), false);
- else if (config.isAutoNotify())
- commandProtocol.checkVersion(getServer().getConsoleSender(), false);
- else
- commandProtocol.updateFinished();
+ if (config.isAutoDownload()) {
+ this.commandProtocol.updateVersion(this.getServer().getConsoleSender(), false);
+ } else if (config.isAutoNotify()) {
+ this.commandProtocol.checkVersion(this.getServer().getConsoleSender(), false);
+ } else {
+ this.commandProtocol.updateFinished();
+ }
}
} catch (Exception e) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e));
@@ -599,36 +565,35 @@ else if (config.isAutoNotify())
@Override
public void onDisable() {
- if (skipDisable) {
+ if (this.skipDisable) {
return;
}
// Disable compiler
- if (backgroundCompiler != null) {
- backgroundCompiler.shutdownAll();
- backgroundCompiler = null;
+ if (this.backgroundCompiler != null) {
+ this.backgroundCompiler.shutdownAll();
+ this.backgroundCompiler = null;
BackgroundCompiler.setInstance(null);
}
// Clean up
- if (packetTask >= 0) {
- getServer().getScheduler().cancelTask(packetTask);
- packetTask = -1;
+ if (this.packetTask >= 0) {
+ this.getServer().getScheduler().cancelTask(this.packetTask);
+ this.packetTask = -1;
}
// And redirect handler too
- if (redirectHandler != null) {
- logger.removeHandler(redirectHandler);
+ if (this.redirectHandler != null) {
+ logger.removeHandler(this.redirectHandler);
}
- if (protocolManager != null)
+ if (protocolManager != null) {
protocolManager.close();
- else
+ } else {
return; // Plugin reloaders!
+ }
- if (unhookTask != null)
- unhookTask.close();
protocolManager = null;
- statistics = null;
+ this.statistics = null;
// To clean up global parameters
reporter = new BasicErrorReporter();
@@ -637,15 +602,24 @@ public void onDisable() {
/**
* Retrieve the metrics instance used to measure users of this library.
*
- * Note that this method may return NULL when the server is reloading or shutting down. It is also
- * NULL if metrics has been disabled.
+ * Note that this method may return NULL when the server is reloading or shutting down. It is also NULL if metrics has
+ * been disabled.
+ *
* @return Metrics instance container.
*/
public Statistics getStatistics() {
- return statistics;
+ return this.statistics;
}
public ProtocolConfig getProtocolConfig() {
return config;
}
+
+ // Different commands
+ private enum ProtocolCommand {
+ FILTER,
+ PACKET,
+ PROTOCOL,
+ LOGGING
+ }
}
diff --git a/src/main/java/com/comphenix/protocol/ProtocolManager.java b/src/main/java/com/comphenix/protocol/ProtocolManager.java
index b73942dc8..2f45bb2a4 100644
--- a/src/main/java/com/comphenix/protocol/ProtocolManager.java
+++ b/src/main/java/com/comphenix/protocol/ProtocolManager.java
@@ -17,16 +17,6 @@
package com.comphenix.protocol;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-import java.util.Set;
-
-import org.bukkit.Location;
-import org.bukkit.World;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-
import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.ListeningWhitelist;
@@ -36,81 +26,94 @@
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
/**
* Represents an API for accessing the Minecraft protocol.
+ *
* @author Kristian
*/
public interface ProtocolManager extends PacketStream {
+
/**
* Retrieve the protocol version of a given player.
*
- * This only really makes sense of a server that support clients of multiple Minecraft versions, such as Spigot #1628.
+ * This only really makes sense of a server that support clients of multiple Minecraft versions, such as Spigot
+ * #1628.
+ *
* @param player - the player.
* @return The associated protocol version, or {@link Integer#MIN_VALUE} if unknown.
*/
int getProtocolVersion(Player player);
-
+
/**
* Send a packet to the given player.
*
- * Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
- * to delay a packet until a certain condition has been met.
- *
+ * Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()} to
+ * delay a packet until a certain condition has been met.
+ *
* @param receiver - the receiver.
- * @param packet - packet to send.
- * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException - if an error occurred when sending the packet.
+ * @param packet - packet to send.
+ * @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
*/
@Override
- void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
- throws InvocationTargetException;
-
+ void sendServerPacket(Player receiver, PacketContainer packet, boolean filters);
+
/**
* Simulate receiving a certain packet from a given player.
*
- * Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
- * to delay a packet until a certain condition has been met.
- *
- * @param sender - the sender.
- * @param packet - the packet that was sent.
+ * Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()} to delay
+ * a packet until a certain condition has been met.
+ *
+ * @param sender - the sender.
+ * @param packet - the packet that was sent.
* @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
- * @throws InvocationTargetException If the reflection machinery failed.
- * @throws IllegalAccessException If the underlying method caused an error.
*/
@Override
- void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
- throws IllegalAccessException, InvocationTargetException;
-
+ void receiveClientPacket(Player sender, PacketContainer packet, boolean filters);
+
/**
* Broadcast a given packet to every connected player on the server.
+ *
* @param packet - the packet to broadcast.
* @throws FieldAccessException If we were unable to send the packet due to reflection problems.
*/
void broadcastServerPacket(PacketContainer packet);
-
+
/**
* Broadcast a packet to every player that is receiving information about a given entity.
*
- * This is usually every player in the same world within an observable distance. If the entity is a
- * player, it will only be included if includeTracker is TRUE.
- * @param packet - the packet to broadcast.
- * @param entity - the entity whose trackers we will inform.
+ * This is usually every player in the same world within an observable distance. If the entity is a player, it will
+ * only be included if includeTracker is TRUE.
+ *
+ * @param packet - the packet to broadcast.
+ * @param entity - the entity whose trackers we will inform.
* @param includeTracker - whether or not to also transmit the packet to the entity, if it is a tracker.
* @throws FieldAccessException If we were unable to send the packet due to reflection problems.
*/
void broadcastServerPacket(PacketContainer packet, Entity entity, boolean includeTracker);
-
+
/**
* Broadcast a packet to every player within the given maximum observer distance.
- * @param packet - the packet to broadcast.
- * @param origin - the origin to consider when calculating the distance to each observer.
+ *
+ * @param packet - the packet to broadcast.
+ * @param origin - the origin to consider when calculating the distance to each observer.
* @param maxObserverDistance - the maximum distance to the origin.
*/
void broadcastServerPacket(PacketContainer packet, Location origin, int maxObserverDistance);
-
+
+ void broadcastServerPacket(PacketContainer packet, Collection extends Player> targetPlayers);
+
/**
* Retrieves a list of every registered packet listener.
+ *
* @return Every registered packet listener.
*/
ImmutableSet getPacketListeners();
@@ -118,9 +121,9 @@ void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
/**
* Adds a packet listener.
*
- * Adding an already registered listener has no effect. If you need to change the packets
- * the current listener is observing, you must first remove the packet listener before you
- * can register it again.
+ * Adding an already registered listener has no effect. If you need to change the packets the current listener is
+ * observing, you must first remove the packet listener before you can register it again.
+ *
* @param listener - new packet listener.
*/
void addPacketListener(PacketListener listener);
@@ -129,98 +132,109 @@ void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
* Removes a given packet listener.
*
* Attempting to remove a listener that doesn't exist has no effect.
+ *
* @param listener - the packet listener to remove.
*/
void removePacketListener(PacketListener listener);
/**
* Removes every listener associated with the given plugin.
+ *
* @param plugin - the plugin to unload.
*/
void removePacketListeners(Plugin plugin);
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
- * @param type - packet type.
+ *
+ * @param type - packet type.
* @return New encapsulated Minecraft packet.
*/
PacketContainer createPacket(PacketType type);
-
+
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
*
- * If set to true, the forceDefaults option will force the system to automatically
- * give non-primitive fields in the packet sensible default values. For instance, certain
- * packets - like Packet60Explosion - require a List or Set to be non-null. If the
- * forceDefaults option is true, the List or Set will be automatically created.
- *
- * @param type - packet type.
+ * If set to true, the forceDefaults option will force the system to automatically give non-primitive fields in
+ * the packet sensible default values. For instance, certain packets - like Packet60Explosion - require a List or Set
+ * to be non-null. If the forceDefaults option is true, the List or Set will be automatically created.
+ *
+ * @param type - packet type.
* @param forceDefaults - TRUE to use sensible defaults in most fields, FALSE otherwise.
* @return New encapsulated Minecraft packet.
*/
PacketContainer createPacket(PacketType type, boolean forceDefaults);
-
+
/**
* Construct a packet using the special builtin Minecraft constructors.
- * @param type - the packet type.
+ *
+ * @param type - the packet type.
* @param arguments - arguments that will be passed to the constructor.
* @return The packet constructor.
*/
PacketConstructor createPacketConstructor(PacketType type, Object... arguments);
-
+
/**
* Completely resend an entity to a list of clients.
*
- * Note that this method is NOT thread safe. If you call this method from anything
- * but the main thread, it will throw an exception.
- * @param entity - entity to refresh.
+ * Note that this method is NOT thread safe. If you call this method from anything but the main thread, it will throw
+ * an exception.
+ *
+ * @param entity - entity to refresh.
* @param observers - the clients to update.
*/
- void updateEntity(Entity entity, List observers) throws FieldAccessException;
-
+ void updateEntity(Entity entity, List observers);
+
/**
* Retrieve the associated entity.
+ *
* @param container - the world the entity belongs to.
- * @param id - the unique ID of the entity.
+ * @param id - the unique ID of the entity.
* @return The associated entity.
* @throws FieldAccessException Reflection failed.
*/
- Entity getEntityFromID(World container, int id) throws FieldAccessException;
-
+ Entity getEntityFromID(World container, int id);
+
/**
* Retrieve every client that is receiving information about a given entity.
+ *
* @param entity - the entity that is being tracked.
* @return Every client/player that is tracking the given entity.
* @throws FieldAccessException If reflection failed.
*/
- List getEntityTrackers(Entity entity) throws FieldAccessException;
+ List getEntityTrackers(Entity entity);
/**
* Retrieves a immutable set containing the type of the sent server packets that will be observed by listeners.
+ *
* @return Every filtered server packet.
*/
Set getSendingFilterTypes();
/**
* Retrieves a immutable set containing the type of the received client packets that will be observed by listeners.
+ *
* @return Every filtered client packet.
*/
Set getReceivingFilterTypes();
-
+
/**
* Retrieve the current Minecraft version.
+ *
* @return The current version.
*/
MinecraftVersion getMinecraftVersion();
-
+
/**
* Determines whether or not this protocol manager has been disabled.
+ *
* @return TRUE if it has, FALSE otherwise.
*/
boolean isClosed();
/**
* Retrieve the current asynchronous packet manager.
+ *
* @return Asynchronous packet manager.
*/
AsynchronousManager getAsynchronousManager();
diff --git a/src/main/java/com/comphenix/protocol/async/AsyncMarker.java b/src/main/java/com/comphenix/protocol/async/AsyncMarker.java
index df253d2aa..d60482a24 100644
--- a/src/main/java/com/comphenix/protocol/async/AsyncMarker.java
+++ b/src/main/java/com/comphenix/protocol/async/AsyncMarker.java
@@ -17,15 +17,6 @@
package com.comphenix.protocol.async;
-import java.io.IOException;
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-
import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLogger;
@@ -37,16 +28,24 @@
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.primitives.Longs;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
/**
* Contains information about the packet that is being processed by asynchronous listeners.
*
* Asynchronous listeners can use this to set packet timeout or transmission order.
- *
+ *
* @author Kristian
*/
public class AsyncMarker implements Serializable, Comparable {
-
+
/**
* Generated by Eclipse.
*/
@@ -56,52 +55,52 @@ public class AsyncMarker implements Serializable, Comparable {
* Default number of milliseconds until a packet will rejected.
*/
public static final int DEFAULT_TIMEOUT_DELTA = 1800 * 1000;
-
+
/**
* Default number of packets to skip.
*/
public static final int DEFAULT_SENDING_DELTA = 0;
-
+
/**
* The packet stream responsible for transmitting the packet when it's done processing.
*/
private transient PacketStream packetStream;
-
+
/**
* Current list of async packet listeners.
*/
private transient Iterator> listenerTraversal;
-
+
// Timeout handling
private long initialTime;
private long timeout;
-
+
// Packet order
private long originalSendingIndex;
private long newSendingIndex;
-
+
// Used to determine if a packet must be reordered in the sending queue
private Long queuedSendingIndex;
-
+
// Whether or not the packet has been processed by the listeners
private volatile boolean processed;
-
+
// Whether or not the packet has been sent
private volatile boolean transmitted;
-
+
// Whether or not the asynchronous processing itself should be cancelled
private volatile boolean asyncCancelled;
-
+
// Whether or not to delay processing
private AtomicInteger processingDelay = new AtomicInteger();
-
+
// Used to synchronize processing on the shared PacketEvent
private Object processingLock = new Object();
-
+
// Used to identify the asynchronous worker
private transient AsyncListenerHandler listenerHandler;
private transient int workerID;
-
+
// Determine if Minecraft processes this packet asynchronously
private volatile static Method isMinecraftAsync;
private volatile static boolean alwaysSync;
@@ -113,18 +112,18 @@ public class AsyncMarker implements Serializable, Comparable {
AsyncMarker(PacketStream packetStream, long sendingIndex, long initialTime, long timeoutDelta) {
if (packetStream == null)
throw new IllegalArgumentException("packetStream cannot be NULL");
-
+
this.packetStream = packetStream;
-
+
// Timeout
this.initialTime = initialTime;
this.timeout = initialTime + timeoutDelta;
-
+
// Sending index
this.originalSendingIndex = sendingIndex;
this.newSendingIndex = sendingIndex;
}
-
+
/**
* Retrieve the time the packet was initially queued for asynchronous processing.
* @return The initial time in number of milliseconds since 01.01.1970 00:00.
@@ -140,7 +139,7 @@ public long getInitialTime() {
public long getTimeout() {
return timeout;
}
-
+
/**
* Set the time the packet will be forcefully rejected.
* @param timeout - time to reject the packet, in milliseconds since 01.01.1970 00:00.
@@ -219,13 +218,13 @@ void setProcessed(boolean processed) {
*
* It is recommended that processing outside a packet listener is wrapped in a synchronized block
* using the {@link #getProcessingLock()} method.
- *
+ *
* @return The new processing delay.
*/
public int incrementProcessingDelay() {
return processingDelay.incrementAndGet();
}
-
+
/**
* Decrement the number of times this packet must be signalled as done before it's transmitted.
* @return The new processing delay. If zero, the packet should be sent.
@@ -233,7 +232,7 @@ public int incrementProcessingDelay() {
int decrementProcessingDelay() {
return processingDelay.decrementAndGet();
}
-
+
/**
* Retrieve the number of times a packet must be signalled to be done before it's sent.
* @return Number of processing delays.
@@ -241,7 +240,7 @@ int decrementProcessingDelay() {
public int getProcessingDelay() {
return processingDelay.get();
}
-
+
/**
* Whether or not this packet is or has been queued for processing.
* @return TRUE if it has, FALSE otherwise.
@@ -296,7 +295,7 @@ public boolean isTransmitted() {
public boolean hasExpired() {
return hasExpired(System.currentTimeMillis());
}
-
+
/**
* Determine if this packet has expired given this time.
* @param currentTime - the current time in milliseconds since 01.01.1970 00:00.
@@ -305,7 +304,7 @@ public boolean hasExpired() {
public boolean hasExpired(long currentTime) {
return timeout < currentTime;
}
-
+
/**
* Determine if the asynchronous handling should be cancelled.
* @return TRUE if it should, FALSE otherwise.
@@ -319,7 +318,7 @@ public boolean isAsyncCancelled() {
*
* This is only relevant during the synchronous processing. Asynchronous
* listeners should use the normal cancel-field to cancel a PacketEvent.
- *
+ *
* @param asyncCancelled - TRUE to cancel it, FALSE otherwise.
*/
public void setAsyncCancelled(boolean asyncCancelled) {
@@ -369,7 +368,7 @@ void setWorkerID(int workerID) {
Iterator> getListenerTraversal() {
return listenerTraversal;
}
-
+
/**
* Set the iterator for the next listener.
* @param listenerTraversal - the new async packet listener iterator.
@@ -377,28 +376,22 @@ Iterator> getListenerTraversal() {
void setListenerTraversal(Iterator> listenerTraversal) {
this.listenerTraversal = listenerTraversal;
}
-
+
/**
* Transmit a given packet to the current packet stream.
* @param event - the packet to send.
* @throws IOException If the packet couldn't be sent.
*/
void sendPacket(PacketEvent event) throws IOException {
- try {
- if (event.isServerPacket()) {
- packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event), false);
- } else {
- packetStream.recieveClientPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event), false);
- }
- transmitted = true;
-
- } catch (InvocationTargetException e) {
- throw new IOException("Cannot send packet", e);
- } catch (IllegalAccessException e) {
- throw new IOException("Cannot send packet", e);
+ if (event.isServerPacket()) {
+ packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event), false);
+ } else {
+ packetStream.receiveClientPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event),
+ false);
}
+ transmitted = true;
}
-
+
/**
* Determine if Minecraft allows asynchronous processing of this packet.
* @param event - packet event
@@ -413,7 +406,7 @@ public boolean isMinecraftAsync(PacketEvent event) throws FieldAccessException {
// This will occur in 1.2.5 (or possibly in later versions)
List methods = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
getMethodListByParameters(boolean.class, new Class[] {});
-
+
// Try to look for boolean methods
if (methods.size() == 2) {
isMinecraftAsync = methods.get(1);
@@ -460,7 +453,7 @@ public boolean isMinecraftAsync(PacketEvent event) throws FieldAccessException {
}
}
}
-
+
@Override
public int compareTo(AsyncMarker o) {
if (o == null)
@@ -468,7 +461,7 @@ public int compareTo(AsyncMarker o) {
else
return Longs.compare(getNewSendingIndex(), o.getNewSendingIndex());
}
-
+
@Override
public boolean equals(Object other) {
// Standard equals
@@ -479,7 +472,7 @@ public boolean equals(Object other) {
else
return false;
}
-
+
@Override
public int hashCode() {
return Longs.hashCode(getNewSendingIndex());
diff --git a/src/main/java/com/comphenix/protocol/async/PacketSendingQueue.java b/src/main/java/com/comphenix/protocol/async/PacketSendingQueue.java
index 95579114b..1e5e1be82 100644
--- a/src/main/java/com/comphenix/protocol/async/PacketSendingQueue.java
+++ b/src/main/java/com/comphenix/protocol/async/PacketSendingQueue.java
@@ -2,58 +2,51 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
- * This program is free software; you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation; either version 2 of
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * You should have received a copy of the GNU General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.async;
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.reflect.FieldAccessException;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.PriorityBlockingQueue;
-
import org.bukkit.entity.Player;
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.ProtocolLibrary;
-import com.comphenix.protocol.error.Report;
-import com.comphenix.protocol.error.ReportType;
-import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.injector.PlayerLoggedOutException;
-import com.comphenix.protocol.reflect.FieldAccessException;
-
/**
* Represents packets ready to be transmitted to a client.
+ *
* @author Kristian
*/
abstract class PacketSendingQueue {
- public static final ReportType REPORT_DROPPED_PACKET = new ReportType("Warning: Dropped packet index %s of type %s.");
-
+
public static final int INITIAL_CAPACITY = 10;
-
+ // Whether or not packet transmission must occur on a specific thread
+ private final boolean notThreadSafe;
private PriorityBlockingQueue sendingQueue;
-
// Asynchronous packet sending
private Executor asynchronousSender;
- // Whether or not packet transmission must occur on a specific thread
- private final boolean notThreadSafe;
// Whether or not we've run the cleanup procedure
private boolean cleanedUp = false;
-
+
/**
* Create a packet sending queue.
+ *
* @param notThreadSafe - whether or not to synchronize with the main thread or a background thread.
*/
public PacketSendingQueue(boolean notThreadSafe, Executor asynchronousSender) {
@@ -61,44 +54,47 @@ public PacketSendingQueue(boolean notThreadSafe, Executor asynchronousSender) {
this.notThreadSafe = notThreadSafe;
this.asynchronousSender = asynchronousSender;
}
-
+
/**
* Number of packet events in the queue.
+ *
* @return The number of packet events in the queue.
*/
public int size() {
return sendingQueue.size();
}
-
+
/**
- * Enqueue a packet for sending.
+ * Enqueue a packet for sending.
+ *
* @param packet - packet to queue.
*/
public void enqueue(PacketEvent packet) {
sendingQueue.add(new PacketEventHolder(packet));
}
-
+
/**
* Invoked when one of the packets have finished processing.
+ *
* @param packetUpdated - the packet that has now been updated.
- * @param onMainThread - whether or not this is occuring on the main thread.
+ * @param onMainThread - whether or not this is occuring on the main thread.
*/
public synchronized void signalPacketUpdate(PacketEvent packetUpdated, boolean onMainThread) {
-
+
AsyncMarker marker = packetUpdated.getAsyncMarker();
-
+
// Should we reorder the event?
if (marker.getQueuedSendingIndex() != marker.getNewSendingIndex() && !marker.hasExpired()) {
PacketEvent copy = PacketEvent.fromSynchronous(packetUpdated, marker);
-
+
// "Cancel" the original event
packetUpdated.setReadOnly(false);
packetUpdated.setCancelled(true);
-
+
// Enqueue the copy with the new sending index
enqueue(copy);
}
-
+
// Mark this packet as finished
marker.setProcessed(true);
trySendPackets(onMainThread);
@@ -111,79 +107,81 @@ public synchronized void signalPacketUpdate(PacketEvent packetUpdated, boolean o
*/
public synchronized void signalPacketUpdate(List packetsRemoved, boolean onMainThread) {
Set lookup = new HashSet(packetsRemoved);
-
+
// Note that this is O(n), so it might be expensive
for (PacketEventHolder holder : sendingQueue) {
PacketEvent event = holder.getEvent();
-
+
if (lookup.contains(event.getPacketType())) {
event.getAsyncMarker().setProcessed(true);
}
}
-
+
// This is likely to have changed the situation a bit
trySendPackets(onMainThread);
}
-
+
/**
* Attempt to send any remaining packets.
+ *
* @param onMainThread - whether or not this is occuring on the main thread.
*/
public void trySendPackets(boolean onMainThread) {
// Whether or not to continue sending packets
boolean sending = true;
-
+
// Transmit as many packets as we can
while (sending) {
PacketEventHolder holder = sendingQueue.poll();
-
+
if (holder != null) {
sending = processPacketHolder(onMainThread, holder);
-
+
if (!sending) {
// Add it back again
sendingQueue.add(holder);
}
-
+
} else {
// No more packets to send
sending = false;
}
}
}
-
+
/**
* Invoked when a packet might be ready for transmission.
+ *
* @param onMainThread - TRUE if we're on the main thread, FALSE otherwise.
- * @param holder - packet container.
+ * @param holder - packet container.
* @return TRUE to continue sending packets, FALSE otherwise.
*/
private boolean processPacketHolder(boolean onMainThread, final PacketEventHolder holder) {
PacketEvent current = holder.getEvent();
AsyncMarker marker = current.getAsyncMarker();
boolean hasExpired = marker.hasExpired();
-
+
// Guard in cause the queue is closed
if (cleanedUp) {
return true;
}
-
+
// End condition?
if (marker.isProcessed() || hasExpired) {
if (hasExpired) {
// Notify timeout listeners
onPacketTimeout(current);
-
+
// Recompute
marker = current.getAsyncMarker();
hasExpired = marker.hasExpired();
-
+
// Could happen due to the timeout listeners
if (!marker.isProcessed() && !hasExpired) {
return false;
}
}
-
+
// Is it okay to send the packet?
if (!current.isCancelled() && !hasExpired) {
// Make sure we're on the main thread
@@ -191,12 +189,12 @@ private boolean processPacketHolder(boolean onMainThread, final PacketEventHolde
try {
boolean wantAsync = marker.isMinecraftAsync(current);
boolean wantSync = !wantAsync;
-
+
// Wait for the next main thread heartbeat if we haven't fulfilled our promise
if (!onMainThread && wantSync) {
return false;
}
-
+
// Let's give it what it wants
if (onMainThread && wantAsync) {
asynchronousSender.execute(new Runnable() {
@@ -206,50 +204,51 @@ public void run() {
processPacketHolder(false, holder);
}
});
-
+
// Scheduler will do the rest
return true;
}
-
+
} catch (FieldAccessException e) {
e.printStackTrace();
-
+
// Just drop the packet
return true;
}
- }
-
+ }
+
// Silently skip players that have logged out
if (isOnline(current.getPlayer())) {
sendPacket(current);
}
- }
-
+ }
+
// Drop the packet
return true;
}
-
+
// Add it back and stop sending
return false;
}
-
+
/**
* Invoked when a packet has timed out.
+ *
* @param event - the timed out packet.
*/
protected abstract void onPacketTimeout(PacketEvent event);
-
+
private boolean isOnline(Player player) {
return player != null && player.isOnline();
}
-
+
/**
* Send every packet, regardless of the processing state.
*/
private void forceSend() {
while (true) {
PacketEventHolder holder = sendingQueue.poll();
-
+
if (holder != null) {
sendPacket(holder.getEvent());
} else {
@@ -257,9 +256,10 @@ private void forceSend() {
}
}
}
-
+
/**
* Whether or not the packet transmission must synchronize with the main thread.
+ *
* @return TRUE if it must, FALSE otherwise.
*/
public boolean isSynchronizeMain() {
@@ -268,24 +268,16 @@ public boolean isSynchronizeMain() {
/**
* Transmit a packet, if it hasn't already.
+ *
* @param event - the packet to transmit.
*/
private void sendPacket(PacketEvent event) {
-
- AsyncMarker marker = event.getAsyncMarker();
-
try {
// Don't send a packet twice
+ AsyncMarker marker = event.getAsyncMarker();
if (marker != null && !marker.isTransmitted()) {
marker.sendPacket(event);
}
-
- } catch (PlayerLoggedOutException e) {
- ProtocolLibrary.getErrorReporter().reportDebug(this, Report.newBuilder(REPORT_DROPPED_PACKET).
- messageParam(marker.getOriginalSendingIndex(), event.getPacketType()).
- callerParam(event)
- );
-
} catch (IOException e) {
// Just print the error
e.printStackTrace();
@@ -299,7 +291,7 @@ public void cleanupAll() {
if (!cleanedUp) {
// Note that the cleanup itself will always occur on the main thread
forceSend();
-
+
// And we're done
cleanedUp = true;
}
diff --git a/src/main/java/com/comphenix/protocol/concurrency/AbstractConcurrentListenerMultimap.java b/src/main/java/com/comphenix/protocol/concurrency/AbstractConcurrentListenerMultimap.java
index 589972fac..86d513a4c 100644
--- a/src/main/java/com/comphenix/protocol/concurrency/AbstractConcurrentListenerMultimap.java
+++ b/src/main/java/com/comphenix/protocol/concurrency/AbstractConcurrentListenerMultimap.java
@@ -2,21 +2,25 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
- * This program is free software; you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation; either version 2 of
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * You should have received a copy of the GNU General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.concurrency;
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.ListeningWhitelist;
+import com.comphenix.protocol.injector.PrioritizedListener;
+import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -24,81 +28,78 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.events.ListeningWhitelist;
-import com.comphenix.protocol.injector.PrioritizedListener;
-import com.google.common.collect.Iterables;
-
/**
* A thread-safe implementation of a listener multimap.
- *
+ *
* @author Kristian
*/
-public abstract class AbstractConcurrentListenerMultimap {
+public abstract class AbstractConcurrentListenerMultimap {
+
// The core of our map
- private ConcurrentMap>> mapListeners;
-
+ private final ConcurrentMap>> mapListeners;
+
public AbstractConcurrentListenerMultimap() {
- mapListeners = new ConcurrentHashMap>>();
+ this.mapListeners = new ConcurrentHashMap<>();
}
-
+
/**
* Adds a listener to its requested list of packet receivers.
- * @param listener - listener with a list of packets to receive notifications for.
+ *
+ * @param listener - listener with a list of packets to receive notifications for.
* @param whitelist - the packet whitelist to use.
*/
- public void addListener(TListener listener, ListeningWhitelist whitelist) {
- PrioritizedListener prioritized = new PrioritizedListener(listener, whitelist.getPriority());
-
+ public void addListener(T listener, ListeningWhitelist whitelist) {
+ PrioritizedListener prioritized = new PrioritizedListener<>(listener, whitelist.getPriority());
for (PacketType type : whitelist.getTypes()) {
- addListener(type, prioritized);
+ this.addListener(type, prioritized);
}
}
-
+
// Add the listener to a specific packet notifcation list
- private void addListener(PacketType type, PrioritizedListener listener) {
- SortedCopyOnWriteArray> list = mapListeners.get(type);
-
+ private void addListener(PacketType type, PrioritizedListener listener) {
+ SortedCopyOnWriteArray> list = this.mapListeners.get(type);
+
// We don't want to create this for every lookup
if (list == null) {
// It would be nice if we could use a PriorityBlockingQueue, but it doesn't preseve iterator order,
// which is a essential feature for our purposes.
- final SortedCopyOnWriteArray> value = new SortedCopyOnWriteArray>();
+ final SortedCopyOnWriteArray> value = new SortedCopyOnWriteArray>();
// We may end up creating multiple multisets, but we'll agree on which to use
- list = mapListeners.putIfAbsent(type, value);
-
+ list = this.mapListeners.putIfAbsent(type, value);
+
if (list == null) {
list = value;
}
}
-
+
// Thread safe
list.add(listener);
}
-
+
/**
* Removes the given listener from the packet event list.
- * @param listener - listener to remove.
+ *
+ * @param listener - listener to remove.
* @param whitelist - the packet whitelist that was used.
* @return Every packet ID that was removed due to no listeners.
*/
- public List removeListener(TListener listener, ListeningWhitelist whitelist) {
+ public List removeListener(T listener, ListeningWhitelist whitelist) {
List removedPackets = new ArrayList();
-
+
// Again, not terribly efficient. But adding or removing listeners should be a rare event.
for (PacketType type : whitelist.getTypes()) {
- SortedCopyOnWriteArray> list = mapListeners.get(type);
-
+ SortedCopyOnWriteArray> list = this.mapListeners.get(type);
+
// Remove any listeners
if (list != null) {
// Don't remove from newly created lists
if (list.size() > 0) {
// Remove this listener. Note that priority is generally ignored.
- list.remove(new PrioritizedListener(listener, whitelist.getPriority()));
-
+ list.remove(new PrioritizedListener(listener, whitelist.getPriority()));
+
if (list.size() == 0) {
- mapListeners.remove(type);
+ this.mapListeners.remove(type);
removedPackets.add(type);
}
}
@@ -107,38 +108,41 @@ public List removeListener(TListener listener, ListeningWhitelist wh
}
return removedPackets;
}
-
+
/**
* Retrieve the registered listeners, in order from the lowest to the highest priority.
*
* The returned list is thread-safe and doesn't require synchronization.
+ *
* @param type - packet type.
* @return Registered listeners.
*/
- public Collection> getListener(PacketType type) {
- return mapListeners.get(type);
+ public Collection> getListener(PacketType type) {
+ return this.mapListeners.get(type);
}
-
+
/**
* Retrieve every listener.
+ *
* @return Every listener.
*/
- public Iterable> values() {
- return Iterables.concat(mapListeners.values());
+ public Iterable> values() {
+ return Iterables.concat(this.mapListeners.values());
}
-
+
/**
* Retrieve every registered packet type:
+ *
* @return Registered packet type.
*/
public Set keySet() {
- return mapListeners.keySet();
+ return this.mapListeners.keySet();
}
-
+
/**
* Remove all packet listeners.
*/
protected void clearListeners() {
- mapListeners.clear();
+ this.mapListeners.clear();
}
}
diff --git a/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java b/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java
index 0b73e764c..5231a7a56 100644
--- a/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java
+++ b/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java
@@ -1,125 +1,135 @@
package com.comphenix.protocol.concurrency;
+import com.comphenix.protocol.PacketType;
+import com.google.common.collect.ImmutableSet;
import java.util.Collection;
-import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
-import com.comphenix.protocol.PacketType;
-import com.comphenix.protocol.injector.packet.PacketRegistry;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
/**
* Represents a concurrent set of packet types.
+ *
* @author Kristian
*/
public class PacketTypeSet {
- private Set types = Collections.newSetFromMap(Maps.newConcurrentMap());
- private Set> classes = Collections.newSetFromMap(Maps., Boolean>newConcurrentMap());
-
+
+ private final Set types;
+ private final Set> classes;
+
public PacketTypeSet() {
- // Do nothing
+ this.types = new HashSet<>(16, 0.9f);
+ this.classes = new HashSet<>(16, 0.9f);
}
-
+
public PacketTypeSet(Collection extends PacketType> values) {
+ this.types = new HashSet<>(values.size(), 0.9f);
+ this.classes = new HashSet<>(values.size(), 0.9f);
+
for (PacketType type : values) {
- addType(type);
+ this.addType(type);
}
}
-
+
/**
* Add a particular type to the set.
+ *
* @param type - the type to add.
*/
- public synchronized void addType(PacketType type) {
+ public void addType(PacketType type) {
+ this.types.add(type);
+
Class> packetClass = type.getPacketClass();
- types.add(Preconditions.checkNotNull(type, "type cannot be NULL."));
-
if (packetClass != null) {
- classes.add(type.getPacketClass());
+ this.classes.add(packetClass);
}
}
-
+
/**
* Add the given types to the set of packet types.
+ *
* @param types - the types to add.
*/
- public synchronized void addAll(Iterable extends PacketType> types) {
+ public void addAll(Iterable extends PacketType> types) {
for (PacketType type : types) {
- addType(type);
+ this.addType(type);
}
}
-
+
/**
* Remove a particular type to the set.
+ *
* @param type - the type to remove.
*/
- public synchronized void removeType(PacketType type) {
+ public void removeType(PacketType type) {
+ this.types.remove(type);
+
Class> packetClass = type.getPacketClass();
- types.remove(Preconditions.checkNotNull(type, "type cannot be NULL."));
-
if (packetClass != null) {
- classes.remove(packetClass);
+ this.classes.remove(packetClass);
}
}
-
+
/**
* Remove the given types from the set.
+ *
* @param types Types to remove
*/
- public synchronized void removeAll(Iterable extends PacketType> types) {
+ public void removeAll(Iterable extends PacketType> types) {
for (PacketType type : types) {
- removeType(type);
+ this.removeType(type);
}
}
/**
* Determine if the given packet type exists in the set.
+ *
* @param type - the type to find.
* @return TRUE if it does, FALSE otherwise.
*/
public boolean contains(PacketType type) {
- return types.contains(type);
+ return this.types.contains(type);
}
-
+
/**
* Determine if a packet type with the given packet class exists in the set.
+ *
* @param packetClass - the class to find.
* @return TRUE if it does, FALSE otherwise.
*/
public boolean contains(Class> packetClass) {
- return classes.contains(packetClass);
+ return this.classes.contains(packetClass);
}
-
+
/**
* Determine if the type of a packet is in the current set.
+ *
* @param packet - the packet.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean containsPacket(Object packet) {
- if (packet == null)
- return false;
- return classes.contains(packet.getClass());
+ return packet != null && this.classes.contains(packet.getClass());
}
-
+
/**
* Retrieve a view of this packet type set.
+ *
* @return The packet type values.
*/
public Set values() {
- return types;
+ return ImmutableSet.copyOf(this.types);
}
-
+
/**
* Retrieve the number of entries in the set.
+ *
* @return The number of entries.
*/
public int size() {
- return types.size();
+ return this.types.size();
}
-
- public synchronized void clear() {
- types.clear();
- classes.clear();
+
+ public void clear() {
+ this.types.clear();
+ this.classes.clear();
}
}
diff --git a/src/main/java/com/comphenix/protocol/concurrency/SortedCopyOnWriteArray.java b/src/main/java/com/comphenix/protocol/concurrency/SortedCopyOnWriteArray.java
index ed1d84c8d..06a6d9fc1 100644
--- a/src/main/java/com/comphenix/protocol/concurrency/SortedCopyOnWriteArray.java
+++ b/src/main/java/com/comphenix/protocol/concurrency/SortedCopyOnWriteArray.java
@@ -2,243 +2,260 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
- * This program is free software; you can redistribute it and/or modify it under the terms of the
- * GNU General Public License as published by the Free Software Foundation; either version 2 of
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * You should have received a copy of the GNU General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.concurrency;
+import com.google.common.base.Objects;
+import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
-import com.google.common.base.Objects;
-import com.google.common.collect.Iterables;
-
/**
* An implicitly sorted array list that preserves insertion order and maintains duplicates.
+ *
* @param - type of the elements in the list.
*/
public class SortedCopyOnWriteArray> implements Collection {
+
// Prevent reordering
private volatile List list;
-
+
/**
* Construct an empty sorted array.
*/
public SortedCopyOnWriteArray() {
- list = new ArrayList();
+ this.list = new LinkedList<>();
}
-
+
/**
* Create a sorted array from the given list. The elements will be automatically sorted.
+ *
* @param wrapped - the collection whose elements are to be placed into the list.
*/
public SortedCopyOnWriteArray(Collection wrapped) {
- this.list = new ArrayList(wrapped);
+ this.list = new LinkedList<>(wrapped);
}
-
+
/**
- * Create a sorted array from the given list.
+ * Create a sorted array from the given list.
+ *
* @param wrapped - the collection whose elements are to be placed into the list.
- * @param sort - TRUE to automatically sort the collection, FALSE if it is already sorted.
+ * @param sort - TRUE to automatically sort the collection, FALSE if it is already sorted.
*/
public SortedCopyOnWriteArray(Collection wrapped, boolean sort) {
this.list = new ArrayList(wrapped);
-
+
if (sort) {
- Collections.sort(list);
+ Collections.sort(this.list);
}
}
-
+
/**
* Inserts the given element in the proper location.
+ *
* @param value - element to insert.
*/
@Override
public synchronized boolean add(T value) {
- // We use NULL as a special marker, so we don't allow it
- if (value == null)
- throw new IllegalArgumentException("value cannot be NULL");
-
- List copy = new ArrayList();
-
- for (T element : list) {
- // If the value is now greater than the current element, it should be placed right before it
- if (value != null && value.compareTo(element) < 0) {
- copy.add(value);
- value = null;
- }
- copy.add(element);
- }
-
- // Don't forget to add it
- if (value != null)
- copy.add(value);
-
- list = copy;
- return true;
- }
-
+ // We use NULL as a special marker, so we don't allow it
+ if (value == null) {
+ throw new IllegalArgumentException("value cannot be NULL");
+ }
+
+ List copy = new ArrayList();
+
+ for (T element : this.list) {
+ // If the value is now greater than the current element, it should be placed right before it
+ if (value != null && value.compareTo(element) < 0) {
+ copy.add(value);
+ value = null;
+ }
+ copy.add(element);
+ }
+
+ // Don't forget to add it
+ if (value != null) {
+ copy.add(value);
+ }
+
+ this.list = copy;
+ return true;
+ }
+
@Override
- public synchronized boolean addAll(Collection extends T> values) {
- if (values == null)
+ public synchronized boolean addAll(Collection extends T> values) {
+ if (values == null) {
throw new IllegalArgumentException("values cannot be NULL");
- if (values.size() == 0)
+ }
+ if (values.size() == 0) {
return false;
-
- List copy = new ArrayList();
-
- // Insert the new content and sort it
- copy.addAll(list);
- copy.addAll(values);
- Collections.sort(copy);
-
- list = copy;
- return true;
- }
-
- /**
- * Removes from the list by making a new list with every element except the one given.
- *
- * Objects will be compared using the given objects equals() method.
- * @param value - value to remove.
- */
+ }
+
+ List copy = new ArrayList();
+
+ // Insert the new content and sort it
+ copy.addAll(this.list);
+ copy.addAll(values);
+ Collections.sort(copy);
+
+ this.list = copy;
+ return true;
+ }
+
+ /**
+ * Removes from the list by making a new list with every element except the one given.
+ *
+ * Objects will be compared using the given objects equals() method.
+ *
+ * @param value - value to remove.
+ */
@Override
- public synchronized boolean remove(Object value) {
- List copy = new ArrayList();
- boolean result = false;
-
- // Note that there's not much to be gained from using BinarySearch, as we
- // have to copy (and thus read) the entire list regardless.
-
- // Copy every element except the one given to us.
- for (T element : list) {
- if (!Objects.equal(value, element)) {
- copy.add(element);
- } else {
- result = true;
- }
- }
-
- list = copy;
- return result;
- }
-
+ public synchronized boolean remove(Object value) {
+ List copy = new ArrayList();
+ boolean result = false;
+
+ // Note that there's not much to be gained from using BinarySearch, as we
+ // have to copy (and thus read) the entire list regardless.
+
+ // Copy every element except the one given to us.
+ for (T element : this.list) {
+ if (!Objects.equal(value, element)) {
+ copy.add(element);
+ } else {
+ result = true;
+ }
+ }
+
+ this.list = copy;
+ return result;
+ }
+
@Override
public boolean removeAll(Collection> values) {
// Special cases
- if (values == null)
+ if (values == null) {
throw new IllegalArgumentException("values cannot be NULL");
- if (values.size() == 0)
+ }
+ if (values.size() == 0) {
return false;
-
+ }
+
List copy = new ArrayList();
-
- copy.addAll(list);
+
+ copy.addAll(this.list);
copy.removeAll(values);
-
- list = copy;
+
+ this.list = copy;
return true;
}
@Override
public boolean retainAll(Collection> values) {
// Special cases
- if (values == null)
+ if (values == null) {
throw new IllegalArgumentException("values cannot be NULL");
- if (values.size() == 0)
+ }
+ if (values.size() == 0) {
return false;
-
+ }
+
List copy = new ArrayList();
-
- copy.addAll(list);
+
+ copy.addAll(this.list);
copy.removeAll(values);
-
- list = copy;
+
+ this.list = copy;
return true;
}
-
- /**
- * Removes from the list by making a copy of every element except the one with the given index.
- * @param index - index of the element to remove.
- */
- public synchronized void remove(int index) {
- List copy = new ArrayList(list);
-
- copy.remove(index);
- list = copy;
- }
-
- /**
- * Retrieves an element by index.
- * @param index - index of element to retrieve.
- * @return The element at the given location.
- */
- public T get(int index) {
- return list.get(index);
- }
-
- /**
- * Retrieve the size of the list.
- * @return Size of the list.
- */
- public int size() {
- return list.size();
- }
-
- /**
- * Retrieves an iterator over the elements in the given list.
- * Warning: No not attempt to remove elements using the iterator.
- */
+
+ /**
+ * Removes from the list by making a copy of every element except the one with the given index.
+ *
+ * @param index - index of the element to remove.
+ */
+ public synchronized void remove(int index) {
+ List copy = new ArrayList(this.list);
+
+ copy.remove(index);
+ this.list = copy;
+ }
+
+ /**
+ * Retrieves an element by index.
+ *
+ * @param index - index of element to retrieve.
+ * @return The element at the given location.
+ */
+ public T get(int index) {
+ return this.list.get(index);
+ }
+
+ /**
+ * Retrieve the size of the list.
+ *
+ * @return Size of the list.
+ */
+ public int size() {
+ return this.list.size();
+ }
+
+ /**
+ * Retrieves an iterator over the elements in the given list. Warning: No not attempt to remove elements using the
+ * iterator.
+ */
public Iterator iterator() {
- return Iterables.unmodifiableIterable(list).iterator();
+ return Iterables.unmodifiableIterable(this.list).iterator();
}
-
+
@Override
public void clear() {
- list = new ArrayList();
+ this.list = new ArrayList();
}
@Override
public boolean contains(Object value) {
- return list.contains(value);
+ return this.list.contains(value);
}
@Override
public boolean containsAll(Collection> values) {
- return list.containsAll(values);
+ return this.list.containsAll(values);
}
@Override
public boolean isEmpty() {
- return list.isEmpty();
+ return this.list.isEmpty();
}
@Override
public Object[] toArray() {
- return list.toArray();
+ return this.list.toArray();
}
@SuppressWarnings("hiding")
@Override
public T[] toArray(T[] a) {
- return list.toArray(a);
+ return this.list.toArray(a);
}
-
+
@Override
public String toString() {
- return list.toString();
+ return this.list.toString();
}
}
diff --git a/src/main/java/com/comphenix/protocol/events/ListenerOptions.java b/src/main/java/com/comphenix/protocol/events/ListenerOptions.java
index 590149347..3233796ba 100644
--- a/src/main/java/com/comphenix/protocol/events/ListenerOptions.java
+++ b/src/main/java/com/comphenix/protocol/events/ListenerOptions.java
@@ -2,29 +2,24 @@
import com.comphenix.protocol.injector.GamePhase;
-
/**
* Represents additional options a listener may require.
- *
+ *
* @author Kristian
*/
public enum ListenerOptions {
+
/**
- * Retrieve the serialized client packet as it appears on the network stream.
- */
- INTERCEPT_INPUT_BUFFER,
-
- /**
- * Disable the automatic game phase detection that will normally force {@link GamePhase#LOGIN} when
- * a packet ID is known to be transmitted during login.
+ * Disable the automatic game phase detection that will normally force {@link GamePhase#LOGIN} when a packet ID is
+ * known to be transmitted during login.
*/
DISABLE_GAMEPHASE_DETECTION,
-
+
/**
* Do not verify that the owning plugin has a vaid plugin.yml.
*/
SKIP_PLUGIN_VERIFIER,
-
+
/**
* Notify ProtocolLib that {@link PacketListener#onPacketSending(PacketEvent)} is thread safe.
*/
diff --git a/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java b/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java
index 01a5c974d..6923b933d 100644
--- a/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java
+++ b/src/main/java/com/comphenix/protocol/events/ListeningWhitelist.java
@@ -17,20 +17,24 @@
package com.comphenix.protocol.events;
-import java.util.*;
-
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.injector.GamePhase;
-import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.google.common.base.Objects;
import com.google.common.collect.Sets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
/**
* Determines which packets will be observed by a listener, and with what priority.
-
+ *
* @author Kristian
*/
public class ListeningWhitelist {
+
/**
* A whitelist with no packets - indicates that the listener shouldn't observe any packets.
*/
@@ -55,8 +59,72 @@ private ListeningWhitelist(ListenerPriority priority) {
this.options = EnumSet.noneOf(ListenerOptions.class);
}
+ /**
+ * Determine if the given whitelist is empty or not.
+ *
+ * @param whitelist - the whitelist to test.
+ * @return TRUE if the whitelist is empty, FALSE otherwise.
+ */
+ public static boolean isEmpty(ListeningWhitelist whitelist) {
+ if (whitelist == EMPTY_WHITELIST) {
+ return true;
+ } else if (whitelist == null) {
+ return true;
+ } else {
+ return whitelist.getTypes().isEmpty();
+ }
+ }
+
+ /**
+ * Construct a new builder of whitelists.
+ *
+ * @return New whitelist builder.
+ */
+ public static Builder newBuilder() {
+ return new Builder(null);
+ }
+
+ /**
+ * Construct a new builder of whitelists initialized to the same values as the template.
+ *
+ * @param template - the template object.
+ * @return New whitelist builder.
+ */
+ public static Builder newBuilder(ListeningWhitelist template) {
+ return new Builder(template);
+ }
+
+ /**
+ * Construct a copy of a given enum.
+ *
+ * @param options - the options to copy, or NULL to indicate the empty set.
+ * @return A copy of the enum set.
+ */
+ private static > EnumSet safeEnumSet(Collection options, Class enumClass) {
+ if (options != null && !options.isEmpty()) {
+ return EnumSet.copyOf(options);
+ } else {
+ return EnumSet.noneOf(enumClass);
+ }
+ }
+
+ /**
+ * Construct a copy of a given set.
+ *
+ * @param set - the set to copy.
+ * @return The copied set.
+ */
+ private static Set safeSet(Collection set) {
+ if (set != null) {
+ return Sets.newHashSet(set);
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
/**
* Whether or not this whitelist has any enabled packets.
+ *
* @return TRUE if there are any packets, FALSE otherwise.
*/
public boolean isEnabled() {
@@ -65,6 +133,7 @@ public boolean isEnabled() {
/**
* Retrieve the priority in the execution order of the packet listener. Highest priority will be executed last.
+ *
* @return Execution order in terms of priority.
*/
public ListenerPriority getPriority() {
@@ -73,22 +142,25 @@ public ListenerPriority getPriority() {
/**
* Retrieves a set of the packets that will be observed by the listeners.
+ *
* @return Packet whitelist.
*/
public Set getTypes() {
return types;
}
-
+
/**
* Retrieve which game phase this listener is active under.
+ *
* @return The active game phase.
*/
public GamePhase getGamePhase() {
return gamePhase;
}
-
+
/**
* Retrieve every special option associated with this whitelist.
+ *
* @return Every special option.
*/
public Set getOptions() {
@@ -100,20 +172,6 @@ public int hashCode() {
return Objects.hashCode(priority, types, gamePhase, options);
}
- /**
- * Determine if the given whitelist is empty or not.
- * @param whitelist - the whitelist to test.
- * @return TRUE if the whitelist is empty, FALSE otherwise.
- */
- public static boolean isEmpty(ListeningWhitelist whitelist) {
- if (whitelist == EMPTY_WHITELIST)
- return true;
- else if (whitelist == null)
- return true;
- else
- return whitelist.getTypes().isEmpty();
- }
-
@Override
public boolean equals(final Object obj) {
if (obj instanceof ListeningWhitelist) {
@@ -129,67 +187,30 @@ public boolean equals(final Object obj) {
@Override
public String toString() {
- if (this == EMPTY_WHITELIST)
+ if (this == EMPTY_WHITELIST) {
return "EMPTY_WHITELIST";
- else
- return "ListeningWhitelist[priority=" + priority + ", packets=" + types + ", gamephase=" + gamePhase + ", options=" + options + "]";
- }
-
- /**
- * Construct a new builder of whitelists.
- * @return New whitelist builder.
- */
- public static Builder newBuilder() {
- return new Builder(null);
- }
-
- /**
- * Construct a new builder of whitelists initialized to the same values as the template.
- * @param template - the template object.
- * @return New whitelist builder.
- */
- public static Builder newBuilder(ListeningWhitelist template) {
- return new Builder(template);
- }
-
- /**
- * Construct a copy of a given enum.
- * @param options - the options to copy, or NULL to indicate the empty set.
- * @return A copy of the enum set.
- */
- private static > EnumSet safeEnumSet(Collection options, Class enumClass) {
- if (options != null && !options.isEmpty()) {
- return EnumSet.copyOf(options);
} else {
- return EnumSet.noneOf(enumClass);
+ return "ListeningWhitelist[priority=" + priority + ", packets=" + types + ", gamephase=" + gamePhase
+ + ", options=" + options + "]";
}
}
-
- /**
- * Construct a copy of a given set.
- * @param set - the set to copy.
- * @return The copied set.
- */
- private static Set safeSet(Collection set) {
- if (set != null)
- return Sets.newHashSet(set);
- else
- return Collections.emptySet();
- }
/**
* Represents a builder of whitelists.
+ *
* @author Kristian
*/
public static class Builder {
+
// Default values
private ListenerPriority priority = ListenerPriority.NORMAL;
private Set types = Sets.newHashSet();
private GamePhase gamePhase = GamePhase.PLAYING;
private Set options = Sets.newHashSet();
-
+
/**
* Construct a new listening whitelist template.
+ *
* @param template - the template.
*/
private Builder(ListeningWhitelist template) {
@@ -200,9 +221,10 @@ private Builder(ListeningWhitelist template) {
options(template.getOptions());
}
}
-
+
/**
* Set the priority to use when constructing new whitelists.
+ *
* @param priority - the priority.
* @return This builder, for chaining.
*/
@@ -210,49 +232,55 @@ public Builder priority(ListenerPriority priority) {
this.priority = priority;
return this;
}
-
+
/**
* Set the priority of the whitelist to monitor.
+ *
* @return This builder, for chaining.
*/
public Builder monitor() {
return priority(ListenerPriority.MONITOR);
}
-
+
/**
* Set the priority of the whitelist to normal.
+ *
* @return This builder, for chaining.
*/
public Builder normal() {
return priority(ListenerPriority.NORMAL);
}
-
+
/**
* Set the priority of the whitelist to lowest.
+ *
* @return This builder, for chaining.
*/
public Builder lowest() {
return priority(ListenerPriority.LOWEST);
}
-
+
/**
* Set the priority of the whitelist to low.
+ *
* @return This builder, for chaining.
*/
public Builder low() {
return priority(ListenerPriority.LOW);
}
-
+
/**
* Set the priority of the whitelist to highest.
+ *
* @return This builder, for chaining.
*/
public Builder highest() {
return priority(ListenerPriority.HIGHEST);
}
-
+
/**
* Set the priority of the whitelist to high.
+ *
* @return This builder, for chaining.
*/
public Builder high() {
@@ -261,6 +289,7 @@ public Builder high() {
/**
* Set the whitelist of packet types to copy when constructing new whitelists.
+ *
* @param types - the whitelist of packets.
* @return This builder, for chaining.
*/
@@ -268,9 +297,10 @@ public Builder types(PacketType... types) {
this.types = safeSet(Sets.newHashSet(types));
return this;
}
-
+
/**
* Set the whitelist of packet types to copy when constructing new whitelists.
+ *
* @param types - the whitelist of packets.
* @return This builder, for chaining.
*/
@@ -278,9 +308,10 @@ public Builder types(Collection types) {
this.types = safeSet(types);
return this;
}
-
+
/**
* Set the gamephase to use when constructing new whitelists.
+ *
* @param gamePhase - the gamephase.
* @return This builder, for chaining.
*/
@@ -288,16 +319,19 @@ public Builder gamePhase(GamePhase gamePhase) {
this.gamePhase = gamePhase;
return this;
}
-
+
/**
* Set the gamephase to {@link GamePhase#BOTH}.
+ *
* @return This builder, for chaining.
*/
public Builder gamePhaseBoth() {
return gamePhase(GamePhase.BOTH);
}
+
/**
* Set the options to copy when constructing new whitelists.
+ *
* @param options - the options.
* @return This builder, for chaining.
*/
@@ -305,9 +339,10 @@ public Builder options(Set options) {
this.options = safeSet(options);
return this;
}
-
+
/**
* Set the options to copy when constructing new whitelists.
+ *
* @param options - the options.
* @return This builder, for chaining.
*/
@@ -315,9 +350,10 @@ public Builder options(Collection options) {
this.options = safeSet(options);
return this;
}
-
+
/**
* Set the options to copy when constructing new whitelists.
+ *
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
@@ -325,32 +361,36 @@ public Builder options(ListenerOptions[] serverOptions) {
this.options = safeSet(Sets.newHashSet(serverOptions));
return this;
}
-
+
/**
* Options to merge into the current set of options.
+ *
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(ListenerOptions... serverOptions) {
return mergeOptions(Arrays.asList(serverOptions));
}
-
+
/**
* Options to merge into the current set of options.
+ *
* @param serverOptions - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(Collection serverOptions) {
- if (options == null)
+ if (options == null) {
return options(serverOptions);
-
+ }
+
// Merge the options
this.options.addAll(serverOptions);
return this;
}
-
+
/**
* Construct a new whitelist from the values in this builder.
+ *
* @return The new whitelist.
*/
public ListeningWhitelist build() {
diff --git a/src/main/java/com/comphenix/protocol/events/NetworkMarker.java b/src/main/java/com/comphenix/protocol/events/NetworkMarker.java
index 0ff7a79e0..2231e88b9 100644
--- a/src/main/java/com/comphenix/protocol/events/NetworkMarker.java
+++ b/src/main/java/com/comphenix/protocol/events/NetworkMarker.java
@@ -1,421 +1,155 @@
package com.comphenix.protocol.events;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.PriorityQueue;
-
-import javax.annotation.Nonnull;
-
-import org.bukkit.entity.Player;
-
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolManager;
-import com.comphenix.protocol.utility.ByteBufferInputStream;
-import com.comphenix.protocol.utility.MinecraftReflection;
-import com.comphenix.protocol.utility.StreamSerializer;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.primitives.Ints;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.bukkit.entity.Player;
/**
- * Marker containing the serialized packet data seen from the network,
- * or output handlers that will serialize the current packet.
- *
+ * Marker containing the serialized packet data seen from the network, or output handlers that will serialize the
+ * current packet.
+ *
* @author Kristian
*/
-public abstract class NetworkMarker {
- public static class EmptyBufferMarker extends NetworkMarker {
- public EmptyBufferMarker(@Nonnull ConnectionSide side) {
- super(side, (byte[]) null, null);
- }
+public class NetworkMarker {
- @Override
- protected DataInputStream skipHeader(DataInputStream input) throws IOException {
- throw new IllegalStateException("Buffer is empty.");
- }
+ // The input data
+ private final PacketType type;
+ private final ConnectionSide side;
- @Override
- protected ByteBuffer addHeader(ByteBuffer buffer, PacketType type) {
- throw new IllegalStateException("Buffer is empty.");
- }
+ // Post-processing of the packet
+ private Set postListeners;
+ private Set scheduledPackets;
- @Override
- protected DataInputStream addHeader(DataInputStream input, PacketType type) {
- throw new IllegalStateException("Buffer is empty.");
- }
- }
-
- // Custom network handler
- private PriorityQueue outputHandlers;
- // Post listeners
- private List postListeners;
- // Post packets
- private List scheduledPackets;
-
- // The input buffer
- private ByteBuffer inputBuffer;
- private final ConnectionSide side;
- private final PacketType type;
-
- // Cache serializer too
- private StreamSerializer serializer;
-
- /**
- * Construct a new network marker.
- * @param side - which side this marker belongs to.
- * @param inputBuffer - the read serialized packet data.
- * @param type - packet type
- */
- public NetworkMarker(@Nonnull ConnectionSide side, ByteBuffer inputBuffer, PacketType type) {
- this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
- this.inputBuffer = inputBuffer;
- this.type = type;
- }
-
/**
* Construct a new network marker.
*
* The input buffer is only non-null for client-side packets.
+ *
* @param side - which side this marker belongs to.
- * @param inputBuffer - the read serialized packet data.
* @param type - packet type
*/
- public NetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer, PacketType type) {
+ public NetworkMarker(@Nonnull ConnectionSide side, PacketType type) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
this.type = type;
-
- if (inputBuffer != null) {
- this.inputBuffer = ByteBuffer.wrap(inputBuffer);
- }
- }
-
- /**
- * Retrieve whether or not this marker belongs to a client or a server side packet.
- * @return The side the parent packet belongs to.
- */
- public ConnectionSide getSide() {
- return side;
}
/**
- * Retrieve a utility class for serializing and deserializing Minecraft objects.
- * @return Serialization utility class.
- */
- public StreamSerializer getSerializer() {
- if (serializer == null)
- serializer = new StreamSerializer();
- return serializer;
- }
-
- /**
- * Retrieve the serialized packet data (excluding the header by default) from the network input stream.
- *
- * The returned buffer is read-only. If the parent event is a server side packet this
- * method throws {@link IllegalStateException}.
- *
- * It returns NULL if the packet was transmitted by a plugin locally.
- * @return A byte buffer containing the raw packet data read from the network.
- */
- public ByteBuffer getInputBuffer() {
- return getInputBuffer(true);
- }
-
- /**
- * Retrieve the serialized packet data from the network input stream.
- *
- * The returned buffer is read-only. If the parent event is a server side packet this
- * method throws {@link IllegalStateException}.
- *
- * It returns NULL if the packet was transmitted by a plugin locally.
- * @param excludeHeader - whether or not to exclude the packet ID header.
- * @return A byte buffer containing the raw packet data read from the network.
- */
- public ByteBuffer getInputBuffer(boolean excludeHeader) {
- if (side.isForServer())
- throw new IllegalStateException("Server-side packets have no input buffer.");
-
- if (inputBuffer != null) {
- ByteBuffer result = inputBuffer.asReadOnlyBuffer();
-
- try {
- if (excludeHeader)
- result = skipHeader(result);
- else
- result = addHeader(result, type);
- } catch (IOException e) {
- throw new RuntimeException("Cannot skip packet header.", e);
- }
- return result;
- }
- return null;
- }
-
- /**
- * Retrieve the serialized packet data (excluding the header by default) as an input stream.
- *
- * The data is exactly the same as in {@link #getInputBuffer()}.
- * @see #getInputBuffer()
- * @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
+ * Determine if the given marker has any post listeners.
+ *
+ * @param marker - the marker to check.
+ * @return TRUE if it does, FALSE otherwise.
*/
- public DataInputStream getInputStream() {
- return getInputStream(true);
+ public static boolean hasPostListeners(NetworkMarker marker) {
+ return marker != null && !marker.getPostListeners().isEmpty();
}
-
+
/**
- * Retrieve the serialized packet data as an input stream.
+ * Retrieve the network marker of a particular event without creating it.
*
- * The data is exactly the same as in {@link #getInputBuffer()}.
- * @see #getInputBuffer()
- * @param excludeHeader - whether or not to exclude the packet ID header.
- * @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
- */
- @SuppressWarnings("resource")
- public DataInputStream getInputStream(boolean excludeHeader) {
- if (side.isForServer())
- throw new IllegalStateException("Server-side packets have no input buffer.");
- if (inputBuffer == null)
- return null;
-
- DataInputStream input = new DataInputStream(
- new ByteArrayInputStream(inputBuffer.array())
- );
-
- try {
- if (excludeHeader)
- input = skipHeader(input);
- else
- input = addHeader(input, type);
- } catch (IOException e) {
- throw new RuntimeException("Cannot skip packet header.", e);
- }
- return input;
- }
-
- /**
- * Whether or not the output handlers have to write a packet header.
- * @return TRUE if they do, FALSE otherwise.
+ * This is an internal method that should not be used by API users.
+ *
+ * @param event - the event.
+ * @return The network marker.
*/
- public boolean requireOutputHeader() {
- return MinecraftReflection.isUsingNetty();
+ public static NetworkMarker getNetworkMarker(PacketEvent event) {
+ return event.networkMarker;
}
-
+
/**
- * Enqueue the given output handler for managing how the current packet will be written to the network stream.
- *
- * Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
- * It is not safe to serialize anonymous classes, as their name depend on the order in which they are declared in the parent class.
+ * Retrieve the scheduled packets of a particular network marker without constructing the list.
*
- * This can only be invoked on server side packet events.
- * @param handler - the handler that will take part in serializing the packet.
- * @return TRUE if it was added, FALSE if it has already been added.
+ * This is an internal method that should not be used by API users.
+ *
+ * @param marker - the marker.
+ * @return The list, or NULL if not found or initialized.
*/
- public boolean addOutputHandler(@Nonnull PacketOutputHandler handler) {
- checkServerSide();
- Preconditions.checkNotNull(handler, "handler cannot be NULL.");
-
- // Lazy initialization - it's imperative that we save space and time here
- if (outputHandlers == null) {
- outputHandlers = new PriorityQueue(10, new Comparator() {
- @Override
- public int compare(PacketOutputHandler o1, PacketOutputHandler o2) {
- return Ints.compare(o1.getPriority().getSlot(), o2.getPriority().getSlot());
- }
- });
- }
- return outputHandlers.add(handler);
+ public static Set readScheduledPackets(NetworkMarker marker) {
+ return marker.scheduledPackets;
}
-
+
/**
- * Remove a given output handler from the serialization queue.
- *
- * This can only be invoked on server side packet events.
- * @param handler - the handler to remove.
- * @return TRUE if the handler was removed, FALSE otherwise.
+ * Retrieve whether or not this marker belongs to a client or a server side packet.
+ *
+ * @return The side the parent packet belongs to.
*/
- public boolean removeOutputHandler(@Nonnull PacketOutputHandler handler) {
- checkServerSide();
- Preconditions.checkNotNull(handler, "handler cannot be NULL.");
-
- if (outputHandlers != null) {
- return outputHandlers.remove(handler);
- }
- return false;
+ public ConnectionSide getSide() {
+ return this.side;
}
-
- /**
- * Retrieve every registered output handler in no particular order.
- * @return Every registered output handler.
- */
- @Nonnull
- public Collection getOutputHandlers() {
- if (outputHandlers != null) {
- return outputHandlers;
- } else {
- return Collections.emptyList();
- }
+
+ public PacketType getType() {
+ return this.type;
}
-
+
/**
- * Add a listener that is invoked after a packet has been successfully sent to the client, or received
- * by the server.
+ * Add a listener that is invoked after a packet has been successfully sent to the client, or received by the server.
*
- * Received packets are not guarenteed to have been fully processed, but packets passed
- * to {@link ProtocolManager#recieveClientPacket(Player, PacketContainer)} will be processed after the
- * current packet event.
+ * Received packets are not guarenteed to have been fully processed, but packets passed to {@link
+ * ProtocolManager#receiveClientPacket(Player, PacketContainer)} will be processed after the current packet event.
*
- * Note that post listeners will be executed asynchronously off the main thread. They are not executed
- * in any defined order.
+ * Note that post listeners will be executed asynchronously off the main thread. They are not executed in any defined
+ * order.
+ *
* @param listener - the listener that will be invoked.
* @return TRUE if it was added.
*/
public boolean addPostListener(PacketPostListener listener) {
- if (postListeners == null)
- postListeners = Lists.newArrayList();
- return postListeners.add(listener);
+ if (this.postListeners == null) {
+ this.postListeners = new HashSet<>();
+ }
+
+ return this.postListeners.add(listener);
}
-
+
/**
* Remove the first instance of the given listener.
+ *
* @param listener - listener to remove.
* @return TRUE if it was removed, FALSE otherwise.
*/
public boolean removePostListener(PacketPostListener listener) {
- if (postListeners != null) {
- return postListeners.remove(listener);
+ if (this.postListeners != null) {
+ return this.postListeners.remove(listener);
}
+
return false;
}
-
+
/**
* Retrieve an immutable view of all the listeners that will be invoked once the packet has been sent or received.
+ *
* @return Every post packet listener. Never NULL.
*/
- public List getPostListeners() {
- return postListeners != null ? Collections.unmodifiableList(postListeners) : Collections.emptyList();
+ public Set getPostListeners() {
+ return this.postListeners != null ? this.postListeners : Collections.emptySet();
}
-
+
/**
- * Retrieve a list of packets that will be schedule (in-order) when the current packet has been successfully transmitted.
+ * Retrieve a list of packets that will be schedule (in-order) when the current packet has been successfully
+ * transmitted.
*
* This list is modifiable.
+ *
* @return List of packets that will be scheduled.
*/
- public List getScheduledPackets() {
- if (scheduledPackets == null)
- scheduledPackets = Lists.newArrayList();
- return scheduledPackets;
+ public Set getScheduledPackets() {
+ if (this.scheduledPackets == null) {
+ this.scheduledPackets = new HashSet<>();
+ }
+
+ return this.scheduledPackets;
}
-
+
/**
* Ensure that the packet event is server side.
*/
private void checkServerSide() {
- if (side.isForClient()) {
+ if (this.side.isForClient()) {
throw new IllegalStateException("Must be a server side packet.");
}
}
-
- /**
- * Return a byte buffer without the header in the current packet.
- *
- * It's safe to modify the position of the buffer.
- * @param buffer - a read-only byte source.
- * @return A byte buffer without the header in the current packet.
- * @throws IOException If integer reading fails
- */
- protected ByteBuffer skipHeader(ByteBuffer buffer) throws IOException {
- skipHeader(new DataInputStream(new ByteBufferInputStream(buffer)));
- return buffer;
- }
-
- /**
- * Return an input stream without the header in the current packet.
- *
- * It's safe to modify the input stream.
- * @param input - input stream
- * @return An input stream without the header
- * @throws IOException If integer reading fails
- */
- protected abstract DataInputStream skipHeader(DataInputStream input) throws IOException;
-
- /**
- * Return the byte buffer prepended with the packet header.
- * @param buffer - the read-only byte buffer.
- * @param type - the current packet.
- * @return The byte buffer.
- */
- protected abstract ByteBuffer addHeader(ByteBuffer buffer, PacketType type);
-
- /**
- * Return the input stream prepended with the packet header.
- * @param input - the input stream.
- * @param type - the current packet.
- * @return The byte buffer.
- */
- protected abstract DataInputStream addHeader(DataInputStream input, PacketType type);
-
- /**
- * Determine if the given marker has any output handlers.
- * @param marker - the marker to check.
- * @return TRUE if it does, FALSE otherwise.
- */
- public static boolean hasOutputHandlers(NetworkMarker marker) {
- return marker != null && !marker.getOutputHandlers().isEmpty();
- }
-
- /**
- * Determine if the given marker has any post listeners.
- * @param marker - the marker to check.
- * @return TRUE if it does, FALSE otherwise.
- */
- public static boolean hasPostListeners(NetworkMarker marker) {
- return marker != null && !marker.getPostListeners().isEmpty();
- }
-
- /**
- * Retrieve the byte buffer stored in the given marker.
- * @param marker - the marker.
- * @return The byte buffer, or NULL if not found.
- */
- public static byte[] getByteBuffer(NetworkMarker marker) {
- if (marker != null) {
- ByteBuffer buffer = marker.getInputBuffer();
-
- if (buffer != null) {
- byte[] data = new byte[buffer.remaining()];
-
- buffer.get(data, 0, data.length);
- return data;
- }
- }
- return null;
- }
-
- /**
- * Retrieve the network marker of a particular event without creating it.
- *
- * This is an internal method that should not be used by API users.
- * @param event - the event.
- * @return The network marker.
- */
- public static NetworkMarker getNetworkMarker(PacketEvent event) {
- return event.networkMarker;
- }
-
- /**
- * Retrieve the scheduled packets of a particular network marker without constructing the list.
- *
- * This is an internal method that should not be used by API users.
- * @param marker - the marker.
- * @return The list, or NULL if not found or initialized.
- */
- public static List readScheduledPackets(NetworkMarker marker) {
- return marker.scheduledPackets;
- }
}
diff --git a/src/main/java/com/comphenix/protocol/events/PacketAdapter.java b/src/main/java/com/comphenix/protocol/events/PacketAdapter.java
index 29cd316e1..45a4cb36b 100644
--- a/src/main/java/com/comphenix/protocol/events/PacketAdapter.java
+++ b/src/main/java/com/comphenix/protocol/events/PacketAdapter.java
@@ -17,86 +17,93 @@
package com.comphenix.protocol.events;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.Nonnull;
-
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.injector.GamePhase;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-
+import java.util.Set;
+import javax.annotation.Nonnull;
import org.bukkit.plugin.Plugin;
/**
* Represents a packet listener with useful constructors.
*
* Remember to override onPacketReceiving() and onPacketSending(), depending on the ConnectionSide.
+ *
* @author Kristian
*/
public abstract class PacketAdapter implements PacketListener {
+
protected Plugin plugin;
protected ConnectionSide connectionSide;
protected ListeningWhitelist receivingWhitelist = ListeningWhitelist.EMPTY_WHITELIST;
protected ListeningWhitelist sendingWhitelist = ListeningWhitelist.EMPTY_WHITELIST;
/**
- * Initialize a packet adapter using a collection of parameters. Use {@link #params()} to get an instance to this builder.
+ * Initialize a packet adapter using a collection of parameters. Use {@link #params()} to get an instance to this
+ * builder.
+ *
* @param params - the parameters.
*/
public PacketAdapter(@Nonnull AdapterParameteters params) {
this(
- checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
- params.gamePhase, params.options, params.packets
+ checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
+ params.gamePhase, params.options, params.packets
);
}
-
+
/**
* Initialize a packet listener with the given parameters.
+ *
* @param plugin - the plugin.
- * @param types - the packet types.
+ * @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, PacketType... types) {
this(plugin, ListenerPriority.NORMAL, types);
}
-
+
/**
* Initialize a packet listener with the given parameters.
+ *
* @param plugin - the plugin.
- * @param types - the packet types.
+ * @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, Iterable extends PacketType> types) {
this(params(plugin, Iterables.toArray(types, PacketType.class)));
}
-
+
/**
* Initialize a packet listener with the given parameters.
- * @param plugin - the plugin.
+ *
+ * @param plugin - the plugin.
* @param listenerPriority - the priority.
- * @param types - the packet types.
+ * @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable extends PacketType> types) {
this(params(plugin, Iterables.toArray(types, PacketType.class)).listenerPriority(listenerPriority));
}
-
+
/**
* Initialize a packet listener with the given parameters.
- * @param plugin - the plugin.
+ *
+ * @param plugin - the plugin.
* @param listenerPriority - the priority.
- * @param types - the packet types.
- * @param options - the options.
+ * @param types - the packet types.
+ * @param options - the options.
*/
- public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable extends PacketType> types, ListenerOptions... options) {
- this(params(plugin, Iterables.toArray(types, PacketType.class)).listenerPriority(listenerPriority).options(options));
+ public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable extends PacketType> types,
+ ListenerOptions... options) {
+ this(
+ params(plugin, Iterables.toArray(types, PacketType.class)).listenerPriority(listenerPriority).options(options));
}
-
+
/**
* Initialize a packet listener with the given parameters.
- * @param plugin - the plugin.
+ *
+ * @param plugin - the plugin.
* @param listenerPriority - the priority.
- * @param types - the packet types.
+ * @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketType... types) {
this(params(plugin, types).listenerPriority(listenerPriority));
@@ -106,102 +113,69 @@ public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketTyp
private PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, PacketType... packets) {
-
- if (plugin == null)
+
+ if (plugin == null) {
throw new IllegalArgumentException("plugin cannot be null");
- if (connectionSide == null)
+ }
+ if (connectionSide == null) {
throw new IllegalArgumentException("connectionSide cannot be null");
- if (listenerPriority == null)
+ }
+ if (listenerPriority == null) {
throw new IllegalArgumentException("listenerPriority cannot be null");
- if (gamePhase == null)
+ }
+ if (gamePhase == null) {
throw new IllegalArgumentException("gamePhase cannot be NULL");
- if (packets == null)
+ }
+ if (packets == null) {
throw new IllegalArgumentException("packets cannot be null");
- if (options == null)
+ }
+ if (options == null) {
throw new IllegalArgumentException("options cannot be null");
-
- ListenerOptions[] serverOptions = options;
- ListenerOptions[] clientOptions = options;
-
- // Special case that allows us to specify optionIntercept().
- if (connectionSide == ConnectionSide.BOTH) {
- serverOptions = except(serverOptions, new ListenerOptions[0],
- ListenerOptions.INTERCEPT_INPUT_BUFFER);
}
-
+
// Add whitelists
- if (connectionSide.isForServer())
- sendingWhitelist = ListeningWhitelist.newBuilder().
- priority(listenerPriority).
- types(packets).
- gamePhase(gamePhase).
- options(serverOptions).
- build();
-
- if (connectionSide.isForClient())
- receivingWhitelist = ListeningWhitelist.newBuilder().
- priority(listenerPriority).
- types(packets).
- gamePhase(gamePhase).
- options(clientOptions).
- build();
-
+ if (connectionSide.isForServer()) {
+ sendingWhitelist = ListeningWhitelist.newBuilder()
+ .priority(listenerPriority)
+ .types(packets)
+ .gamePhase(gamePhase)
+ .options(options)
+ .build();
+ }
+
+ if (connectionSide.isForClient()) {
+ receivingWhitelist = ListeningWhitelist.newBuilder()
+ .priority(listenerPriority)
+ .types(packets)
+ .gamePhase(gamePhase)
+ .options(options)
+ .build();
+ }
+
this.plugin = plugin;
this.connectionSide = connectionSide;
}
-
- // Remove a given element from an array
- private static T[] except(T[] values, T[] buffer, T except) {
- List result = Lists.newArrayList(values);
-
- result.remove(except);
- return result.toArray(buffer);
- }
-
- @Override
- public void onPacketReceiving(PacketEvent event) {
- // Lets prevent some bugs
- throw new IllegalStateException("Override onPacketReceiving to get notifcations of received packets!");
- }
-
- @Override
- public void onPacketSending(PacketEvent event) {
- // Lets prevent some bugs
- throw new IllegalStateException("Override onPacketSending to get notifcations of sent packets!");
- }
-
- @Override
- public ListeningWhitelist getReceivingWhitelist() {
- return receivingWhitelist;
- }
-
- @Override
- public ListeningWhitelist getSendingWhitelist() {
- return sendingWhitelist;
- }
-
- @Override
- public Plugin getPlugin() {
- return plugin;
- }
-
+
/**
* Retrieves the name of the plugin that has been associated with the listener.
+ *
* @param listener - the listener.
* @return Name of the associated plugin.
*/
public static String getPluginName(PacketListener listener) {
return getPluginName(listener.getPlugin());
}
-
+
/**
* Retrieves the name of the given plugin.
+ *
* @param plugin - the plugin.
* @return Name of the given plugin.
*/
public static String getPluginName(Plugin plugin) {
- if (plugin == null)
+ if (plugin == null) {
return "UNKNOWN";
+ }
try {
return plugin.getName();
@@ -209,20 +183,12 @@ public static String getPluginName(Plugin plugin) {
return plugin.toString();
}
}
-
- @Override
- public String toString() {
- // This is used by the error reporter
- return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
- getPluginName(this),
- sendingWhitelist,
- receivingWhitelist);
- }
-
+
/**
* Construct a helper object for passing parameters to the packet adapter.
*
* This is often simpler and better than passing them directly to each constructor.
+ *
* @return Helper object.
*/
public static AdapterParameteters params() {
@@ -233,32 +199,91 @@ public static AdapterParameteters params() {
* Construct a helper object for passing parameters to the packet adapter.
*
* This is often simpler and better than passing them directly to each constructor.
- * @param plugin - the plugin that spawned this listener.
+ *
+ * @param plugin - the plugin that spawned this listener.
* @param packets - the packet types the listener is looking for.
* @return Helper object.
*/
public static AdapterParameteters params(Plugin plugin, PacketType... packets) {
return new AdapterParameteters().plugin(plugin).types(packets);
}
-
+
+ /**
+ * Determine if the required parameters are set.
+ */
+ private static AdapterParameteters checkValidity(AdapterParameteters params) {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be NULL.");
+ }
+ if (params.plugin == null) {
+ throw new IllegalStateException("Plugin was never set in the parameters.");
+ }
+ if (params.connectionSide == null) {
+ throw new IllegalStateException("Connection side was never set in the parameters.");
+ }
+ if (params.packets == null) {
+ throw new IllegalStateException("Packet IDs was never set in the parameters.");
+ }
+ return params;
+ }
+
+ @Override
+ public void onPacketReceiving(PacketEvent event) {
+ // Lets prevent some bugs
+ throw new IllegalStateException("Override onPacketReceiving to get notifcations of received packets!");
+ }
+
+ @Override
+ public void onPacketSending(PacketEvent event) {
+ // Lets prevent some bugs
+ throw new IllegalStateException("Override onPacketSending to get notifcations of sent packets!");
+ }
+
+ @Override
+ public ListeningWhitelist getReceivingWhitelist() {
+ return receivingWhitelist;
+ }
+
+ @Override
+ public ListeningWhitelist getSendingWhitelist() {
+ return sendingWhitelist;
+ }
+
+ @Override
+ public Plugin getPlugin() {
+ return plugin;
+ }
+
+ @Override
+ public String toString() {
+ // This is used by the error reporter
+ return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
+ getPluginName(this),
+ sendingWhitelist,
+ receivingWhitelist);
+ }
+
/**
* Represents a builder for passing parameters to the packet adapter constructor.
*
* Note: Never make spelling mistakes in a public API!
+ *
* @author Kristian
*/
public static class AdapterParameteters {
+
private Plugin plugin;
private ConnectionSide connectionSide;
private PacketType[] packets;
-
+
// Parameters with default values
private GamePhase gamePhase = GamePhase.PLAYING;
private ListenerOptions[] options = new ListenerOptions[0];
private ListenerPriority listenerPriority = ListenerPriority.NORMAL;
-
+
/**
* Set the plugin that spawned this listener. This parameter is required.
+ *
* @param plugin - the plugin.
* @return This builder, for chaining.
*/
@@ -266,9 +291,10 @@ public AdapterParameteters plugin(@Nonnull Plugin plugin) {
this.plugin = Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
return this;
}
-
+
/**
* Set the packet types this listener is looking for. This parameter is required.
+ *
* @param connectionSide - the new packet type.
* @return This builder, for chaining.
*/
@@ -276,27 +302,30 @@ public AdapterParameteters connectionSide(@Nonnull ConnectionSide connectionSide
this.connectionSide = Preconditions.checkNotNull(connectionSide, "connectionside cannot be NULL.");
return this;
}
-
+
/**
* Set this adapter to also look for client-side packets.
+ *
* @return This builder, for chaining.
*/
public AdapterParameteters clientSide() {
return connectionSide(ConnectionSide.add(connectionSide, ConnectionSide.CLIENT_SIDE));
}
-
+
/**
* Set this adapter to also look for server-side packets.
+ *
* @return This builder, for chaining.
*/
public AdapterParameteters serverSide() {
return connectionSide(ConnectionSide.add(connectionSide, ConnectionSide.SERVER_SIDE));
}
-
+
/**
* Set the the event priority, where the execution is in ascending order from lowest to highest.
*
* Default is {@link ListenerPriority#NORMAL}.
+ *
* @param listenerPriority - the new event priority.
* @return This builder, for chaining.
*/
@@ -304,11 +333,13 @@ public AdapterParameteters listenerPriority(@Nonnull ListenerPriority listenerPr
this.listenerPriority = Preconditions.checkNotNull(listenerPriority, "listener priority cannot be NULL.");
return this;
}
-
+
/**
- * Set which game phase this listener is active under. This is a hint for ProtocolLib to start intercepting login packets.
+ * Set which game phase this listener is active under. This is a hint for ProtocolLib to start intercepting login
+ * packets.
*
* Default is {@link GamePhase#PLAYING}, which will not intercept login packets.
+ *
* @param gamePhase - the new game phase.
* @return This builder, for chaining.
*/
@@ -316,19 +347,22 @@ public AdapterParameteters gamePhase(@Nonnull GamePhase gamePhase) {
this.gamePhase = Preconditions.checkNotNull(gamePhase, "gamePhase cannot be NULL.");
return this;
}
-
+
/**
* Set the game phase to {@link GamePhase#LOGIN}, allowing ProtocolLib to intercept login packets.
+ *
* @return This builder, for chaining.
*/
public AdapterParameteters loginPhase() {
return gamePhase(GamePhase.LOGIN);
}
-
+
/**
- * Set listener options that decide whether or not to intercept the raw packet data as read from the network stream.
+ * Set listener options that decide whether or not to intercept the raw packet data as read from the network
+ * stream.
*
* The default is to disable this raw packet interception.
+ *
* @param options - every option to use.
* @return This builder, for chaining.
*/
@@ -338,9 +372,11 @@ public AdapterParameteters options(@Nonnull ListenerOptions... options) {
}
/**
- * Set listener options that decide whether or not to intercept the raw packet data as read from the network stream.
+ * Set listener options that decide whether or not to intercept the raw packet data as read from the network
+ * stream.
*
* The default is to disable this raw packet interception.
+ *
* @param options - every option to use.
* @return This builder, for chaining.
*/
@@ -349,9 +385,10 @@ public AdapterParameteters options(@Nonnull Set extends ListenerOptions> optio
this.options = options.toArray(new ListenerOptions[0]);
return this;
}
-
+
/**
* Add a given option to the current builder.
+ *
* @param option - the option to add.
* @return This builder, for chaining.
*/
@@ -364,19 +401,12 @@ private AdapterParameteters addOption(ListenerOptions option) {
return options(current);
}
}
-
- /**
- * Set the listener option to {@link ListenerOptions#INTERCEPT_INPUT_BUFFER}, causing ProtocolLib to read the raw packet data from the network stream.
- * @return This builder, for chaining.
- */
- public AdapterParameteters optionIntercept() {
- return addOption(ListenerOptions.INTERCEPT_INPUT_BUFFER);
- }
/**
* Set the listener option to {@link ListenerOptions#ASYNC}, indicating that our listener is thread safe.
*
* This allows ProtocolLib to perform certain optimizations.
+ *
* @return This builder, for chaining.
*/
public AdapterParameteters optionAsync() {
@@ -387,6 +417,7 @@ public AdapterParameteters optionAsync() {
* Set the packet types the listener is looking for.
*
* This parameter is required.
+ *
* @param packets - the packet types to look for.
* @return This builder, for chaining.
*/
@@ -398,16 +429,18 @@ public AdapterParameteters types(@Nonnull PacketType... packets) {
}
}
this.packets = Preconditions.checkNotNull(packets, "packets cannot be NULL");
-
- if (packets.length == 0)
+
+ if (packets.length == 0) {
throw new IllegalArgumentException("Passed an empty packet type array.");
+ }
return this;
}
-
+
/**
* Set the packet types the listener is looking for.
*
* This parameter is required.
+ *
* @param packets - a set of packet types to look for.
* @return This builder, for chaining.
*/
@@ -415,19 +448,4 @@ public AdapterParameteters types(@Nonnull Set packets) {
return types(packets.toArray(new PacketType[0]));
}
}
-
- /**
- * Determine if the required parameters are set.
- */
- private static AdapterParameteters checkValidity(AdapterParameteters params) {
- if (params == null)
- throw new IllegalArgumentException("params cannot be NULL.");
- if (params.plugin == null)
- throw new IllegalStateException("Plugin was never set in the parameters.");
- if (params.connectionSide == null)
- throw new IllegalStateException("Connection side was never set in the parameters.");
- if (params.packets == null)
- throw new IllegalStateException("Packet IDs was never set in the parameters.");
- return params;
- }
}
diff --git a/src/main/java/com/comphenix/protocol/events/PacketEvent.java b/src/main/java/com/comphenix/protocol/events/PacketEvent.java
index 815f9bf16..248a48fd5 100644
--- a/src/main/java/com/comphenix/protocol/events/PacketEvent.java
+++ b/src/main/java/com/comphenix/protocol/events/PacketEvent.java
@@ -17,64 +17,60 @@
package com.comphenix.protocol.events;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.lang.ref.WeakReference;
-import java.util.EventObject;
-
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-import org.bukkit.event.Cancellable;
-
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.error.PluginContext;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
-import com.comphenix.protocol.injector.server.TemporaryPlayer;
+import com.comphenix.protocol.injector.temporary.TemporaryPlayer;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.WeakReference;
+import java.util.EventObject;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
/**
- * Represents a packet sending or receiving event. Changes to the packet will be
- * reflected in the final version to be sent or received. It is also possible to cancel an event.
+ * Represents a packet sending or receiving event. Changes to the packet will be reflected in the final version to be
+ * sent or received. It is also possible to cancel an event.
+ *
* @author Kristian
*/
public class PacketEvent extends EventObject implements Cancellable {
+
public static final ReportType REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING = new ReportType(
"Plugin %s changed packet type from %s to %s in packet listener. This is confusing for other plugins! (Not an error, though!)");
-
+
private static final SetMultimap CHANGE_WARNINGS =
Multimaps.synchronizedSetMultimap(HashMultimap.create());
-
+
/**
* Automatically generated by Eclipse.
*/
private static final long serialVersionUID = -5360289379097430620L;
-
+ // Network input and output handlers
+ NetworkMarker networkMarker;
private transient WeakReference playerReference;
-
private PacketContainer packet;
private boolean serverPacket;
private boolean cancel;
-
private AsyncMarker asyncMarker;
private boolean asynchronous;
-
- // Network input and output handlers
- NetworkMarker networkMarker;
-
// Whether or not a packet event is read only
private boolean readOnly;
private boolean filtered;
-
+
/**
* Use the static constructors to create instances of this event.
+ *
* @param source - the event source.
*/
public PacketEvent(Object source) {
@@ -85,8 +81,9 @@ public PacketEvent(Object source) {
private PacketEvent(Object source, PacketContainer packet, Player player, boolean serverPacket) {
this(source, packet, null, player, serverPacket, true);
}
-
- private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket, boolean filtered) {
+
+ private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket,
+ boolean filtered) {
super(source);
this.packet = packet;
this.playerReference = new WeakReference<>(player);
@@ -94,7 +91,7 @@ private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker,
this.serverPacket = serverPacket;
this.filtered = filtered;
}
-
+
private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) {
super(origial.source);
this.packet = origial.packet;
@@ -109,6 +106,7 @@ private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) {
/**
* Creates an event representing a client packet transmission.
+ *
* @param source - the event source.
* @param packet - the packet.
* @param client - the client that sent the packet.
@@ -117,9 +115,10 @@ private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) {
public static PacketEvent fromClient(Object source, PacketContainer packet, Player client) {
return new PacketEvent(source, packet, client, false);
}
-
+
/**
* Creates an event representing a client packet transmission.
+ *
* @param source - the event source.
* @param packet - the packet.
* @param marker - the network marker.
@@ -129,85 +128,94 @@ public static PacketEvent fromClient(Object source, PacketContainer packet, Play
public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client) {
return new PacketEvent(source, packet, marker, client, false, true);
}
-
+
/**
* Creates an event representing a client packet transmission.
*
* If filtered is FALSE, then this event is only processed by packet monitors.
- * @param source - the event source.
- * @param packet - the packet.
- * @param marker - the network marker.
- * @param client - the client that sent the packet.
+ *
+ * @param source - the event source.
+ * @param packet - the packet.
+ * @param marker - the network marker.
+ * @param client - the client that sent the packet.
* @param filtered - whether or not this packet event is processed by every packet listener.
* @return The event.
*/
- public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client, boolean filtered) {
+ public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client,
+ boolean filtered) {
return new PacketEvent(source, packet, marker, client, false, filtered);
}
-
+
/**
* Creates an event representing a server packet transmission.
- * @param source - the event source.
- * @param packet - the packet.
+ *
+ * @param source - the event source.
+ * @param packet - the packet.
* @param recipient - the client that will receieve the packet.
* @return The event.
*/
- public static PacketEvent fromServer(Object source, PacketContainer packet, Player recipient) {
+ public static PacketEvent fromServer(Object source, PacketContainer packet, Player recipient) {
return new PacketEvent(source, packet, recipient, true);
}
-
+
/**
* Creates an event representing a server packet transmission.
- * @param source - the event source.
- * @param packet - the packet.
- * @param marker - the network marker.
+ *
+ * @param source - the event source.
+ * @param packet - the packet.
+ * @param marker - the network marker.
* @param recipient - the client that will receieve the packet.
* @return The event.
*/
public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient) {
return new PacketEvent(source, packet, marker, recipient, true, true);
}
-
+
/**
* Creates an event representing a server packet transmission.
*
* If filtered is FALSE, then this event is only processed by packet monitors.
- * @param source - the event source.
- * @param packet - the packet.
- * @param marker - the network marker.
+ *
+ * @param source - the event source.
+ * @param packet - the packet.
+ * @param marker - the network marker.
* @param recipient - the client that will receieve the packet.
- * @param filtered - whether or not this packet event is processed by every packet listener.
+ * @param filtered - whether or not this packet event is processed by every packet listener.
* @return The event.
*/
- public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient, boolean filtered) {
+ public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient,
+ boolean filtered) {
return new PacketEvent(source, packet, marker, recipient, true, filtered);
}
-
+
/**
* Create an asynchronous packet event from a synchronous event and a async marker.
- * @param event - the original synchronous event.
+ *
+ * @param event - the original synchronous event.
* @param marker - the asynchronous marker.
* @return The new packet event.
*/
public static PacketEvent fromSynchronous(PacketEvent event, AsyncMarker marker) {
return new PacketEvent(event, marker);
}
-
+
/**
* Determine if we are executing the packet event in an asynchronous thread.
*
* If so, you must synchronize all calls to the Bukkit API.
*
- * Generally, most server packets are executed on the main thread, whereas client packets
- * are all executed asynchronously.
+ * Generally, most server packets are executed on the main thread, whereas client packets are all executed
+ * asynchronously.
+ *
* @return TRUE if we are, FALSE otherwise.
*/
public boolean isAsync() {
return !Bukkit.isPrimaryThread();
}
-
+
/**
* Retrieves the packet that will be sent to the player.
+ *
* @return Packet to send to the player.
*/
public PacketContainer getPacket() {
@@ -216,14 +224,17 @@ public PacketContainer getPacket() {
/**
* Replace the packet that will be sent to the player.
+ *
* @param packet - the packet that will be sent instead.
*/
public void setPacket(PacketContainer packet) {
- if (readOnly)
+ if (readOnly) {
throw new IllegalStateException("The packet event is read-only.");
- if (packet == null)
+ }
+ if (packet == null) {
throw new IllegalArgumentException("Cannot set packet to NULL. Use setCancelled() instead.");
-
+ }
+
// Change warnings
final PacketType oldType = this.packet.getType();
final PacketType newType = packet.getType();
@@ -232,53 +243,77 @@ public void setPacket(PacketContainer packet) {
if (CHANGE_WARNINGS.put(oldType, newType)) {
ProtocolLibrary.getErrorReporter().reportWarning(this,
Report.newBuilder(REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING).
- messageParam(PluginContext.getPluginCaller(new Exception()), oldType, newType).
- build());
+ messageParam(PluginContext.getPluginCaller(new Exception()), oldType, newType).
+ build());
}
}
this.packet = packet;
}
-
+
/**
* Retrieves the packet ID.
*
* Deprecated: Use {@link #getPacketType()} instead.
+ *
* @return The current packet ID.
*/
@Deprecated
public int getPacketID() {
return packet.getId();
}
-
+
/**
* Retrieve the packet type.
+ *
* @return The type.
*/
public PacketType getPacketType() {
return packet.getType();
}
-
+
/**
* Retrieves whether or not the packet should be cancelled.
+ *
* @return TRUE if it should be cancelled, FALSE otherwise.
*/
@Override
public boolean isCancelled() {
return cancel;
}
-
+
+ /**
+ * Sets whether or not the packet should be cancelled. Uncancelling is possible.
+ *
+ * Warning: A cancelled packet should never be re-transmitted. Use the asynchronous
+ * packet manager if you need to perform extensive processing. It should also be used if you need to synchronize with
+ * the main thread.
+ *
+ * This ensures that other plugins can work with the same packet.
+ *
+ * An asynchronous listener can also delay a packet indefinitely without having to block its thread.
+ *
+ * @param cancel - TRUE if it should be cancelled, FALSE otherwise.
+ */
+ @Override
+ public void setCancelled(boolean cancel) {
+ if (readOnly) {
+ throw new IllegalStateException("The packet event is read-only.");
+ }
+ this.cancel = cancel;
+ }
+
/**
* Retrieve the object responsible for managing the serialized input and output of a packet.
*
- * Note that the serialized input data is only available for client-side packets, and the output handlers
- * can only be applied to server-side packets.
+ * Note that the serialized input data is only available for client-side packets, and the output handlers can only be
+ * applied to server-side packets.
+ *
* @return The network manager.
*/
public NetworkMarker getNetworkMarker() {
if (networkMarker == null) {
if (isServerPacket()) {
- networkMarker = new NetworkMarker.EmptyBufferMarker(
- serverPacket ? ConnectionSide.SERVER_SIDE : ConnectionSide.CLIENT_SIDE);
+ networkMarker = new NetworkMarker(serverPacket ? ConnectionSide.SERVER_SIDE : ConnectionSide.CLIENT_SIDE, this.getPacketType());
} else {
throw new IllegalStateException("Add the option ListenerOptions.INTERCEPT_INPUT_BUFFER to your listener.");
}
@@ -290,31 +325,12 @@ public NetworkMarker getNetworkMarker() {
* Update the network manager.
*
* This method is internal - do not call.
+ *
* @param networkMarker - the new network manager.
*/
public void setNetworkMarker(NetworkMarker networkMarker) {
this.networkMarker = Preconditions.checkNotNull(networkMarker, "marker cannot be NULL");
}
-
- /**
- * Sets whether or not the packet should be cancelled. Uncancelling is possible.
- *
- * Warning: A cancelled packet should never be re-transmitted. Use the asynchronous
- * packet manager if you need to perform extensive processing. It should also be used
- * if you need to synchronize with the main thread.
- *
- * This ensures that other plugins can work with the same packet.
- *
- * An asynchronous listener can also delay a packet indefinitely without having to block its thread.
- *
- * @param cancel - TRUE if it should be cancelled, FALSE otherwise.
- */
- @Override
- public void setCancelled(boolean cancel) {
- if (readOnly)
- throw new IllegalStateException("The packet event is read-only.");
- this.cancel = cancel;
- }
private WeakReference getPlayerReference() {
Player player = playerReference.get();
@@ -332,6 +348,7 @@ private WeakReference getPlayerReference() {
/**
* Retrieves the player that has sent the packet or is receiving it.
+ *
* @return The player associated with this event.
*/
public Player getPlayer() {
@@ -350,7 +367,7 @@ public Player getPlayer() {
*
kickPlayer
*
isOnline
*
- *
+ *
* Anything else will throw an UnsupportedOperationException. Use this check before calling other methods when
* dealing with packets early in the login sequence or if you get the aforementioned exception.
*
@@ -359,27 +376,29 @@ public Player getPlayer() {
public boolean isPlayerTemporary() {
return getPlayer() instanceof TemporaryPlayer;
}
-
+
/**
* Determine if this packet is filtered by every packet listener.
*
* If not, it will only be intercepted by monitor packets.
+ *
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isFiltered() {
return filtered;
}
-
+
/**
* Whether or not this packet was created by the server.
*
* Most listeners can deduce this by noting which listener method was invoked.
+ *
* @return TRUE if the packet was created by the server, FALSE if it was created by a client.
*/
public boolean isServerPacket() {
return serverPacket;
}
-
+
/**
* Retrieve the asynchronous marker.
*
@@ -387,54 +406,62 @@ public boolean isServerPacket() {
* asynchronous event, the marker is used to correctly pass the packet around to the different threads.
*
* Note that if there are no asynchronous events that can receive this packet, the marker is NULL.
+ *
* @return The current asynchronous marker, or NULL.
*/
public AsyncMarker getAsyncMarker() {
return asyncMarker;
}
+
/**
* Set the asynchronous marker.
*
- * If the marker is non-null at the end of an synchronous event processing, the packet will be scheduled
- * to be processed asynchronously with the given settings.
+ * If the marker is non-null at the end of an synchronous event processing, the packet will be scheduled to be
+ * processed asynchronously with the given settings.
*
* Note that if there are no asynchronous events that can receive this packet, the marker should be NULL.
+ *
* @param asyncMarker - the new asynchronous marker, or NULL.
* @throws IllegalStateException If the current event is asynchronous.
*/
public void setAsyncMarker(AsyncMarker asyncMarker) {
- if (isAsynchronous())
+ if (isAsynchronous()) {
throw new IllegalStateException("The marker is immutable for asynchronous events");
- if (readOnly)
+ }
+ if (readOnly) {
throw new IllegalStateException("The packet event is read-only.");
+ }
this.asyncMarker = asyncMarker;
}
/**
* Determine if the current packet event is read only.
*
- * This is used to ensure that a monitor listener doesn't accidentally alter the state of the event. However,
- * it is still possible to modify the packet itself, as it would require too many resources to verify its integrity.
+ * This is used to ensure that a monitor listener doesn't accidentally alter the state of the event. However, it is
+ * still possible to modify the packet itself, as it would require too many resources to verify its integrity.
*
* Thus, the packet is considered immutable if the packet event is read only.
+ *
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isReadOnly() {
return readOnly;
}
-
+
/**
* Set the read-only state of this packet event.
*
* This will be reset for every packet listener.
+ *
* @param readOnly - TRUE if it is read-only, FALSE otherwise.
*/
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
-
+
/**
* Determine if the packet event has been executed asynchronously or not.
+ *
* @return TRUE if this packet event is asynchronous, FALSE otherwise.
*/
public boolean isAsynchronous() {
@@ -445,14 +472,16 @@ public boolean isAsynchronous() {
* Schedule a packet for sending or receiving after the current packet event is successful.
*
* The packet will be added to {@link NetworkMarker#getScheduledPackets()}.
+ *
* @param scheduled - the packet to transmit or receive.
*/
public void schedule(ScheduledPacket scheduled) {
getNetworkMarker().getScheduledPackets().add(scheduled);
}
-
+
/**
* Unschedule a specific packet.
+ *
* @param scheduled - the scheduled packet.
* @return TRUE if it was unscheduled, FALSE otherwise.
*/
@@ -462,9 +491,9 @@ public boolean unschedule(ScheduledPacket scheduled) {
}
return false;
}
-
+
private void writeObject(ObjectOutputStream output) throws IOException {
- // Default serialization
+ // Default serialization
output.defaultWriteObject();
// Write the name of the player (or NULL if it's not set)
@@ -473,17 +502,17 @@ private void writeObject(ObjectOutputStream output) throws IOException {
}
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
- // Default deserialization
+ // Default deserialization
input.defaultReadObject();
final SerializedOfflinePlayer serialized = (SerializedOfflinePlayer) input.readObject();
-
+
// Better than nothing
- if (serialized != null) {
- // Store it, to prevent weak reference from cleaning up the reference
- Player offlinePlayer = serialized.getPlayer();
- playerReference = new WeakReference<>(offlinePlayer);
- }
+ if (serialized != null) {
+ // Store it, to prevent weak reference from cleaning up the reference
+ Player offlinePlayer = serialized.getPlayer();
+ playerReference = new WeakReference<>(offlinePlayer);
+ }
}
@Override
diff --git a/src/main/java/com/comphenix/protocol/events/ScheduledPacket.java b/src/main/java/com/comphenix/protocol/events/ScheduledPacket.java
index cb4ddf94e..46fdc5895 100644
--- a/src/main/java/com/comphenix/protocol/events/ScheduledPacket.java
+++ b/src/main/java/com/comphenix/protocol/events/ScheduledPacket.java
@@ -1,7 +1,5 @@
package com.comphenix.protocol.events;
-import java.lang.reflect.InvocationTargetException;
-
import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketStream;
@@ -121,17 +119,11 @@ public void schedule() {
*/
public void schedule(PacketStream stream) {
Preconditions.checkNotNull(stream, "stream cannot be NULL");
-
- try {
- if (getSender() == Sender.CLIENT) {
- stream.recieveClientPacket(getTarget(), getPacket(), isFiltered());
- } else {
- stream.sendServerPacket(getTarget(), getPacket(), isFiltered());
- }
- } catch (InvocationTargetException e) {
- throw new RuntimeException("Cannot send packet " + this + " to " + stream);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Cannot send packet " + this + " to " + stream);
+
+ if (getSender() == Sender.CLIENT) {
+ stream.receiveClientPacket(getTarget(), getPacket(), isFiltered());
+ } else {
+ stream.sendServerPacket(getTarget(), getPacket(), isFiltered());
}
}
diff --git a/src/main/java/com/comphenix/protocol/injector/BukkitUnwrapper.java b/src/main/java/com/comphenix/protocol/injector/BukkitUnwrapper.java
index e32566220..440f91a7d 100644
--- a/src/main/java/com/comphenix/protocol/injector/BukkitUnwrapper.java
+++ b/src/main/java/com/comphenix/protocol/injector/BukkitUnwrapper.java
@@ -17,16 +17,6 @@
package com.comphenix.protocol.injector;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
@@ -36,6 +26,14 @@
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.primitives.Primitives;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
/**
* Represents an object capable of converting wrapped Bukkit objects into NMS objects.
@@ -45,123 +43,136 @@
*
org.bukkit.entity.Player to net.minecraft.server.EntityPlayer
*
org.bukkit.World to net.minecraft.server.WorldServer
*
- *
+ *
* @author Kristian
*/
public class BukkitUnwrapper implements Unwrapper {
- private static BukkitUnwrapper DEFAULT;
public static final ReportType REPORT_ILLEGAL_ARGUMENT = new ReportType("Illegal argument.");
public static final ReportType REPORT_SECURITY_LIMITATION = new ReportType("Security limitation.");
public static final ReportType REPORT_CANNOT_FIND_UNWRAP_METHOD = new ReportType("Cannot find method.");
-
public static final ReportType REPORT_CANNOT_READ_FIELD_HANDLE = new ReportType("Cannot read field 'handle'.");
-
- private static Map, Unwrapper> unwrapperCache = new ConcurrentHashMap, Unwrapper>();
-
+
+ private static final Map, Unwrapper> UNWRAPPER_CACHE = new ConcurrentHashMap, Unwrapper>();
+ private static BukkitUnwrapper DEFAULT;
+
// The current error reporter
private final ErrorReporter reporter;
-
+
+ /**
+ * Construct a new Bukkit unwrapper with ProtocolLib's default error reporter.
+ */
+ public BukkitUnwrapper() {
+ this(ProtocolLibrary.getErrorReporter());
+ }
+
+ /**
+ * Construct a new Bukkit unwrapper with the given error reporter.
+ *
+ * @param reporter - the error reporter to use.
+ */
+ public BukkitUnwrapper(ErrorReporter reporter) {
+ this.reporter = reporter;
+ }
+
/**
* Retrieve the default instance of the Bukkit unwrapper.
+ *
* @return The default instance.
*/
public static BukkitUnwrapper getInstance() {
ErrorReporter currentReporter = ProtocolLibrary.getErrorReporter();
-
+
// Also recreate the unwrapper if the error reporter has changed
if (DEFAULT == null || DEFAULT.reporter != currentReporter) {
DEFAULT = new BukkitUnwrapper(currentReporter);
}
return DEFAULT;
}
-
- /**
- * Construct a new Bukkit unwrapper with ProtocolLib's default error reporter.
- */
- public BukkitUnwrapper() {
- this(ProtocolLibrary.getErrorReporter());
- }
-
- /**
- * Construct a new Bukkit unwrapper with the given error reporter.
- * @param reporter - the error reporter to use.
- */
- public BukkitUnwrapper(ErrorReporter reporter) {
- this.reporter = reporter;
+
+ private static Class> checkClass(Class> input, Class> expected, Class> result) {
+ if (expected.isAssignableFrom(input)) {
+ return result;
+ }
+ return null;
}
-
+
@SuppressWarnings("unchecked")
@Override
public Object unwrapItem(Object wrappedObject) {
// Special case
- if (wrappedObject == null)
+ if (wrappedObject == null) {
return null;
+ }
Class> currentClass = PacketConstructor.getClass(wrappedObject);
-
+
// No need to unwrap primitives
- if (currentClass.isPrimitive() || currentClass.equals(String.class))
+ if (currentClass.isPrimitive() || currentClass.equals(String.class)) {
return null;
-
+ }
+
// Next, check for types that doesn't have a getHandle()
if (wrappedObject instanceof Collection) {
return handleCollection((Collection