diff --git a/ProtocolLib/.project b/ProtocolLib/.project
index a1960c9e..d36fcbe8 100644
--- a/ProtocolLib/.project
+++ b/ProtocolLib/.project
@@ -11,12 +11,12 @@
- org.eclipse.m2e.core.maven2Builder
+ net.sourceforge.metrics.builder
- net.sourceforge.metrics.builder
+ org.eclipse.m2e.core.maven2Builder
diff --git a/ProtocolLib/pom.xml b/ProtocolLib/pom.xml
index a81c34d1..9c0c920b 100644
--- a/ProtocolLib/pom.xml
+++ b/ProtocolLib/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.comphenix.protocol
ProtocolLib
- 2.0.0
+ 2.1.0
jar
Provides read/write access to the Minecraft protocol.
@@ -203,7 +203,7 @@
org.bukkit
craftbukkit
- 1.4.6-R0.1
+ 1.4.7-R0.1
provided
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
index c35f7632..672c4127 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
@@ -17,6 +17,8 @@
package com.comphenix.protocol;
+import java.io.IOException;
+
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
@@ -25,6 +27,7 @@ import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.metrics.Updater;
import com.comphenix.protocol.metrics.Updater.UpdateResult;
import com.comphenix.protocol.metrics.Updater.UpdateType;
+import com.comphenix.protocol.utility.WrappedScheduler;
/**
* Handles the "protocol" administration command.
@@ -64,42 +67,59 @@ class CommandProtocol extends CommandBase {
return true;
}
- @SuppressWarnings("deprecation")
public void checkVersion(final CommandSender sender) {
// Perform on an async thread
- plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
+ WrappedScheduler.runAsynchronouslyOnce(plugin, new Runnable() {
@Override
public void run() {
try {
UpdateResult result = updater.update(UpdateType.NO_DOWNLOAD, true);
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
} catch (Exception e) {
- getReporter().reportDetailed(this, "Cannot check updates for ProtocolLib.", e, sender);
+ if (isHttpError(e)) {
+ getReporter().reportWarning(this, "Http error: " + e.getCause().getMessage());
+ } else {
+ getReporter().reportDetailed(this, "Cannot check updates for ProtocolLib.", e, sender);
+ }
}
}
- });
+ }, 0L);
updateFinished();
}
- @SuppressWarnings("deprecation")
public void updateVersion(final CommandSender sender) {
// Perform on an async thread
- plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
+ WrappedScheduler.runAsynchronouslyOnce(plugin, new Runnable() {
@Override
public void run() {
try {
UpdateResult result = updater.update(UpdateType.DEFAULT, true);
sender.sendMessage(ChatColor.BLUE + "[ProtocolLib] " + result.toString());
} catch (Exception e) {
- getReporter().reportDetailed(this, "Cannot update ProtocolLib.", e, sender);
+ if (isHttpError(e)) {
+ getReporter().reportWarning(this, "Http error: " + e.getCause().getMessage());
+ } else {
+ getReporter().reportDetailed(this, "Cannot update ProtocolLib.", e, sender);
+ }
}
}
- });
+ }, 0L);
updateFinished();
}
+ private boolean isHttpError(Exception e) {
+ Throwable cause = e.getCause();
+
+ if (cause instanceof IOException) {
+ // Thanks for making the message a part of the API ...
+ return cause.getMessage().contains("HTTP response");
+ } else {
+ return false;
+ }
+ }
+
/**
* Prevent further automatic updates until the next delay.
*/
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/Packets.java b/ProtocolLib/src/main/java/com/comphenix/protocol/Packets.java
index 33023c47..1509c411 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/Packets.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/Packets.java
@@ -52,9 +52,18 @@ public final class Packets {
public static final int PLAYER_POSITION = 11;
public static final int PLAYER_LOOK = 12;
public static final int PLAYER_LOOK_MOVE = 13;
+ /**
+ * Made bi-directional in 1.4.6.
+ */
+ public static final int BLOCK_ITEM_SWITCH = 16;
public static final int ENTITY_LOCATION_ACTION = 17;
public static final int ARM_ANIMATION = 18;
public static final int NAMED_ENTITY_SPAWN = 20;
+ /**
+ * Removed in 1.4.6 and replaced with {@link VEHICLE_SPAWN}.
+ * @see Protocol History - MinecraftCoalition
+ */
+ @Deprecated()
public static final int PICKUP_SPAWN = 21;
public static final int COLLECT = 22;
public static final int VEHICLE_SPAWN = 23;
@@ -153,7 +162,13 @@ public final class Packets {
public static final int HANDSHAKE = 2;
public static final int CHAT = 3;
public static final int USE_ENTITY = 7;
+
+ /**
+ * Since 1.3.1, the client no longer sends a respawn packet. Moved to CLIENT_COMMAND.
+ */
+ @Deprecated
public static final int RESPAWN = 9;
+
public static final int FLYING = 10;
public static final int PLAYER_POSITION = 11;
public static final int PLAYER_LOOK = 12;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
index 040a8ef1..ce084d0a 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
@@ -23,6 +23,8 @@ import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
+import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
+
/**
* Represents the configuration of ProtocolLib.
*
@@ -35,9 +37,10 @@ class ProtocolConfig {
private static final String METRICS_ENABLED = "metrics";
- private static final String IGNORE_VERSION_CHECK = "ignore version check";
-
+ private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
+
+ private static final String INJECTION_METHOD = "injection method";
private static final String UPDATER_NOTIFY = "notify";
private static final String UPDATER_DOWNLAD = "download";
@@ -234,6 +237,38 @@ class ProtocolConfig {
updater.set(UPDATER_LAST_TIME, lastTimeSeconds);
}
+ /**
+ * 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().replace(" ", "_"));
+ return hook;
+ }
+
+ /**
+ * Set the starting injection method to use.
+ * @return Injection method.
+ */
+ public void setInjectionMethod(PlayerInjectHooks hook) {
+ global.set(INJECTION_METHOD, hook.name());
+ }
+
/**
* Save the current configuration file.
*/
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
index c8c3e0a8..9a5bd6ac 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
@@ -37,6 +37,7 @@ import com.comphenix.protocol.error.DetailedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.DelayedSingleTask;
import com.comphenix.protocol.injector.PacketFilterManager;
+import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.metrics.Statistics;
import com.comphenix.protocol.metrics.Updater;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
@@ -55,7 +56,7 @@ public class ProtocolLibrary extends JavaPlugin {
/**
* The maximum version ProtocolLib has been tested with,
*/
- private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.6";
+ private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.7";
/**
* The number of milliseconds per second.
@@ -136,6 +137,19 @@ public class ProtocolLibrary extends JavaPlugin {
protocolManager = new PacketFilterManager(getClassLoader(), getServer(), unhookTask, detailedReporter);
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) {
+ detailedReporter.reportWarning(config, "Cannot parse injection method. Using default.", e);
+ }
+
// Initialize command handlers
commandProtocol = new CommandProtocol(detailedReporter, this, updater, config);
commandPacket = new CommandPacket(detailedReporter, this, logger, protocolManager);
@@ -269,12 +283,15 @@ public class ProtocolLibrary extends JavaPlugin {
MinecraftVersion currentVersion = new MinecraftVersion(this.getDescription().getVersion());
MinecraftVersion newestVersion = null;
+ // Skip the file that contains this current instance however
+ File loadedFile = getFile();
+
try {
// Scan the plugin folder for newer versions of ProtocolLib
File pluginFolder = new File("plugins/");
for (File candidate : pluginFolder.listFiles()) {
- if (candidate.isFile()) {
+ if (candidate.isFile() && !candidate.equals(loadedFile)) {
Matcher match = ourPlugin.matcher(candidate.getName());
if (match.matches()) {
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncListenerHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncListenerHandler.java
index cefd8a0a..47eb84a6 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncListenerHandler.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncListenerHandler.java
@@ -30,6 +30,7 @@ import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
+import com.comphenix.protocol.utility.WrappedScheduler;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
@@ -298,9 +299,9 @@ public class AsyncListenerHandler {
});
}
- @SuppressWarnings("deprecation")
private void scheduleAsync(Runnable runnable) {
- filterManager.getScheduler().scheduleAsyncDelayedTask(listener.getPlugin(), runnable);
+ // Handle deprecation
+ WrappedScheduler.runAsynchronouslyRepeat(listener.getPlugin(), filterManager.getScheduler(), runnable, 0L, -1L);
}
/**
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java
index df867951..54295cdb 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java
@@ -114,7 +114,10 @@ public class BlockingHashMap {
if (remainingTime > 0) {
TimeUnit.NANOSECONDS.timedWait(lock, remainingTime);
value = backingMap.get(key);
- }
+ } else {
+ // Timeout elapsed
+ break;
+ }
}
}
}
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java
index 4c679cb3..93bc0d19 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java
@@ -175,6 +175,14 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(byte.class);
}
+ /**
+ * Retrieves a read/write structure for every boolean field.
+ * @return A modifier for every boolean field.
+ */
+ public StructureModifier getBooleans() {
+ return structureModifier.withType(boolean.class);
+ }
+
/**
* Retrieves a read/write structure for every short field.
* @return A modifier for every short field.
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java
index 3722e4f5..a59e5772 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java
@@ -50,7 +50,7 @@ public class PlayerInjectionHandler {
/**
* The maximum number of milliseconds to wait until a player can be looked up by connection.
*/
- private static final long TIMEOUT_PLAYER_LOOKUP = 1000; // ms
+ private static final long TIMEOUT_PLAYER_LOOKUP = 2000; // ms
/**
* The highest possible packet ID. It's unlikely that this value will ever change.
@@ -486,7 +486,7 @@ public class PlayerInjectionHandler {
if (injector != null)
injector.sendServerPacket(packet.getHandle(), filters);
else
- reporter.reportWarning(this, String.format(
+ throw new PlayerLoggedOutException(String.format(
"Unable to send packet %s (%s): Player %s has logged out.",
packet.getID(), packet, reciever.getName()
));
@@ -507,7 +507,7 @@ public class PlayerInjectionHandler {
if (injector != null)
injector.processPacket(mcPacket);
else
- reporter.reportWarning(this, String.format(
+ throw new PlayerLoggedOutException(String.format(
"Unable to receieve packet %s. Player %s has logged out.",
mcPacket, player.getName()
));
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java b/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java
index 3ff786ff..d7640502 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Metrics.java
@@ -51,6 +51,8 @@ import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
+import com.comphenix.protocol.utility.WrappedScheduler;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@@ -136,7 +138,7 @@ public class Metrics {
/**
* The scheduled task
*/
- private volatile Scheduling.TaskWrapper task = null;
+ private volatile WrappedScheduler.TaskWrapper task = null;
public Metrics(final Plugin plugin) throws IOException {
if (plugin == null) {
@@ -237,7 +239,7 @@ public class Metrics {
}
// Begin hitting the server with glorious data
- task = Scheduling.runAsynchronously(plugin, new Runnable() {
+ task = WrappedScheduler.runAsynchronouslyRepeat(plugin, new Runnable() {
private boolean firstPost = true;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Updater.java b/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Updater.java
index 50ea9583..3133a434 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Updater.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Updater.java
@@ -119,7 +119,12 @@ public class Updater
/**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
*/
- UPDATE_AVAILABLE(7, "The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.");
+ UPDATE_AVAILABLE(7, "The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded."),
+
+ /**
+ * Updating SNAPSHOT versions are not supported. Please perform a manual upgrade.
+ */
+ NOT_SUPPORTED(8, "Updating SNAPSHOT versions are not supported. Please perform a manual upgrade.");
private static final Map valueList = new HashMap();
private final int value;
@@ -479,7 +484,12 @@ public class Updater
remVer=-1;
}
- if(hasTag(version)||version.equalsIgnoreCase(remoteVersion)||curVer>=remVer)
+ if (hasTag(version))
+ {
+ result = Updater.UpdateResult.NOT_SUPPORTED;
+ return false;
+ }
+ else if (version.equalsIgnoreCase(remoteVersion) || curVer>=remVer)
{
// We already have the latest version, or this build is tagged for no-update
result = Updater.UpdateResult.NO_UPDATE;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Scheduling.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/WrappedScheduler.java
similarity index 70%
rename from ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Scheduling.java
rename to ProtocolLib/src/main/java/com/comphenix/protocol/utility/WrappedScheduler.java
index 42e6db77..a7a54395 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/metrics/Scheduling.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/WrappedScheduler.java
@@ -1,4 +1,4 @@
-package com.comphenix.protocol.metrics;
+package com.comphenix.protocol.utility;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
@@ -9,7 +9,7 @@ import org.bukkit.scheduler.BukkitTask;
*
* @author Kristian
*/
-class Scheduling {
+public class WrappedScheduler {
/**
* Represents a backwards compatible Bukkit task.
*/
@@ -21,15 +21,26 @@ class Scheduling {
}
/**
- * Schedule a given task for asynchronous execution.
+ * Schedule a given task for a single asynchronous execution.
+ * @param plugin - the owner plugin.
+ * @param runnable - the task to run.
+ * @param firstDelay - the amount of time to wait until executing the task.
+ * @return A cancel token.
+ */
+ public static TaskWrapper runAsynchronouslyOnce(final Plugin plugin, Runnable runnable, long firstDelay) {
+ return runAsynchronouslyRepeat(plugin, plugin.getServer().getScheduler(), runnable, firstDelay, -1L);
+ }
+
+ /**
+ * Schedule a given task for multiple asynchronous executions.
* @param plugin - the owner plugin.
* @param runnable - the task to run.
* @param firstDelay - the amount of time to wait until executing the task for the first time.
* @param repeatDelay - the amount of time inbetween each execution. If less than zero, the task is only executed once.
* @return A cancel token.
*/
- public static TaskWrapper runAsynchronously(final Plugin plugin, Runnable runnable, long firstDelay, long repeatDelay) {
- return runAsynchronously(plugin, plugin.getServer().getScheduler(), runnable, firstDelay, repeatDelay);
+ public static TaskWrapper runAsynchronouslyRepeat(final Plugin plugin, Runnable runnable, long firstDelay, long repeatDelay) {
+ return runAsynchronouslyRepeat(plugin, plugin.getServer().getScheduler(), runnable, firstDelay, repeatDelay);
}
/**
@@ -41,7 +52,7 @@ class Scheduling {
* @param repeatDelay - the amount of time inbetween each execution. If less than zero, the task is only executed once.
* @return A cancel token.
*/
- public static TaskWrapper runAsynchronously(final Plugin plugin, final BukkitScheduler scheduler, Runnable runnable, long firstDelay, long repeatDelay) {
+ public static TaskWrapper runAsynchronouslyRepeat(final Plugin plugin, final BukkitScheduler scheduler, Runnable runnable, long firstDelay, long repeatDelay) {
try {
@SuppressWarnings("deprecation")
final int taskID = scheduler.scheduleAsyncRepeatingTask(plugin, runnable, firstDelay, repeatDelay);
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java
index c1b2edb7..1ef3de0f 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedWatchableObject.java
@@ -218,6 +218,14 @@ public class WrappedWatchableObject {
modifier.withType(Object.class).write(0, getUnwrapped(newValue));
}
+ /**
+ * Read the underlying value field.
+ * @return The underlying value.
+ */
+ private Object getNMSValue() {
+ return modifier.withType(Object.class).read(0);
+ }
+
/**
* Read the value field.
* @return The watched value.
@@ -324,7 +332,7 @@ public class WrappedWatchableObject {
// Helper
Object getClonedValue() throws FieldAccessException {
- Object value = getValue();
+ Object value = getNMSValue();
// Only a limited set of references types are supported
if (MinecraftReflection.isChunkPosition(value)) {
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java
index ba27a6cb..5465ae29 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java
@@ -272,7 +272,7 @@ public interface NbtCompound extends NbtBase