diff --git a/CraftBukkit-Patches/0002-mc-dev-imports.patch b/CraftBukkit-Patches/0002-mc-dev-imports.patch
index d8236cfa9c..39d6aebbd1 100644
--- a/CraftBukkit-Patches/0002-mc-dev-imports.patch
+++ b/CraftBukkit-Patches/0002-mc-dev-imports.patch
@@ -1,4 +1,4 @@
-From 728698cfb07683d5ce15c07ea8cf32591cc4c95c Mon Sep 17 00:00:00 2001
+From 1d5b81555def55b67178090ba0e5f3ecf27f5bda Mon Sep 17 00:00:00 2001
 From: md_5 <md_5@live.com.au>
 Date: Sun, 1 Dec 2013 15:10:48 +1100
 Subject: [PATCH] mc-dev imports
@@ -1187,6 +1187,281 @@ index 0000000..90a2a80
 +        c.put(ChunkCoordinates.class, Integer.valueOf(6));
 +    }
 +}
+diff --git a/src/main/java/net/minecraft/server/NBTBase.java b/src/main/java/net/minecraft/server/NBTBase.java
+new file mode 100644
+index 0000000..6e7c3a2
+--- /dev/null
++++ b/src/main/java/net/minecraft/server/NBTBase.java
+@@ -0,0 +1,129 @@
++package net.minecraft.server;
++
++import java.io.DataInput;
++import java.io.DataOutput;
++import java.io.IOException;
++
++public abstract class NBTBase {
++
++    public static final String[] a = new String[] { "END", "BYTE", "SHORT", "INT", "LONG", "FLOAT", "DOUBLE", "BYTE[]", "STRING", "LIST", "COMPOUND", "INT[]"};
++
++    abstract void write(DataOutput dataoutput) throws IOException;
++
++    abstract void load(DataInput datainput, int i) throws IOException;
++
++    public abstract String toString();
++
++    public abstract byte getTypeId();
++
++    protected NBTBase() {}
++
++    protected static NBTBase createTag(byte b0) {
++        switch (b0) {
++        case 0:
++            return new NBTTagEnd();
++
++        case 1:
++            return new NBTTagByte();
++
++        case 2:
++            return new NBTTagShort();
++
++        case 3:
++            return new NBTTagInt();
++
++        case 4:
++            return new NBTTagLong();
++
++        case 5:
++            return new NBTTagFloat();
++
++        case 6:
++            return new NBTTagDouble();
++
++        case 7:
++            return new NBTTagByteArray();
++
++        case 8:
++            return new NBTTagString();
++
++        case 9:
++            return new NBTTagList();
++
++        case 10:
++            return new NBTTagCompound();
++
++        case 11:
++            return new NBTTagIntArray();
++
++        default:
++            return null;
++        }
++    }
++
++    public static String getTagName(int i) {
++        switch (i) {
++        case 0:
++            return "TAG_End";
++
++        case 1:
++            return "TAG_Byte";
++
++        case 2:
++            return "TAG_Short";
++
++        case 3:
++            return "TAG_Int";
++
++        case 4:
++            return "TAG_Long";
++
++        case 5:
++            return "TAG_Float";
++
++        case 6:
++            return "TAG_Double";
++
++        case 7:
++            return "TAG_Byte_Array";
++
++        case 8:
++            return "TAG_String";
++
++        case 9:
++            return "TAG_List";
++
++        case 10:
++            return "TAG_Compound";
++
++        case 11:
++            return "TAG_Int_Array";
++
++        case 99:
++            return "Any Numeric Tag";
++
++        default:
++            return "UNKNOWN";
++        }
++    }
++
++    public abstract NBTBase clone();
++
++    public boolean equals(Object object) {
++        if (!(object instanceof NBTBase)) {
++            return false;
++        } else {
++            NBTBase nbtbase = (NBTBase) object;
++
++            return this.getTypeId() == nbtbase.getTypeId();
++        }
++    }
++
++    public int hashCode() {
++        return this.getTypeId();
++    }
++
++    protected String a_() {
++        return this.toString();
++    }
++}
+diff --git a/src/main/java/net/minecraft/server/NBTTagByteArray.java b/src/main/java/net/minecraft/server/NBTTagByteArray.java
+new file mode 100644
+index 0000000..916d935
+--- /dev/null
++++ b/src/main/java/net/minecraft/server/NBTTagByteArray.java
+@@ -0,0 +1,56 @@
++package net.minecraft.server;
++
++import java.io.DataInput;
++import java.io.DataOutput;
++import java.io.IOException;
++import java.util.Arrays;
++
++public class NBTTagByteArray extends NBTBase {
++
++    private byte[] data;
++
++    NBTTagByteArray() {}
++
++    public NBTTagByteArray(byte[] abyte) {
++        this.data = abyte;
++    }
++
++    void write(DataOutput dataoutput) throws IOException {
++        dataoutput.writeInt(this.data.length);
++        dataoutput.write(this.data);
++    }
++
++    void load(DataInput datainput, int i) throws IOException {
++        int j = datainput.readInt();
++
++        this.data = new byte[j];
++        datainput.readFully(this.data);
++    }
++
++    public byte getTypeId() {
++        return (byte) 7;
++    }
++
++    public String toString() {
++        return "[" + this.data.length + " bytes]";
++    }
++
++    public NBTBase clone() {
++        byte[] abyte = new byte[this.data.length];
++
++        System.arraycopy(this.data, 0, abyte, 0, this.data.length);
++        return new NBTTagByteArray(abyte);
++    }
++
++    public boolean equals(Object object) {
++        return super.equals(object) ? Arrays.equals(this.data, ((NBTTagByteArray) object).data) : false;
++    }
++
++    public int hashCode() {
++        return super.hashCode() ^ Arrays.hashCode(this.data);
++    }
++
++    public byte[] c() {
++        return this.data;
++    }
++}
+diff --git a/src/main/java/net/minecraft/server/NBTTagIntArray.java b/src/main/java/net/minecraft/server/NBTTagIntArray.java
+new file mode 100644
+index 0000000..49b3f14
+--- /dev/null
++++ b/src/main/java/net/minecraft/server/NBTTagIntArray.java
+@@ -0,0 +1,72 @@
++package net.minecraft.server;
++
++import java.io.DataInput;
++import java.io.DataOutput;
++import java.io.IOException;
++import java.util.Arrays;
++
++public class NBTTagIntArray extends NBTBase {
++
++    private int[] data;
++
++    NBTTagIntArray() {}
++
++    public NBTTagIntArray(int[] aint) {
++        this.data = aint;
++    }
++
++    void write(DataOutput dataoutput) throws IOException {
++        dataoutput.writeInt(this.data.length);
++
++        for (int i = 0; i < this.data.length; ++i) {
++            dataoutput.writeInt(this.data[i]);
++        }
++    }
++
++    void load(DataInput datainput, int i) throws IOException {
++        int j = datainput.readInt();
++
++        this.data = new int[j];
++
++        for (int k = 0; k < j; ++k) {
++            this.data[k] = datainput.readInt();
++        }
++    }
++
++    public byte getTypeId() {
++        return (byte) 11;
++    }
++
++    public String toString() {
++        String s = "[";
++        int[] aint = this.data;
++        int i = aint.length;
++
++        for (int j = 0; j < i; ++j) {
++            int k = aint[j];
++
++            s = s + k + ",";
++        }
++
++        return s + "]";
++    }
++
++    public NBTBase clone() {
++        int[] aint = new int[this.data.length];
++
++        System.arraycopy(this.data, 0, aint, 0, this.data.length);
++        return new NBTTagIntArray(aint);
++    }
++
++    public boolean equals(Object object) {
++        return super.equals(object) ? Arrays.equals(this.data, ((NBTTagIntArray) object).data) : false;
++    }
++
++    public int hashCode() {
++        return super.hashCode() ^ Arrays.hashCode(this.data);
++    }
++
++    public int[] c() {
++        return this.data;
++    }
++}
 diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java
 new file mode 100644
 index 0000000..06934a1
@@ -2282,5 +2557,5 @@ index 0000000..c0db754
 +    }
 +}
 -- 
-1.8.4.msysgit.0
+1.8.3.2
 
diff --git a/CraftBukkit-Patches/0097-Catch-stalling-on-corrupted-map-data-NBT-arrays.patch b/CraftBukkit-Patches/0097-Catch-stalling-on-corrupted-map-data-NBT-arrays.patch
new file mode 100644
index 0000000000..9acded7db1
--- /dev/null
+++ b/CraftBukkit-Patches/0097-Catch-stalling-on-corrupted-map-data-NBT-arrays.patch
@@ -0,0 +1,33 @@
+From 51cc9fc818ece90ca3349895c2d8d7d7f210b99e Mon Sep 17 00:00:00 2001
+From: md_5 <git@md-5.net>
+Date: Mon, 20 Jan 2014 13:44:07 +1100
+Subject: [PATCH] Catch stalling on corrupted map data / NBT arrays.
+
+
+diff --git a/src/main/java/net/minecraft/server/NBTTagByteArray.java b/src/main/java/net/minecraft/server/NBTTagByteArray.java
+index 916d935..3fa9c1a 100644
+--- a/src/main/java/net/minecraft/server/NBTTagByteArray.java
++++ b/src/main/java/net/minecraft/server/NBTTagByteArray.java
+@@ -22,6 +22,7 @@ public class NBTTagByteArray extends NBTBase {
+ 
+     void load(DataInput datainput, int i) throws IOException {
+         int j = datainput.readInt();
++        com.google.common.base.Preconditions.checkArgument( i < 1 << 24);
+ 
+         this.data = new byte[j];
+         datainput.readFully(this.data);
+diff --git a/src/main/java/net/minecraft/server/NBTTagIntArray.java b/src/main/java/net/minecraft/server/NBTTagIntArray.java
+index 49b3f14..6c33462 100644
+--- a/src/main/java/net/minecraft/server/NBTTagIntArray.java
++++ b/src/main/java/net/minecraft/server/NBTTagIntArray.java
+@@ -25,6 +25,7 @@ public class NBTTagIntArray extends NBTBase {
+ 
+     void load(DataInput datainput, int i) throws IOException {
+         int j = datainput.readInt();
++        com.google.common.base.Preconditions.checkArgument( i < 1 << 24);
+ 
+         this.data = new int[j];
+ 
+-- 
+1.8.3.2
+
diff --git a/CraftBukkit-Patches/0097-Optimize-NextTickList-processing.patch b/CraftBukkit-Patches/0097-Optimize-NextTickList-processing.patch
deleted file mode 100644
index d956a4010e..0000000000
--- a/CraftBukkit-Patches/0097-Optimize-NextTickList-processing.patch
+++ /dev/null
@@ -1,308 +0,0 @@
-From dc7f9783926c0f66e83fcca98161f4d513dccf04 Mon Sep 17 00:00:00 2001
-From: Mike Primm <mike@primmhome.com>
-Date: Sat, 18 Jan 2014 13:54:38 -0600
-Subject: [PATCH] Optimize NextTickList processing
-
-
-diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java
-index 06934a1..d90acfc 100644
---- a/src/main/java/net/minecraft/server/NextTickListEntry.java
-+++ b/src/main/java/net/minecraft/server/NextTickListEntry.java
-@@ -30,7 +30,7 @@ public class NextTickListEntry implements Comparable {
-     }
- 
-     public int hashCode() {
--        return (this.a * 1024 * 1024 + this.c * 1024 + this.b) * 256;
-+        return (this.a * 257) ^ this.b ^ (this.c * 60217); // Spigot - better hash
-     }
- 
-     public NextTickListEntry a(long i) {
-diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
-index 9672508..74a3294 100644
---- a/src/main/java/net/minecraft/server/WorldServer.java
-+++ b/src/main/java/net/minecraft/server/WorldServer.java
-@@ -29,8 +29,8 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-     private final MinecraftServer server;
-     public EntityTracker tracker; // CraftBukkit - private final -> public
-     private final PlayerChunkMap manager;
--    private Set M;
--    private TreeSet N;
-+    private org.bukkit.craftbukkit.util.LongObjectHashMap<Set<NextTickListEntry>> tickEntriesByChunk; // Spigot - switch to something better for chunk-wise access
-+    private TreeSet<NextTickListEntry> tickEntryQueue; // Spigot    public ChunkProviderServer chunkProviderServer;
-     public ChunkProviderServer chunkProviderServer;
-     public boolean savingDisabled;
-     private boolean O;
-@@ -40,7 +40,8 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-     private NoteDataList[] S = new NoteDataList[] { new NoteDataList((EmptyClass2) null), new NoteDataList((EmptyClass2) null)};
-     private int T;
-     private static final StructurePieceTreasure[] U = new StructurePieceTreasure[] { new StructurePieceTreasure(Items.STICK, 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.WOOD), 0, 1, 3, 10), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG), 0, 1, 3, 10), new StructurePieceTreasure(Items.STONE_AXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOOD_AXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.STONE_PICKAXE, 0, 1, 1, 3), new StructurePieceTreasure(Items.WOOD_PICKAXE, 0, 1, 1, 5), new StructurePieceTreasure(Items.APPLE, 0, 2, 3, 5), new StructurePieceTreasure(Items.BREAD, 0, 2, 3, 3), new StructurePieceTreasure(Item.getItemOf(Blocks.LOG2), 0, 1, 3, 10)};
--    private List V = new ArrayList();
-+    private ArrayList<NextTickListEntry> pendingTickEntries = new ArrayList<NextTickListEntry>(); // Spigot
-+    private int nextPendingTickEntry; // Spigot
-     private IntHashMap entitiesById;
- 
-     // CraftBukkit start
-@@ -59,13 +60,15 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-             this.entitiesById = new IntHashMap();
-         }
- 
--        if (this.M == null) {
--            this.M = new HashSet();
-+        // Spigot start
-+        if (this.tickEntriesByChunk == null) {
-+            this.tickEntriesByChunk = new org.bukkit.craftbukkit.util.LongObjectHashMap<Set<NextTickListEntry>>();
-         }
- 
--        if (this.N == null) {
--            this.N = new TreeSet();
-+        if (this.tickEntryQueue == null) {
-+            this.tickEntryQueue = new TreeSet<NextTickListEntry>();
-         }
-+        // Spigot end
- 
-         this.Q = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit
-         this.scoreboard = new ScoreboardServer(minecraftserver);
-@@ -445,9 +448,16 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-     }
- 
-     public boolean a(int i, int j, int k, Block block) {
--        NextTickListEntry nextticklistentry = new NextTickListEntry(i, j, k, block);
--
--        return this.V.contains(nextticklistentry);
-+        // Spigot start
-+        int te_cnt = this.pendingTickEntries.size();
-+        for (int idx = this.nextPendingTickEntry; idx < te_cnt; idx++) {
-+            NextTickListEntry ent = this.pendingTickEntries.get(idx);
-+            if ((ent.a == i) && (ent.b == j) && (ent.c == k) && Block.a(ent.a(), block)) {
-+                return true;
-+            }
-+        }
-+        return false;
-+        // Spigot end        
-     }
- 
-     public void a(int i, int j, int k, Block block, int l) {
-@@ -481,10 +491,9 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-                 nextticklistentry.a(i1);
-             }
- 
--            if (!this.M.contains(nextticklistentry)) {
--                this.M.add(nextticklistentry);
--                this.N.add(nextticklistentry);
--            }
-+            // Spigot start
-+            addNextTickIfNeeded(nextticklistentry);
-+            // Spigot end
-         }
-     }
- 
-@@ -496,10 +505,9 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-             nextticklistentry.a((long) l + this.worldData.getTime());
-         }
- 
--        if (!this.M.contains(nextticklistentry)) {
--            this.M.add(nextticklistentry);
--            this.N.add(nextticklistentry);
--        }
-+        // Spigot start
-+        addNextTickIfNeeded(nextticklistentry);
-+        // Spigot end
-     }
- 
-     public void tickEntities() {
-@@ -519,11 +527,11 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-     }
- 
-     public boolean a(boolean flag) {
--        int i = this.N.size();
--
--        if (i != this.M.size()) {
--            throw new IllegalStateException("TickNextTick list out of synch");
--        } else {
-+        // Spigot start
-+        int i = this.tickEntryQueue.size(); 
-+        this.nextPendingTickEntry = 0;
-+        {
-+        // Spigot end
-             if (i > 1000) {
-                 // CraftBukkit start - If the server has too much to process over time, try to alleviate that
-                 if (i > 20 * 1000) {
-@@ -539,23 +547,24 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-             NextTickListEntry nextticklistentry;
- 
-             for (int j = 0; j < i; ++j) {
--                nextticklistentry = (NextTickListEntry) this.N.first();
-+                nextticklistentry = (NextTickListEntry) this.tickEntryQueue.first(); // Spigot
-                 if (!flag && nextticklistentry.d > this.worldData.getTime()) {
-                     break;
-                 }
- 
--                this.N.remove(nextticklistentry);
--                this.M.remove(nextticklistentry);
--                this.V.add(nextticklistentry);
-+                // Spigot start
-+                this.removeNextTickIfNeeded(nextticklistentry);
-+                this.pendingTickEntries.add(nextticklistentry);
-+                // Spigot end
-             }
- 
-             this.methodProfiler.b();
-             this.methodProfiler.a("ticking");
--            Iterator iterator = this.V.iterator();
--
--            while (iterator.hasNext()) {
--                nextticklistentry = (NextTickListEntry) iterator.next();
--                iterator.remove();
-+            // Spigot start
-+            for (int j = 0, te_cnt = this.pendingTickEntries.size(); j < te_cnt; j++) {
-+                nextticklistentry = pendingTickEntries.get(j);
-+                this.nextPendingTickEntry = j + 1; // treat this as dequeued
-+                // Spigot end
-                 byte b0 = 0;
- 
-                 if (this.b(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) {
-@@ -586,50 +595,18 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-             }
- 
-             this.methodProfiler.b();
--            this.V.clear();
--            return !this.N.isEmpty();
-+            // Spigot start
-+            this.pendingTickEntries.clear();
-+            this.nextPendingTickEntry = 0;
-+            return !this.tickEntryQueue.isEmpty();
-+            // Spigot end
-         }
-     }
- 
-     public List a(Chunk chunk, boolean flag) {
--        ArrayList arraylist = null;
--        ChunkCoordIntPair chunkcoordintpair = chunk.l();
--        int i = (chunkcoordintpair.x << 4) - 2;
--        int j = i + 16 + 2;
--        int k = (chunkcoordintpair.z << 4) - 2;
--        int l = k + 16 + 2;
--
--        for (int i1 = 0; i1 < 2; ++i1) {
--            Iterator iterator;
--
--            if (i1 == 0) {
--                iterator = this.N.iterator();
--            } else {
--                iterator = this.V.iterator();
--                if (!this.V.isEmpty()) {
--                    a.debug("toBeTicked = " + this.V.size());
--                }
--            }
--
--            while (iterator.hasNext()) {
--                NextTickListEntry nextticklistentry = (NextTickListEntry) iterator.next();
--
--                if (nextticklistentry.a >= i && nextticklistentry.a < j && nextticklistentry.c >= k && nextticklistentry.c < l) {
--                    if (flag) {
--                        this.M.remove(nextticklistentry);
--                        iterator.remove();
--                    }
--
--                    if (arraylist == null) {
--                        arraylist = new ArrayList();
--                    }
--
--                    arraylist.add(nextticklistentry);
--                }
--            }
--        }
--
--        return arraylist;
-+        // Spigot start
-+        return this.getNextTickEntriesForChunk(chunk, flag);
-+        // Spigot end
-     }
- 
-     /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed
-@@ -701,13 +678,15 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-             this.entitiesById = new IntHashMap();
-         }
- 
--        if (this.M == null) {
--            this.M = new HashSet();
-+        // Spigot start
-+        if (this.tickEntriesByChunk == null) {
-+            this.tickEntriesByChunk = new org.bukkit.craftbukkit.util.LongObjectHashMap<Set<NextTickListEntry>>();
-         }
- 
--        if (this.N == null) {
--            this.N = new TreeSet();
-+        if (this.tickEntryQueue == null) {
-+            this.tickEntryQueue = new TreeSet<NextTickListEntry>();
-         }
-+        // Spigot end
- 
-         this.b(worldsettings);
-         super.a(worldsettings);
-@@ -1037,4 +1016,62 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
-         return Block.b(getType(x, y, z));
-     }
-     // CraftBukkit end
-+    // Spigot start
-+    private void addNextTickIfNeeded(NextTickListEntry ent) {
-+        long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4);
-+        Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
-+        if (chunkset == null) {
-+            chunkset = new HashSet<NextTickListEntry>();
-+            this.tickEntriesByChunk.put(coord, chunkset);
-+        } else if (chunkset.contains(ent)) {
-+            return;
-+        }
-+        chunkset.add(ent);
-+        this.tickEntryQueue.add(ent);
-+    }
-+    
-+    private void removeNextTickIfNeeded(NextTickListEntry ent) {
-+        long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4);
-+        Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
-+        if (chunkset != null) {
-+            chunkset.remove(ent);
-+            if (chunkset.isEmpty()) {
-+                this.tickEntriesByChunk.remove(coord);
-+            }
-+        }
-+        this.tickEntryQueue.remove(ent);
-+    }
-+    
-+    private List<NextTickListEntry> getNextTickEntriesForChunk(Chunk chunk, boolean remove) {
-+        long coord = LongHash.toLong(chunk.locX, chunk.locZ);
-+        Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
-+        List<NextTickListEntry> list = null;
-+        if (chunkset != null) {
-+            list = new ArrayList<NextTickListEntry>(chunkset);
-+            if (remove) {
-+                this.tickEntriesByChunk.remove(coord);
-+                this.tickEntryQueue.removeAll(list);
-+                chunkset.clear();
-+            }
-+        }
-+        // See if any on list of ticks being processed now
-+        if (this.nextPendingTickEntry < this.pendingTickEntries.size()) {
-+            int xmin = (chunk.locX << 4);
-+            int xmax = xmin + 16;
-+            int zmin = (chunk.locZ << 4);
-+            int zmax = zmin + 16;
-+            int te_cnt = this.pendingTickEntries.size();
-+            for (int i = this.nextPendingTickEntry; i < te_cnt; i++) {
-+                NextTickListEntry ent = this.pendingTickEntries.get(i);
-+                if ((ent.a >= xmin) && (ent.a < xmax) && (ent.c >= zmin) && (ent.c < zmax)) {
-+                    if (list == null) {
-+                        list = new ArrayList<NextTickListEntry>();
-+                    }
-+                    list.add(ent);
-+                }
-+            }
-+        }
-+        return list;
-+    }
-+    // Spigot end 
- }
--- 
-1.8.3.4 (Apple Git-47)
-