diff --git a/CraftBukkit-Patches/0002-mc-dev-imports.patch b/CraftBukkit-Patches/0002-mc-dev-imports.patch index f2e2c84a3a..b573897855 100644 --- a/CraftBukkit-Patches/0002-mc-dev-imports.patch +++ b/CraftBukkit-Patches/0002-mc-dev-imports.patch @@ -1,4 +1,4 @@ -From 889d5efb0e10f4111b4ecda5b2e42e6ee82f641e Mon Sep 17 00:00:00 2001 +From 401298e7004254ee150ea7bcd6263eaf68cd6fc1 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 1 Dec 2013 15:10:48 +1100 Subject: [PATCH] mc-dev imports @@ -1526,343 +1526,6 @@ index 0000000..3eeed3e + return this.data; + } +} -diff --git a/src/main/java/net/minecraft/server/NBTTagCompound.java b/src/main/java/net/minecraft/server/NBTTagCompound.java -new file mode 100644 -index 0000000..5b8842f ---- /dev/null -+++ b/src/main/java/net/minecraft/server/NBTTagCompound.java -@@ -0,0 +1,331 @@ -+package net.minecraft.server; -+ -+import java.io.DataInput; -+import java.io.DataOutput; -+import java.io.IOException; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.Map; -+import java.util.Set; -+import java.util.concurrent.Callable; -+ -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+ -+public class NBTTagCompound extends NBTBase { -+ -+ private static final Logger b = LogManager.getLogger(); -+ private Map map = new HashMap(); -+ -+ public NBTTagCompound() {} -+ -+ void write(DataOutput dataoutput) throws IOException -+ { -+ Iterator iterator = this.map.keySet().iterator(); -+ -+ while (iterator.hasNext()) { -+ String s = (String) iterator.next(); -+ NBTBase nbtbase = (NBTBase) this.map.get(s); -+ -+ a(s, nbtbase, dataoutput); -+ } -+ -+ dataoutput.writeByte(0); -+ } -+ -+ void load(DataInput datainput, int i, NBTReadLimiter nbtreadlimiter) throws IOException -+ { -+ if (i > 512) { -+ throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512"); -+ } else { -+ this.map.clear(); -+ -+ byte b0; -+ -+ while ((b0 = a(datainput, nbtreadlimiter)) != 0) { -+ String s = b(datainput, nbtreadlimiter); -+ -+ nbtreadlimiter.a((long) (16 * s.length())); -+ NBTBase nbtbase = a(b0, s, datainput, i + 1, nbtreadlimiter); -+ -+ this.map.put(s, nbtbase); -+ } -+ } -+ } -+ -+ public Set c() { -+ return this.map.keySet(); -+ } -+ -+ public byte getTypeId() { -+ return (byte) 10; -+ } -+ -+ public void set(String s, NBTBase nbtbase) { -+ this.map.put(s, nbtbase); -+ } -+ -+ public void setByte(String s, byte b0) { -+ this.map.put(s, new NBTTagByte(b0)); -+ } -+ -+ public void setShort(String s, short short1) { -+ this.map.put(s, new NBTTagShort(short1)); -+ } -+ -+ public void setInt(String s, int i) { -+ this.map.put(s, new NBTTagInt(i)); -+ } -+ -+ public void setLong(String s, long i) { -+ this.map.put(s, new NBTTagLong(i)); -+ } -+ -+ public void setFloat(String s, float f) { -+ this.map.put(s, new NBTTagFloat(f)); -+ } -+ -+ public void setDouble(String s, double d0) { -+ this.map.put(s, new NBTTagDouble(d0)); -+ } -+ -+ public void setString(String s, String s1) { -+ this.map.put(s, new NBTTagString(s1)); -+ } -+ -+ public void setByteArray(String s, byte[] abyte) { -+ this.map.put(s, new NBTTagByteArray(abyte)); -+ } -+ -+ public void setIntArray(String s, int[] aint) { -+ this.map.put(s, new NBTTagIntArray(aint)); -+ } -+ -+ public void setBoolean(String s, boolean flag) { -+ this.setByte(s, (byte) (flag ? 1 : 0)); -+ } -+ -+ public NBTBase get(String s) { -+ return (NBTBase) this.map.get(s); -+ } -+ -+ public byte b(String s) { -+ NBTBase nbtbase = (NBTBase) this.map.get(s); -+ -+ return nbtbase != null ? nbtbase.getTypeId() : 0; -+ } -+ -+ public boolean hasKey(String s) { -+ return this.map.containsKey(s); -+ } -+ -+ public boolean hasKeyOfType(String s, int i) { -+ byte b0 = this.b(s); -+ -+ if (b0 == i) { -+ return true; -+ } else if (i != 99) { -+ if (b0 > 0) { -+ b.warn("NBT tag {} was of wrong type; expected {}, found {}", new Object[] { s, getTagName(i), getTagName(b0)}); -+ } -+ -+ return false; -+ } else { -+ return b0 == 1 || b0 == 2 || b0 == 3 || b0 == 4 || b0 == 5 || b0 == 6; -+ } -+ } -+ -+ public byte getByte(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0 : ((NBTNumber) this.map.get(s)).f(); -+ } catch (ClassCastException classcastexception) { -+ return (byte) 0; -+ } -+ } -+ -+ public short getShort(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0 : ((NBTNumber) this.map.get(s)).e(); -+ } catch (ClassCastException classcastexception) { -+ return (short) 0; -+ } -+ } -+ -+ public int getInt(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0 : ((NBTNumber) this.map.get(s)).d(); -+ } catch (ClassCastException classcastexception) { -+ return 0; -+ } -+ } -+ -+ public long getLong(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0L : ((NBTNumber) this.map.get(s)).c(); -+ } catch (ClassCastException classcastexception) { -+ return 0L; -+ } -+ } -+ -+ public float getFloat(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0.0F : ((NBTNumber) this.map.get(s)).h(); -+ } catch (ClassCastException classcastexception) { -+ return 0.0F; -+ } -+ } -+ -+ public double getDouble(String s) { -+ try { -+ return !this.map.containsKey(s) ? 0.0D : ((NBTNumber) this.map.get(s)).g(); -+ } catch (ClassCastException classcastexception) { -+ return 0.0D; -+ } -+ } -+ -+ public String getString(String s) { -+ try { -+ return !this.map.containsKey(s) ? "" : ((NBTBase) this.map.get(s)).a_(); -+ } catch (ClassCastException classcastexception) { -+ return ""; -+ } -+ } -+ -+ public byte[] getByteArray(String s) { -+ try { -+ return !this.map.containsKey(s) ? new byte[0] : ((NBTTagByteArray) this.map.get(s)).c(); -+ } catch (ClassCastException classcastexception) { -+ throw new ReportedException(this.a(s, 7, classcastexception)); -+ } -+ } -+ -+ public int[] getIntArray(String s) { -+ try { -+ return !this.map.containsKey(s) ? new int[0] : ((NBTTagIntArray) this.map.get(s)).c(); -+ } catch (ClassCastException classcastexception) { -+ throw new ReportedException(this.a(s, 11, classcastexception)); -+ } -+ } -+ -+ public NBTTagCompound getCompound(String s) { -+ try { -+ return !this.map.containsKey(s) ? new NBTTagCompound() : (NBTTagCompound) this.map.get(s); -+ } catch (ClassCastException classcastexception) { -+ throw new ReportedException(this.a(s, 10, classcastexception)); -+ } -+ } -+ -+ public NBTTagList getList(String s, int i) { -+ try { -+ if (this.b(s) != 9) { -+ return new NBTTagList(); -+ } else { -+ NBTTagList nbttaglist = (NBTTagList) this.map.get(s); -+ -+ return nbttaglist.size() > 0 && nbttaglist.d() != i ? new NBTTagList() : nbttaglist; -+ } -+ } catch (ClassCastException classcastexception) { -+ throw new ReportedException(this.a(s, 9, classcastexception)); -+ } -+ } -+ -+ public boolean getBoolean(String s) { -+ return this.getByte(s) != 0; -+ } -+ -+ public void remove(String s) { -+ this.map.remove(s); -+ } -+ -+ public String toString() { -+ String s = "{"; -+ -+ String s1; -+ -+ for (Iterator iterator = this.map.keySet().iterator(); iterator.hasNext(); s = s + s1 + ':' + this.map.get(s1) + ',') { -+ s1 = (String) iterator.next(); -+ } -+ -+ return s + "}"; -+ } -+ -+ public boolean isEmpty() { -+ return this.map.isEmpty(); -+ } -+ -+ private CrashReport a(String s, int i, ClassCastException classcastexception) { -+ CrashReport crashreport = CrashReport.a(classcastexception, "Reading NBT data"); -+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Corrupt NBT tag", 1); -+ -+ crashreportsystemdetails.a("Tag type found", (Callable) (new CrashReportCorruptNBTTag(this, s))); -+ crashreportsystemdetails.a("Tag type expected", (Callable) (new CrashReportCorruptNBTTag2(this, i))); -+ crashreportsystemdetails.a("Tag name", s); -+ return crashreport; -+ } -+ -+ public NBTBase clone() { -+ NBTTagCompound nbttagcompound = new NBTTagCompound(); -+ Iterator iterator = this.map.keySet().iterator(); -+ -+ while (iterator.hasNext()) { -+ String s = (String) iterator.next(); -+ -+ nbttagcompound.set(s, ((NBTBase) this.map.get(s)).clone()); -+ } -+ -+ return nbttagcompound; -+ } -+ -+ public boolean equals(Object object) { -+ if (super.equals(object)) { -+ NBTTagCompound nbttagcompound = (NBTTagCompound) object; -+ -+ return this.map.entrySet().equals(nbttagcompound.map.entrySet()); -+ } else { -+ return false; -+ } -+ } -+ -+ public int hashCode() { -+ return super.hashCode() ^ this.map.hashCode(); -+ } -+ -+ private static void a(String s, NBTBase nbtbase, DataOutput dataoutput) throws IOException -+ { -+ dataoutput.writeByte(nbtbase.getTypeId()); -+ if (nbtbase.getTypeId() != 0) { -+ dataoutput.writeUTF(s); -+ nbtbase.write(dataoutput); -+ } -+ } -+ -+ private static byte a(DataInput datainput, NBTReadLimiter nbtreadlimiter) throws IOException -+ { -+ return datainput.readByte(); -+ } -+ -+ private static String b(DataInput datainput, NBTReadLimiter nbtreadlimiter) throws IOException -+ { -+ return datainput.readUTF(); -+ } -+ -+ static NBTBase a(byte b0, String s, DataInput datainput, int i, NBTReadLimiter nbtreadlimiter) { -+ NBTBase nbtbase = NBTBase.createTag(b0); -+ -+ try { -+ nbtbase.load(datainput, i, nbtreadlimiter); -+ return nbtbase; -+ } catch (IOException ioexception) { -+ CrashReport crashreport = CrashReport.a(ioexception, "Loading NBT data"); -+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("NBT Tag"); -+ -+ crashreportsystemdetails.a("Tag name", s); -+ crashreportsystemdetails.a("Tag type", Byte.valueOf(b0)); -+ throw new ReportedException(crashreport); -+ } -+ } -+ -+ static Map a(NBTTagCompound nbttagcompound) { -+ return nbttagcompound.map; -+ } -+} 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..c7cea7f @@ -3548,5 +3211,5 @@ index 0000000..c0db754 + } +} -- -1.8.5.2.msysgit.0 +1.9.1 diff --git a/CraftBukkit-Patches/0137-Log-null-TileEntity-Owner.patch b/CraftBukkit-Patches/0137-Log-null-TileEntity-Owner.patch new file mode 100644 index 0000000000..f56fc8a417 --- /dev/null +++ b/CraftBukkit-Patches/0137-Log-null-TileEntity-Owner.patch @@ -0,0 +1,29 @@ +From 9cac662254b15d2ab59efa9e99a4a988be30e4f6 Mon Sep 17 00:00:00 2001 +From: md_5 +Date: Sun, 20 Apr 2014 11:16:54 +1000 +Subject: [PATCH] Log null TileEntity Owner + + +diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java +index 78e17d7..19d008c 100644 +--- a/src/main/java/net/minecraft/server/TileEntity.java ++++ b/src/main/java/net/minecraft/server/TileEntity.java +@@ -177,7 +177,14 @@ public class TileEntity { + + // CraftBukkit start - add method + public InventoryHolder getOwner() { +- org.bukkit.block.BlockState state = world.getWorld().getBlockAt(x, y, z).getState(); ++ // Spigot start ++ org.bukkit.block.Block block = world.getWorld().getBlockAt(x, y, z); ++ if (block == null) { ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "No block for owner at %s %d %d %d", new Object[]{world.getWorld(), x, y, z}); ++ return null; ++ } ++ // Spigot end ++ org.bukkit.block.BlockState state = block.getState(); + if (state instanceof InventoryHolder) return (InventoryHolder) state; + return null; + } +-- +1.9.1 + diff --git a/CraftBukkit-Patches/0138-Don-t-special-case-invalid-usernames-for-UUIDs.patch b/CraftBukkit-Patches/0138-Don-t-special-case-invalid-usernames-for-UUIDs.patch new file mode 100644 index 0000000000..c6ca430f85 --- /dev/null +++ b/CraftBukkit-Patches/0138-Don-t-special-case-invalid-usernames-for-UUIDs.patch @@ -0,0 +1,34 @@ +From d3c20f6bc5078698723d6f34d68bd3865c7e674c Mon Sep 17 00:00:00 2001 +From: md_5 +Date: Sun, 20 Apr 2014 18:58:00 +1000 +Subject: [PATCH] Don't special case 'invalid' usernames for UUIDs. + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 7c265b5..a996677 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -231,8 +231,6 @@ public final class CraftServer implements Server { + private boolean printSaveWarning; + private CraftIconCache icon; + private boolean overrideAllCommandBlockCommands = false; +- private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$"); +- private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8)); + + private final class BooleanWrapper { + private boolean value = true; +@@ -1321,11 +1319,6 @@ public final class CraftServer implements Server { + Validate.notNull(name, "Name cannot be null"); + com.google.common.base.Preconditions.checkArgument( !org.apache.commons.lang.StringUtils.isBlank( name ), "Name cannot be blank" ); // Spigot + +- // If the name given cannot ever be a valid username give a dummy return, for scoreboard plugins +- if (!validUserPattern.matcher(name).matches()) { +- return new CraftOfflinePlayer(this, new GameProfile(invalidUserUUID, name)); +- } +- + OfflinePlayer result = getPlayerExact(name); + if (result == null) { + // This is potentially blocking :( +-- +1.9.1 + diff --git a/CraftBukkit-Patches/0139-Convert-player-skulls-async.patch b/CraftBukkit-Patches/0139-Convert-player-skulls-async.patch new file mode 100644 index 0000000000..593c98ad81 --- /dev/null +++ b/CraftBukkit-Patches/0139-Convert-player-skulls-async.patch @@ -0,0 +1,96 @@ +From fa5e5bc9da02923761b86b69e08eeabdb3581d20 Mon Sep 17 00:00:00 2001 +From: Thinkofdeath +Date: Sun, 20 Apr 2014 13:18:55 +0100 +Subject: [PATCH] Convert player skulls async + + +diff --git a/src/main/java/net/minecraft/server/TileEntitySkull.java b/src/main/java/net/minecraft/server/TileEntitySkull.java +index 748f00a..a239f04 100644 +--- a/src/main/java/net/minecraft/server/TileEntitySkull.java ++++ b/src/main/java/net/minecraft/server/TileEntitySkull.java +@@ -6,11 +6,25 @@ import net.minecraft.util.com.google.common.collect.Iterables; + import net.minecraft.util.com.mojang.authlib.GameProfile; + import net.minecraft.util.com.mojang.authlib.properties.Property; + ++// Spigot start ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import net.minecraft.util.com.mojang.authlib.Agent; ++// Spigot end ++ + public class TileEntitySkull extends TileEntity { + + private int a; + private int i; + private GameProfile j = null; ++ // Spigot start ++ private static final Executor executor = Executors.newFixedThreadPool(3, ++ new ThreadFactoryBuilder() ++ .setNameFormat("Head Conversion Thread - %1$d") ++ .build() ++ ); ++ // Spigot end + + public TileEntitySkull() {} + +@@ -65,18 +79,45 @@ public class TileEntitySkull extends TileEntity { + private void d() { + if (this.j != null && !UtilColor.b(this.j.getName())) { + if (!this.j.isComplete() || !this.j.getProperties().containsKey("textures")) { +- GameProfile gameprofile = MinecraftServer.getServer().getUserCache().a(this.j.getName()); +- +- if (gameprofile != null) { +- Property property = (Property) Iterables.getFirst(gameprofile.getProperties().get("textures"), null); +- +- if (property == null) { +- gameprofile = MinecraftServer.getServer().av().fillProfileProperties(gameprofile, true); ++ // Spigot start - Handle async ++ final String name = this.j.getName(); ++ executor.execute(new Runnable() { ++ @Override ++ public void run() { ++ GameProfile[] profiles = new GameProfile[1]; ++ GameProfileLookup gameProfileLookup = new GameProfileLookup(profiles); ++ ++ MinecraftServer.getServer().getGameProfileRepository().findProfilesByNames(new String[] { name }, Agent.MINECRAFT, gameProfileLookup); ++ if (!MinecraftServer.getServer().getOnlineMode() && profiles[0] == null) { ++ UUID uuid = EntityHuman.a(new GameProfile(null, name)); ++ GameProfile profile = new GameProfile(uuid, name); ++ ++ gameProfileLookup.onProfileLookupSucceeded(profile); ++ } ++ ++ GameProfile profile = profiles[0]; ++ if (profile != null) { ++ Property property = Iterables.getFirst(profile.getProperties().get("textures"), null); ++ ++ if (property == null) { ++ profile = MinecraftServer.getServer().av().fillProfileProperties(profile, true); ++ } ++ ++ final GameProfile finalProfile = profile; ++ MinecraftServer.getServer().processQueue.add(new Runnable() { ++ @Override ++ public void run() { ++ j = finalProfile; ++ update(); ++ MinecraftServer.getServer().getPlayerList().sendPacketNearby(x, y, z, ++ world.spigotConfig.viewDistance * 16, ++ world.worldData.j()/*Dimension*/, getUpdatePacket()); ++ } ++ }); ++ } + } +- +- this.j = gameprofile; +- this.update(); +- } ++ }); ++ // Spigot end + } + } + } +-- +1.9.1 + diff --git a/CraftBukkit-Patches/0140-Prevent-NoClassDefError-crash-and-notify-on-crash.patch b/CraftBukkit-Patches/0140-Prevent-NoClassDefError-crash-and-notify-on-crash.patch new file mode 100644 index 0000000000..a044e532e1 --- /dev/null +++ b/CraftBukkit-Patches/0140-Prevent-NoClassDefError-crash-and-notify-on-crash.patch @@ -0,0 +1,50 @@ +From 7298686551958fd4fe66772a694ead9a01d956c5 Mon Sep 17 00:00:00 2001 +From: David +Date: Mon, 21 Apr 2014 12:43:08 +0100 +Subject: [PATCH] Prevent NoClassDefError crash and notify on crash + + +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 52ed625..ff65035 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -108,6 +108,8 @@ public abstract class World implements IBlockAccess { + protected float growthOdds = 100; + protected float modifiedOdds = 100; + private final byte chunkTickRadius; ++ public static boolean haveWeSilencedAPhysicsCrash; ++ public static String blockLocation; + + public static long chunkToKey(int x, int z) + { +@@ -531,6 +533,9 @@ public abstract class World implements IBlockAccess { + // CraftBukkit end + + block1.doPhysics(this, i, j, k, block); ++ } catch (StackOverflowError stackoverflowerror) { // Spigot Start ++ haveWeSilencedAPhysicsCrash = true; ++ blockLocation = i + ", " + j + ", " + k; // Spigot End + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.a(throwable, "Exception while updating neighbours"); + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being updated"); +diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java +index de08ad6..94a3d42 100644 +--- a/src/main/java/org/spigotmc/WatchdogThread.java ++++ b/src/main/java/org/spigotmc/WatchdogThread.java +@@ -60,6 +60,13 @@ public class WatchdogThread extends Thread + log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" ); + log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() ); + // ++ if(net.minecraft.server.World.haveWeSilencedAPhysicsCrash) ++ { ++ log.log( Level.SEVERE, "------------------------------" ); ++ log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" ); ++ log.log( Level.SEVERE, "near " + net.minecraft.server.World.blockLocation); ++ } ++ // + log.log( Level.SEVERE, "------------------------------" ); + log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" ); + dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE ), log ); +-- +1.9.1 + diff --git a/CraftBukkit-Patches/0141-Stop-anvils-from-destroying-all-items-in-the-second-.patch b/CraftBukkit-Patches/0141-Stop-anvils-from-destroying-all-items-in-the-second-.patch new file mode 100644 index 0000000000..83a2815144 --- /dev/null +++ b/CraftBukkit-Patches/0141-Stop-anvils-from-destroying-all-items-in-the-second-.patch @@ -0,0 +1,23 @@ +From 7847557ebc8cf54f1f66fbe027ecf2e0ab9a4c74 Mon Sep 17 00:00:00 2001 +From: David +Date: Wed, 23 Apr 2014 01:01:47 +0100 +Subject: [PATCH] Stop anvils from destroying all items in the second slot + +While this may allow multiple stacked items to be repaired at once, it's better than eating all of a user's items. + +diff --git a/src/main/java/net/minecraft/server/ContainerAnvilInventory.java b/src/main/java/net/minecraft/server/ContainerAnvilInventory.java +index 1afa6e7..d975b44 100644 +--- a/src/main/java/net/minecraft/server/ContainerAnvilInventory.java ++++ b/src/main/java/net/minecraft/server/ContainerAnvilInventory.java +@@ -43,7 +43,7 @@ public class ContainerAnvilInventory extends InventorySubcontainer { // CraftBuk + ContainerAnvilInventory(ContainerAnvil containeranvil, String s, boolean flag, int i) { + super(s, flag, i); + this.a = containeranvil; +- this.setMaxStackSize(1); // CraftBukkit ++ // Spigot - Removed this.setMaxStackSize(1); // CraftBukkit + } + + // CraftBukkit start - override inherited maxStack from InventorySubcontainer +-- +1.9.1 +