Merge branch 'master' into gh-pages

This commit is contained in:
Kristian S. Stangeland 2013-01-22 13:26:58 +01:00
commit 290b791eb3
24 changed files with 243 additions and 77 deletions

View File

@ -11,12 +11,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>net.sourceforge.metrics.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>net.sourceforge.metrics.builder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>2.0.0</version>
<version>2.1.0</version>
<packaging>jar</packaging>
<description>Provides read/write access to the Minecraft protocol.</description>
@ -203,7 +203,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.4.6-R0.1</version>
<version>1.4.7-R0.1</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -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.
*/

View File

@ -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 <a href="http://www.wiki.vg/Protocol_History#2012-12-20">Protocol History - MinecraftCoalition</a>
*/
@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;

View File

@ -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.
*
@ -36,9 +38,10 @@ class ProtocolConfig {
private static final String METRICS_ENABLED = "metrics";
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";
private static final String UPDATER_DELAY = "delay";
@ -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.
*/

View File

@ -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()) {

View File

@ -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);
}
/**

View File

@ -114,6 +114,9 @@ public class BlockingHashMap<TKey, TValue> {
if (remainingTime > 0) {
TimeUnit.NANOSECONDS.timedWait(lock, remainingTime);
value = backingMap.get(key);
} else {
// Timeout elapsed
break;
}
}
}

View File

@ -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<Boolean> getBooleans() {
return structureModifier.withType(boolean.class);
}
/**
* Retrieves a read/write structure for every short field.
* @return A modifier for every short field.

View File

@ -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()
));

View File

@ -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;

View File

@ -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<Integer, Updater.UpdateResult> valueList = new HashMap<Integer, Updater.UpdateResult>();
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;

View File

@ -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);

View File

@ -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)) {

View File

@ -272,7 +272,7 @@ public interface NbtCompound extends NbtBase<Map<String, NbtBase<?>>>, Iterable<
* @param compound - the compound value.
* @return This current compound, for chaining.
*/
public abstract NbtCompound put(WrappedCompound compound);
public abstract NbtCompound put(NbtCompound compound);
/**
* Retrieve the NBT list value of an entry identified by a given key.

View File

@ -524,7 +524,7 @@ class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Iterable<N
* @return This current compound, for chaining.
*/
@Override
public NbtCompound put(WrappedCompound compound) {
public NbtCompound put(NbtCompound compound) {
getValue().put(compound.getName(), compound);
return this;
}

View File

@ -16,3 +16,7 @@ global:
# Disable version checking for the given Minecraft version. Backup your world first!
ignore version check:
# Override the starting injecting method
injection method:

View File

@ -1,5 +1,5 @@
name: ProtocolLib
version: 2.0.0
version: 2.1.0
description: Provides read/write access to the Minecraft protocol.
author: Comphenix
website: http://www.comphenix.net/ProtocolLib

View File

@ -0,0 +1,60 @@
package com.comphenix.protocol;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
// Will have to be updated for every version though
import org.bukkit.craftbukkit.v1_4_R1.inventory.CraftItemFactory;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.meta.ItemMeta;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.utility.MinecraftReflection;
/**
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
*
* @author Kristian
*/
public class BukkitInitialization {
private static boolean initialized;
/**
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing.
* @throws IllegalAccessException If we are unable to initialize Bukkit.
*/
public static void initializeItemMeta() throws IllegalAccessException {
if (!initialized) {
// Denote that we're done
initialized = true;
initializePackage();
// Mock the server object
Server mockedServer = mock(Server.class);
ItemFactory mockedFactory = mock(CraftItemFactory.class);
ItemMeta mockedMeta = mock(ItemMeta.class);
when(mockedServer.getItemFactory()).thenReturn(mockedFactory);
when(mockedFactory.getItemMeta(any(Material.class))).thenReturn(mockedMeta);
// Inject this fake server
FieldUtils.writeStaticField(Bukkit.class, "server", mockedServer, true);
// And the fake item factory
FieldUtils.writeStaticField(CraftItemFactory.class, "instance", mockedFactory, true);
}
}
/**
* Ensure that package names are correctly set up.
*/
public static void initializePackage() {
// Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_R1", "org.bukkit.craftbukkit.v1_4_R1");
}
}

View File

@ -18,31 +18,23 @@
package com.comphenix.protocol.events;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.Array;
import java.util.List;
// Will have to be updated for every version though
import org.bukkit.craftbukkit.v1_4_6.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_4_R1.inventory.CraftItemFactory;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.WorldType;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.BukkitConverters;
@ -65,22 +57,7 @@ public class PacketContainerTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
// Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_6", "org.bukkit.craftbukkit.v1_4_6");
// Mock the server object
Server mockedServer = mock(Server.class);
ItemFactory mockedFactory = mock(CraftItemFactory.class);
ItemMeta mockedMeta = mock(ItemMeta.class);
when(mockedServer.getItemFactory()).thenReturn(mockedFactory);
when(mockedFactory.getItemMeta(any(Material.class))).thenReturn(mockedMeta);
// Inject this fake server
FieldUtils.writeStaticField(Bukkit.class, "server", mockedServer, true);
// And the fake item factory
FieldUtils.writeStaticField(CraftItemFactory.class, "instance", mockedFactory, true);
BukkitInitialization.initializeItemMeta();
}
private <T> void testPrimitive(StructureModifier<T> modifier, int index, T initialValue, T testValue) {

View File

@ -30,7 +30,6 @@ import com.comphenix.protocol.events.ListenerPriority;
import com.google.common.primitives.Ints;
public class SortedCopyOnWriteArrayTest {
@Test
public void testInsertion() {

View File

@ -21,13 +21,12 @@ import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.BukkitInitialization;
public class NbtCompoundTest {
@BeforeClass
public static void setupBukkit() {
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_6", "org.bukkit.craftbukkit.v1_4_6");
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@Test

View File

@ -28,15 +28,13 @@ import java.io.DataOutputStream;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
public class NbtFactoryTest {
@BeforeClass
public static void initializeBukkit() {
// Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_6", "org.bukkit.craftbukkit.v1_4_6");
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@Test

View File

@ -6,15 +6,14 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
public class NbtConfigurationSerializerTest {
@BeforeClass
public static void initializeBukkit() {
// Initialize reflection
MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_6", "org.bukkit.craftbukkit.v1_4_6");
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
@SuppressWarnings("unchecked")