diff --git a/ProtocolLib/.project b/ProtocolLib/.project
index 3b5df9da..a1960c9e 100644
--- a/ProtocolLib/.project
+++ b/ProtocolLib/.project
@@ -15,9 +15,15 @@
+
+ net.sourceforge.metrics.builder
+
+
+ org.eclipse.m2e.core.maven2Natureorg.eclipse.jdt.core.javanature
+ net.sourceforge.metrics.nature
diff --git a/ProtocolLib/dependency-reduced-pom.xml b/ProtocolLib/dependency-reduced-pom.xml
index 00d4c784..ea37303c 100644
--- a/ProtocolLib/dependency-reduced-pom.xml
+++ b/ProtocolLib/dependency-reduced-pom.xml
@@ -4,7 +4,7 @@
com.comphenix.protocolProtocolLibProtocolLib
- 1.8.0
+ 1.9.0Provides read/write access to the Minecraft protocol.http://dev.bukkit.org/server-mods/protocollib/
@@ -139,7 +139,7 @@
org.bukkitcraftbukkit
- 1.4.5-R0.3-SNAPSHOT
+ 1.4.6-R0.1provided
@@ -154,6 +154,36 @@
+
+ org.mockito
+ mockito-all
+ 1.8.4
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ 1.5
+ test
+
+
+ powermock-module-junit4-common
+ org.powermock
+
+
+
+
+ org.powermock
+ powermock-api-mockito
+ 1.5
+ test
+
+
+ powermock-api-support
+ org.powermock
+
+
+
@@ -181,6 +211,7 @@
+ 1.5cp1252
diff --git a/ProtocolLib/pom.xml b/ProtocolLib/pom.xml
index 421b5e48..c95ebec1 100644
--- a/ProtocolLib/pom.xml
+++ b/ProtocolLib/pom.xml
@@ -2,12 +2,13 @@
4.0.0com.comphenix.protocolProtocolLib
- 1.8.0
+ 1.9.0jarProvides read/write access to the Minecraft protocol.cp1252
+ 1.5
@@ -202,7 +203,7 @@
org.bukkitcraftbukkit
- 1.4.5-R0.3-SNAPSHOT
+ 1.4.6-R0.1provided
@@ -211,5 +212,23 @@
4.10test
+
+ org.mockito
+ mockito-all
+ 1.8.4
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ ${powermock.version}
+ test
+
+
+ org.powermock
+ powermock-api-mockito
+ ${powermock.version}
+ test
+
\ No newline at end of file
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java
index f04aebdc..f4940bee 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CleanupStaticMembers.java
@@ -1,3 +1,20 @@
+/*
+ * 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.lang.reflect.Field;
@@ -13,7 +30,7 @@ import com.comphenix.protocol.injector.BukkitUnwrapper;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.MethodUtils;
-import com.comphenix.protocol.reflect.ObjectCloner;
+import com.comphenix.protocol.reflect.ObjectWriter;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.reflect.compiler.StructureCompiler;
import com.comphenix.protocol.reflect.instances.CollectionGenerator;
@@ -48,7 +65,7 @@ class CleanupStaticMembers {
BukkitUnwrapper.class, DefaultInstances.class, CollectionGenerator.class,
PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class,
BackgroundCompiler.class, StructureCompiler.class,
- ObjectCloner.class, Packets.Server.class, Packets.Client.class,
+ ObjectWriter.class, Packets.Server.class, Packets.Client.class,
ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class
};
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java
index 7cda5346..18ddb25e 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandBase.java
@@ -1,3 +1,20 @@
+/*
+ * 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 org.bukkit.ChatColor;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java
index 5719a097..4da7a3c4 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandPacket.java
@@ -1,3 +1,20 @@
+/*
+ * 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.lang.reflect.InvocationTargetException;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
index d4c6aa05..c35f7632 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/CommandProtocol.java
@@ -1,3 +1,20 @@
+/*
+ * 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 org.bukkit.ChatColor;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java b/ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java
index 6544ac11..53fb9898 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java
@@ -1,3 +1,20 @@
+/*
+ * 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.util.regex.Matcher;
@@ -7,6 +24,7 @@ import org.bukkit.Server;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
/**
* Determine the current Minecraft version.
@@ -22,6 +40,9 @@ class MinecraftVersion implements Comparable {
private final int major;
private final int minor;
private final int build;
+
+ // The development stage
+ private final String development;
/**
* Determine the current Minecraft version.
@@ -36,11 +57,13 @@ class MinecraftVersion implements Comparable {
* @param versionOnly - the version in text form.
*/
public MinecraftVersion(String versionOnly) {
- int[] numbers = parseVersion(versionOnly);
+ String[] section = versionOnly.split("-");
+ int[] numbers = parseVersion(section[0]);
this.major = numbers[0];
this.minor = numbers[1];
this.build = numbers[2];
+ this.development = section.length > 1 ? section[1] : null;
}
/**
@@ -50,9 +73,21 @@ class MinecraftVersion implements Comparable {
* @param build - build version number.
*/
public MinecraftVersion(int major, int minor, int build) {
+ this(major, minor, build, null);
+ }
+
+ /**
+ * Construct a version object directly.
+ * @param major - major version number.
+ * @param minor - minor version number.
+ * @param build - build version number.
+ * @param development - development stage.
+ */
+ public MinecraftVersion(int major, int minor, int build, String development) {
this.major = major;
this.minor = minor;
this.build = build;
+ this.development = development;
}
private int[] parseVersion(String version) {
@@ -65,7 +100,7 @@ class MinecraftVersion implements Comparable {
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
for (int i = 0; i < Math.min(numbers.length, elements.length); i++)
- numbers[i] = Integer.parseInt(elements[i].trim());
+ numbers[i] = Integer.parseInt(elements[i].trim());
return numbers;
}
@@ -93,12 +128,23 @@ class MinecraftVersion implements Comparable {
return build;
}
+ /**
+ * Retrieve the development stage.
+ * @return Development stage, or NULL if this is a release.
+ */
+ public String getDevelopmentStage() {
+ return development;
+ }
+
/**
* Retrieve the version String (major.minor.build) only.
* @return A normal version string.
*/
public String getVersion() {
- return String.format("%s.%s.%s", major, minor, build);
+ if (development == null)
+ return String.format("%s.%s.%s", major, minor, build);
+ else
+ return String.format("%s.%s.%s-%s", major, minor, build, development);
}
@Override
@@ -110,6 +156,8 @@ class MinecraftVersion implements Comparable {
compare(major, o.major).
compare(minor, o.minor).
compare(build, o.build).
+ // No development String means it's a release
+ compare(development, o.development, Ordering.natural().nullsLast()).
result();
}
@@ -125,7 +173,8 @@ class MinecraftVersion implements Comparable {
return major == other.major &&
minor == other.minor &&
- build == other.build;
+ build == other.build &&
+ Objects.equal(development, other.development);
}
return false;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
index f135fa97..040a8ef1 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java
@@ -1,3 +1,20 @@
+/*
+ * 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;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
index 2f5b4774..c8c3e0a8 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
@@ -17,11 +17,14 @@
package com.comphenix.protocol;
+import java.io.File;
import java.io.IOException;
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;
@@ -52,7 +55,7 @@ public class ProtocolLibrary extends JavaPlugin {
/**
* The maximum version ProtocolLib has been tested with,
*/
- private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.5";
+ private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.6";
/**
* The number of milliseconds per second.
@@ -65,7 +68,7 @@ public class ProtocolLibrary extends JavaPlugin {
private static PacketFilterManager protocolManager;
// Error reporter
- private ErrorReporter reporter;
+ private static ErrorReporter reporter;
// Metrics and statistisc
private Statistics statistisc;
@@ -97,6 +100,9 @@ public class ProtocolLibrary extends JavaPlugin {
private CommandProtocol commandProtocol;
private CommandPacket commandPacket;
+ // Whether or not disable is not needed
+ private boolean skipDisable;
+
@Override
public void onLoad() {
// Load configuration
@@ -104,7 +110,6 @@ public class ProtocolLibrary extends JavaPlugin {
// Add global parameters
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
- updater = new Updater(this, logger, "protocollib", getFile(), "protocol.info");
reporter = detailedReporter;
try {
@@ -121,6 +126,12 @@ public class ProtocolLibrary extends JavaPlugin {
}
try {
+ // Check for other versions
+ checkConflictingVersions();
+
+ // Set updater
+ updater = new Updater(this, logger, "protocollib", getFile(), "protocol.info");
+
unhookTask = new DelayedSingleTask(this);
protocolManager = new PacketFilterManager(getClassLoader(), getServer(), unhookTask, detailedReporter);
detailedReporter.addGlobalParameter("manager", protocolManager);
@@ -252,6 +263,45 @@ public class ProtocolLibrary extends JavaPlugin {
reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e);
}
}
+
+ private void checkConflictingVersions() {
+ Pattern ourPlugin = Pattern.compile("ProtocolLib-(.*)\\.jar");
+ MinecraftVersion currentVersion = new MinecraftVersion(this.getDescription().getVersion());
+ MinecraftVersion newestVersion = null;
+
+ try {
+ // Scan the plugin folder for newer versions of ProtocolLib
+ File pluginFolder = new File("plugins/");
+
+ for (File candidate : pluginFolder.listFiles()) {
+ if (candidate.isFile()) {
+ Matcher match = ourPlugin.matcher(candidate.getName());
+
+ if (match.matches()) {
+ MinecraftVersion version = new MinecraftVersion(match.group(1));
+
+ if (newestVersion == null || newestVersion.compareTo(version) < 0) {
+ newestVersion = version;
+ }
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ reporter.reportWarning(this, "Unable to detect conflicting plugin versions.", e);
+ }
+
+ // 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;
+
+ throw new IllegalStateException(
+ String.format("Detected a newer version of ProtocolLib (%s) in plugin folder than the current (%s). Disabling.",
+ newestVersion.getVersion(), currentVersion.getVersion())
+ );
+ }
+ }
private void registerCommand(String name, CommandExecutor executor) {
try {
@@ -331,6 +381,10 @@ public class ProtocolLibrary extends JavaPlugin {
@Override
public void onDisable() {
+ if (skipDisable) {
+ return;
+ }
+
// Disable compiler
if (backgroundCompiler != null) {
backgroundCompiler.shutdownAll();
@@ -353,6 +407,7 @@ public class ProtocolLibrary extends JavaPlugin {
protocolManager.close();
protocolManager = null;
statistisc = null;
+ reporter = null;
// Leaky ClassLoader begone!
CleanupStaticMembers cleanup = new CleanupStaticMembers(getClassLoader(), reporter);
@@ -373,6 +428,14 @@ public class ProtocolLibrary extends JavaPlugin {
return log;
}
+ /**
+ * Retrieve the current error reporter.
+ * @return Current error reporter.
+ */
+ public static ErrorReporter getErrorReporter() {
+ return reporter;
+ }
+
/**
* Retrieves the packet protocol manager.
* @return Packet protocol manager, or NULL if it has been disabled.
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java b/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java
index d396be43..f893f731 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/RangeParser.java
@@ -1,3 +1,20 @@
+/*
+ * 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.util.ArrayList;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java
index 8dc4d0be..e2aa0f09 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java
@@ -1,3 +1,20 @@
+/*
+ * 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.async;
import java.util.ArrayList;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/AbstractIntervalTree.java b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/AbstractIntervalTree.java
index 9b241e90..7d29ddf2 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/AbstractIntervalTree.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/AbstractIntervalTree.java
@@ -1,3 +1,20 @@
+/*
+ * 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.concurrency;
import java.util.HashSet;
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 793f3c11..df867951 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/concurrency/BlockingHashMap.java
@@ -1,3 +1,20 @@
+/*
+ * 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.concurrency;
import java.util.Collection;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/error/DetailedErrorReporter.java b/ProtocolLib/src/main/java/com/comphenix/protocol/error/DetailedErrorReporter.java
index 9b6ef329..09786d1a 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/error/DetailedErrorReporter.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/error/DetailedErrorReporter.java
@@ -1,3 +1,20 @@
+/*
+ * 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.error;
import java.io.PrintWriter;
@@ -6,6 +23,9 @@ import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -15,6 +35,7 @@ import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.reflect.PrettyPrinter;
import com.google.common.primitives.Primitives;
/**
@@ -35,10 +56,14 @@ public class DetailedErrorReporter implements ErrorReporter {
// We don't want to spam the server
public static final int DEFAULT_MAX_ERROR_COUNT = 20;
+ // Prevent spam per plugin too
+ private ConcurrentMap warningCount = new ConcurrentHashMap();
+
protected String prefix;
protected String supportURL;
- protected int errorCount;
+ protected AtomicInteger internalErrorCount = new AtomicInteger();
+
protected int maxErrorCount;
protected Logger logger;
@@ -97,23 +122,65 @@ public class DetailedErrorReporter implements ErrorReporter {
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
- reportMinimal(sender, methodName, error);
-
- // Print parameters, if they are given
- if (parameters != null && parameters.length > 0) {
- logger.log(Level.SEVERE, " Parameters:");
-
- // Print each parameter
- for (Object parameter : parameters) {
- logger.log(Level.SEVERE, " " + getStringDescription(parameter));
+ if (reportMinimalNoSpam(sender, methodName, error)) {
+ // Print parameters, if they are given
+ if (parameters != null && parameters.length > 0) {
+ logger.log(Level.SEVERE, " Parameters:");
+
+ // Print each parameter
+ for (Object parameter : parameters) {
+ logger.log(Level.SEVERE, " " + getStringDescription(parameter));
+ }
}
}
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
- logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception occured in " + methodName + " for " +
- PacketAdapter.getPluginName(sender), error);
+ reportMinimalNoSpam(sender, methodName, error);
+ }
+
+ public boolean reportMinimalNoSpam(Plugin sender, String methodName, Throwable error) {
+ String pluginName = PacketAdapter.getPluginName(sender);
+ AtomicInteger counter = warningCount.get(pluginName);
+
+ // Thread safe pattern
+ if (counter == null) {
+ AtomicInteger created = new AtomicInteger();
+ counter = warningCount.putIfAbsent(pluginName, created);
+
+ if (counter == null) {
+ counter = created;
+ }
+ }
+
+ final int errorCount = counter.incrementAndGet();
+
+ // See if we should print the full error
+ if (errorCount < getMaxErrorCount()) {
+ logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception occured in " +
+ methodName + " for " + pluginName, error);
+ return true;
+
+ } else {
+ // Nope - only print the error count occationally
+ if (isPowerOfTwo(errorCount)) {
+ logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception number " + errorCount + " occured in " +
+ methodName + " for " + pluginName, error);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Determine if a given number is a power of two.
+ *
+ * That is, if there exists an N such that 2^N = number.
+ * @param number - the number to check.
+ * @return TRUE if the given number is a power of two, FALSE otherwise.
+ */
+ private boolean isPowerOfTwo(int number) {
+ return (number & (number - 1)) == 0;
}
@Override
@@ -137,12 +204,18 @@ public class DetailedErrorReporter implements ErrorReporter {
public void reportDetailed(Object sender, String message, Throwable error, Object... parameters) {
final Plugin plugin = pluginReference.get();
+ final int errorCount = internalErrorCount.incrementAndGet();
// Do not overtly spam the server!
- if (++errorCount > maxErrorCount) {
- String maxReached = String.format("Reached maxmimum error count. Cannot pass error %s from %s.", error, sender);
- logger.severe(maxReached);
- return;
+ if (errorCount > getMaxErrorCount()) {
+ // Only allow the error count at rare occations
+ if (isPowerOfTwo(errorCount)) {
+ // Permit it - but print the number of exceptions first
+ reportWarning(this, "Internal exception count: " + errorCount + "!");
+ } else {
+ // NEVER SPAM THE CONSOLE
+ return;
+ }
}
StringWriter text = new StringWriter();
@@ -230,12 +303,15 @@ public class DetailedErrorReporter implements ErrorReporter {
return (ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null));
} catch (Throwable ex) {
// Apache is probably missing
- logger.warning("Cannot find Apache Commons. Object introspection disabled.");
apacheCommonsMissing = true;
}
- // Just use toString()
- return String.format("%s", value);
+ // Use our custom object printer instead
+ try {
+ return PrettyPrinter.printObject(value, value.getClass(), Object.class);
+ } catch (IllegalAccessException e) {
+ return "[Error: " + e.getMessage() + "]";
+ }
}
}
@@ -249,11 +325,11 @@ public class DetailedErrorReporter implements ErrorReporter {
}
public int getErrorCount() {
- return errorCount;
+ return internalErrorCount.get();
}
public void setErrorCount(int errorCount) {
- this.errorCount = errorCount;
+ internalErrorCount.set(errorCount);
}
public int getMaxErrorCount() {
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/error/ErrorReporter.java b/ProtocolLib/src/main/java/com/comphenix/protocol/error/ErrorReporter.java
index 54b45f48..e1b7f927 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/error/ErrorReporter.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/error/ErrorReporter.java
@@ -1,3 +1,20 @@
+/*
+ * 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.error;
import org.bukkit.plugin.Plugin;
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java
index 832c2d8f..358c6bd0 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/MonitorAdapter.java
@@ -1,3 +1,20 @@
+/*
+ * 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.events;
import java.util.logging.Level;
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 a7b4a265..c724a266 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java
@@ -17,20 +17,21 @@
package com.comphenix.protocol.events;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
+import javax.annotation.Nullable;
+
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
@@ -39,12 +40,22 @@ import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.injector.StructureCache;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
+import com.comphenix.protocol.reflect.ObjectWriter;
import com.comphenix.protocol.reflect.StructureModifier;
+import com.comphenix.protocol.reflect.cloning.AggregateCloner;
+import com.comphenix.protocol.reflect.cloning.BukkitCloner;
+import com.comphenix.protocol.reflect.cloning.Cloner;
+import com.comphenix.protocol.reflect.cloning.CollectionCloner;
+import com.comphenix.protocol.reflect.cloning.FieldCloner;
+import com.comphenix.protocol.reflect.cloning.ImmutableDetector;
+import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
+import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
+import com.google.common.base.Function;
import com.google.common.collect.Maps;
/**
@@ -69,6 +80,28 @@ public class PacketContainer implements Serializable {
private static ConcurrentMap, Method> writeMethods = Maps.newConcurrentMap();
private static ConcurrentMap, Method> readMethods = Maps.newConcurrentMap();
+ // Used to clone packets
+ private static final AggregateCloner DEEP_CLONER = AggregateCloner.newBuilder().
+ instanceProvider(DefaultInstances.DEFAULT).
+ andThen(BukkitCloner.class).
+ andThen(ImmutableDetector.class).
+ andThen(CollectionCloner.class).
+ andThen(getSpecializedDeepClonerFactory()).
+ build();
+
+ private static final AggregateCloner SHALLOW_CLONER = AggregateCloner.newBuilder().
+ instanceProvider(DefaultInstances.DEFAULT).
+ andThen(new Function() {
+ @Override
+ public Cloner apply(@Nullable BuilderParameters param) {
+ return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
+ // Use a default writer with no concept of cloning
+ writer = new ObjectWriter();
+ }};
+ }
+ }).
+ build();
+
/**
* Creates a packet container for a new packet.
* @param id - ID of the packet to create.
@@ -241,12 +274,12 @@ public class PacketContainer implements Serializable {
BukkitConverters.getIgnoreNull(new EquivalentConverter() {
public Object getGeneric(Class>genericType, ItemStack[] specific) {
- Object[] result = new Object[specific.length];
+ Class> nmsStack = MinecraftReflection.getItemStackClass();
+ Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
- result[i] = stackConverter.getGeneric(
- MinecraftReflection.getItemStackClass(), specific[i]);
+ result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
}
return result;
}
@@ -364,40 +397,54 @@ public class PacketContainer implements Serializable {
return id;
}
+ /**
+ * Create a shallow copy of the current packet.
+ *
+ * This merely writes the content of each field to the new class directly,
+ * without performing any expensive copies.
+ *
+ * @return A shallow copy of the current packet.
+ */
+ public PacketContainer shallowClone() {
+ Object clonedPacket = SHALLOW_CLONER.clone(getHandle());
+ return new PacketContainer(getID(), clonedPacket);
+ }
+
/**
* Create a deep copy of the current packet.
+ *
+ * This will perform a full copy of the entire object tree, only skipping
+ * known immutable objects and primitive types.
+ *
+ * Note that the inflated buffers in packet 51 and 56 will be copied directly to save memory.
+ *
* @return A deep copy of the current packet.
*/
public PacketContainer deepClone() {
- ObjectOutputStream output = null;
- ObjectInputStream input = null;
-
- try {
- // Use a small buffer of 32 bytes initially.
- ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
- output = new ObjectOutputStream(bufferOut);
- output.writeObject(this);
-
- ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
- input = new ObjectInputStream(bufferIn);
- return (PacketContainer) input.readObject();
-
- } catch (IOException e) {
- throw new IllegalStateException("Unexpected error occured during object cloning.", e);
- } catch (ClassNotFoundException e) {
- // Cannot happen
- throw new IllegalStateException("Unexpected failure with serialization.", e);
- } finally {
- try {
- if (output != null)
- output.close();
- if (input != null)
- input.close();
-
- } catch (IOException e) {
- // STOP IT
+ Object clonedPacket = DEEP_CLONER.clone(getHandle());
+ return new PacketContainer(getID(), clonedPacket);
+ }
+
+ // To save space, we'll skip copying the inflated buffers in packet 51 and 56
+ private static Function getSpecializedDeepClonerFactory() {
+ // Look at what you've made me do Java, look at it!!
+ return new Function() {
+ @Override
+ public Cloner apply(@Nullable BuilderParameters param) {
+ return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
+ this.writer = new ObjectWriter() {
+ protected void transformField(StructureModifier