From 9abbfe5f399d1a42809dd062d225e727d445f1b4 Mon Sep 17 00:00:00 2001 From: md_5 Date: Wed, 16 Jan 2013 11:32:20 +1100 Subject: [PATCH] Re add chunk snc lock and update patch files. --- Bukkit-Patches/0001-Spigot-POM-Changes.patch | 2 +- ...This-commit-has-undergone-basic-test.patch | 29 +- CraftBukkit-Patches/0001-Spigot-Changes.patch | 2856 ----------------- ...de-Plugin-to-version-2.0.-Fixes-BUKK.patch | 6 +- ...286-by-firing-the-inventory-close-ev.patch | 4 +- .../0004-Update-item-merge-logic.patch | 6 +- ...rray-from-mc-dev-for-diff-visibility.patch | 4 +- ...ning-of-NibbleArrays-only-allocate-b.patch | 4 +- .../0007-Return-LOHS-to-full-operation.patch | 4 +- ...te-timeout-time-to-new-default-value.patch | 4 +- .../0009-Per-world-view-distance.patch | 4 +- ...-crop-growth-modifier-formula-issues.patch | 6 +- ...dius-setting-so-that-its-actually-us.patch | 4 +- ...ader-from-mc-dev-for-diff-visibility.patch | 4 +- ...013-Fix-mcRegion-to-Anvil-conversion.patch | 4 +- ...Update-pom-with-Spigot-specific-info.patch | 4 +- ...g-check-to-correctly-resolve-api-ver.patch | 2 +- 17 files changed, 37 insertions(+), 2910 deletions(-) delete mode 100644 CraftBukkit-Patches/0001-Spigot-Changes.patch diff --git a/Bukkit-Patches/0001-Spigot-POM-Changes.patch b/Bukkit-Patches/0001-Spigot-POM-Changes.patch index e28c441b0..f6cbcbed8 100644 --- a/Bukkit-Patches/0001-Spigot-POM-Changes.patch +++ b/Bukkit-Patches/0001-Spigot-POM-Changes.patch @@ -1,4 +1,4 @@ -From 3359843a528eeada4d61ef1d4e7c0c30ad4ca982 Mon Sep 17 00:00:00 2001 +From 73cb91ccc10f12f2fb506a6800aaccc8e419c8e3 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sat, 5 Jan 2013 15:34:12 +1100 Subject: [PATCH] Spigot POM Changes diff --git a/CraftBukkit-Patches/0001-Spigot-Changes.-This-commit-has-undergone-basic-test.patch b/CraftBukkit-Patches/0001-Spigot-Changes.-This-commit-has-undergone-basic-test.patch index a267de42b..d5daa0649 100644 --- a/CraftBukkit-Patches/0001-Spigot-Changes.-This-commit-has-undergone-basic-test.patch +++ b/CraftBukkit-Patches/0001-Spigot-Changes.-This-commit-has-undergone-basic-test.patch @@ -1,7 +1,7 @@ -From 181e716d4433066069208693b6b494d5944cb0b6 Mon Sep 17 00:00:00 2001 +From 6b8688ec60bde099d830d49b86211ac90d295af5 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 30 Dec 2012 23:56:05 -0600 -Subject: [PATCH 01/13] Spigot Changes. This commit has undergone basic testing +Subject: [PATCH 01/15] Spigot Changes. This commit has undergone basic testing and appears to now be safe for careful production usage. Please report any bugs to IRC as soon as you encounter them. Long live Spigot! @@ -28,7 +28,7 @@ Subject: [PATCH 01/13] Spigot Changes. This commit has undergone basic testing src/main/java/net/minecraft/server/PlayerList.java | 10 +- .../java/net/minecraft/server/SpawnerCreature.java | 23 +- .../net/minecraft/server/ThreadLoginVerifier.java | 23 + - src/main/java/net/minecraft/server/World.java | 206 ++++++++- + src/main/java/net/minecraft/server/World.java | 202 ++++++++- .../java/net/minecraft/server/WorldServer.java | 133 ++++-- .../java/org/bukkit/craftbukkit/CraftServer.java | 108 ++++- .../java/org/bukkit/craftbukkit/CraftWorld.java | 76 +++- @@ -47,7 +47,7 @@ Subject: [PATCH 01/13] Spigot Changes. This commit has undergone basic testing .../org/bukkit/craftbukkit/util/TimedThread.java | 37 ++ .../bukkit/craftbukkit/util/WatchdogThread.java | 88 ++++ src/main/resources/configurations/bukkit.yml | 55 +++ - 41 files changed, 1660 insertions(+), 158 deletions(-) + 41 files changed, 1658 insertions(+), 156 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/command/RestartCommand.java create mode 100644 src/main/java/org/bukkit/craftbukkit/command/TicksPerSecondCommand.java create mode 100644 src/main/java/org/bukkit/craftbukkit/util/ExceptionHandler.java @@ -69,7 +69,7 @@ index a689360..4138573 100644 + +/dependency-reduced-pom.xml diff --git a/pom.xml b/pom.xml -index 47e7e52..c923f94 100644 +index 6a75d75..f331d53 100644 --- a/pom.xml +++ b/pom.xml @@ -51,8 +51,8 @@ @@ -716,7 +716,7 @@ index 0686ba0..58d30eb 100644 URL url = new URL("http://session.minecraft.net/game/checkserver.jsp?user=" + URLEncoder.encode(PendingConnection.d(this.pendingConnection), "UTF-8") + "&serverId=" + URLEncoder.encode(s, "UTF-8")); BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(url.openStream())); diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index e2fd0df..c50b814 100644 +index e2fd0df..263cbd3 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -64,7 +64,8 @@ public abstract class World implements IBlockAccess { @@ -786,23 +786,6 @@ index e2fd0df..c50b814 100644 if (worldprovider != null) { this.worldProvider = worldprovider; } else if (this.worldData != null && this.worldData.j() != 0) { -@@ -276,14 +298,14 @@ public abstract class World implements IBlockAccess { - // CraftBukkit start - public Chunk getChunkAt(int i, int j) { - Chunk result = null; -- synchronized (this.chunkLock) { -+ // Spigot start - remove sync - if (this.lastChunkAccessed == null || this.lastXAccessed != i || this.lastZAccessed != j) { - this.lastChunkAccessed = this.chunkProvider.getOrCreateChunk(i, j); - this.lastXAccessed = i; - this.lastZAccessed = j; - } - result = this.lastChunkAccessed; -- } -+ // Spigot end - return result; - } - // CraftBukkit end @@ -903,6 +925,47 @@ public abstract class World implements IBlockAccess { event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason); } else if (entity instanceof EntityItem) { diff --git a/CraftBukkit-Patches/0001-Spigot-Changes.patch b/CraftBukkit-Patches/0001-Spigot-Changes.patch deleted file mode 100644 index b5b115e82..000000000 --- a/CraftBukkit-Patches/0001-Spigot-Changes.patch +++ /dev/null @@ -1,2856 +0,0 @@ -From a4a917da13d09fe9b5046339457f4e811dcb22a9 Mon Sep 17 00:00:00 2001 -From: md_5 -Date: Sun, 30 Dec 2012 23:56:05 -0600 -Subject: [PATCH 01/13] Spigot Changes. This commit has undergone basic - testing and appears to now be safe for careful - production usage. Please report any bugs to IRC as - soon as you encounter them. Long live Spigot! - ---- - .gitignore | 2 + - pom.xml | 11 +- - src/main/java/net/minecraft/server/Block.java | 12 + - .../java/net/minecraft/server/BlockCactus.java | 2 +- - src/main/java/net/minecraft/server/BlockCrops.java | 2 +- - src/main/java/net/minecraft/server/BlockGrass.java | 2 +- - .../java/net/minecraft/server/BlockMushroom.java | 2 +- - src/main/java/net/minecraft/server/BlockMycel.java | 2 +- - src/main/java/net/minecraft/server/BlockReed.java | 2 +- - .../java/net/minecraft/server/BlockSapling.java | 2 +- - src/main/java/net/minecraft/server/BlockStem.java | 2 +- - .../net/minecraft/server/ChunkRegionLoader.java | 35 +- - .../java/net/minecraft/server/ChunkSection.java | 31 +- - src/main/java/net/minecraft/server/EntityItem.java | 3 +- - .../java/net/minecraft/server/EntityPlayer.java | 1 + - .../java/net/minecraft/server/EntitySquid.java | 4 - - .../net/minecraft/server/EntityTrackerEntry.java | 2 + - .../java/net/minecraft/server/MinecraftServer.java | 51 +- - .../net/minecraft/server/PlayerConnection.java | 18 +- - src/main/java/net/minecraft/server/PlayerList.java | 10 +- - .../java/net/minecraft/server/SpawnerCreature.java | 23 +- - .../net/minecraft/server/ThreadLoginVerifier.java | 23 + - src/main/java/net/minecraft/server/World.java | 206 ++++++++- - .../java/net/minecraft/server/WorldServer.java | 133 ++++-- - .../java/org/bukkit/craftbukkit/CraftServer.java | 108 ++++- - .../java/org/bukkit/craftbukkit/CraftWorld.java | 76 ++- - .../craftbukkit/chunkio/ChunkIOProvider.java | 2 +- - .../bukkit/craftbukkit/command/RestartCommand.java | 24 + - .../craftbukkit/command/TicksPerSecondCommand.java | 35 ++ - .../org/bukkit/craftbukkit/entity/CraftPlayer.java | 7 + - .../updater/BukkitDLUpdaterService.java | 26 +- - .../bukkit/craftbukkit/util/ExceptionHandler.java | 31 ++ - .../bukkit/craftbukkit/util/ExceptionReporter.java | 26 ++ - .../java/org/bukkit/craftbukkit/util/FlatMap.java | 34 ++ - .../craftbukkit/util/LightningSimulator.java | 184 ++++++++ - .../org/bukkit/craftbukkit/util/LongHashSet.java | 11 +- - .../bukkit/craftbukkit/util/LongObjectHashMap.java | 5 + - .../java/org/bukkit/craftbukkit/util/Metrics.java | 488 ++++++++++++++++++++ - .../org/bukkit/craftbukkit/util/TimedThread.java | 37 ++ - .../bukkit/craftbukkit/util/WatchdogThread.java | 88 ++++ - src/main/resources/configurations/bukkit.yml | 55 +++ - 41 files changed, 1660 insertions(+), 158 deletions(-) - create mode 100644 src/main/java/org/bukkit/craftbukkit/command/RestartCommand.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/command/TicksPerSecondCommand.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/ExceptionHandler.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/ExceptionReporter.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/FlatMap.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/LightningSimulator.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/Metrics.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/TimedThread.java - create mode 100644 src/main/java/org/bukkit/craftbukkit/util/WatchdogThread.java - -diff --git a/.gitignore b/.gitignore -index a689360..4138573 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -34,3 +34,5 @@ - - /src/main/resources/achievement - /src/main/resources/lang -+ -+/dependency-reduced-pom.xml -diff --git a/pom.xml b/pom.xml -index 6a75d75..f331d53 100644 ---- a/pom.xml -+++ b/pom.xml -@@ -51,8 +51,8 @@ - - - -- org.bukkit -- bukkit -+ org.spigotmc -+ spigot-api - ${project.version} - jar - compile -@@ -145,6 +145,11 @@ - 1.3 - test - -+ -+ net.sf.trove4j -+ trove4j -+ 3.0.2 -+ - - - -@@ -156,7 +161,7 @@ - gitdescribe-maven-plugin - 1.3 - -- git-Bukkit- -+ git-Spigot- - - - -diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java -index f29eace..202bd19 100644 ---- a/src/main/java/net/minecraft/server/Block.java -+++ b/src/main/java/net/minecraft/server/Block.java -@@ -753,4 +753,16 @@ public class Block { - return 0; - } - // CraftBukkit end -+ -+ // Spigot start -+ public static float range(float min, float value, float max) { -+ if (value < min) { -+ return min; -+ } -+ if (value > max) { -+ return max; -+ } -+ return value; -+ } -+ // Spigot end - } -diff --git a/src/main/java/net/minecraft/server/BlockCactus.java b/src/main/java/net/minecraft/server/BlockCactus.java -index dd68020..1cb89fa 100644 ---- a/src/main/java/net/minecraft/server/BlockCactus.java -+++ b/src/main/java/net/minecraft/server/BlockCactus.java -@@ -23,7 +23,7 @@ public class BlockCactus extends Block { - if (l < 3) { - int i1 = world.getData(i, j, k); - -- if (i1 == 15) { -+ if (i1 >= (byte) range(3, (world.growthOdds * 100 / world.getWorld().cactusGrowthModifier * 15 / 100F) + 0.5F, 15)) { // Spigot - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j + 1, k, this.id, 0); // CraftBukkit - world.setData(i, j, k, 0); - } else { -diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java -index a2ce8f9..4d3b448 100644 ---- a/src/main/java/net/minecraft/server/BlockCrops.java -+++ b/src/main/java/net/minecraft/server/BlockCrops.java -@@ -30,7 +30,7 @@ public class BlockCrops extends BlockFlower { - if (l < 7) { - float f = this.l(world, i, j, k); - -- if (random.nextInt((int) (25.0F / f) + 1) == 0) { -+ if (random.nextInt((int) ((world.growthOdds * 100 / world.getWorld().wheatGrowthModifier / 25.0F) / f) + 1) == 0) { // Spigot - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j, k, this.id, ++l); // CraftBukkit - } - } -diff --git a/src/main/java/net/minecraft/server/BlockGrass.java b/src/main/java/net/minecraft/server/BlockGrass.java -index 79a007c..0bc7882 100644 ---- a/src/main/java/net/minecraft/server/BlockGrass.java -+++ b/src/main/java/net/minecraft/server/BlockGrass.java -@@ -37,7 +37,7 @@ public class BlockGrass extends Block { - } - // CraftBukkit end - } else if (world.getLightLevel(i, j + 1, k) >= 9) { -- for (int l = 0; l < 4; ++l) { -+ for (int l = 0; l < Math.max(4, Math.max(20, (int) (4 * 100F / world.growthOdds))); ++l) { // Spigot - int i1 = i + random.nextInt(3) - 1; - int j1 = j + random.nextInt(5) - 3; - int k1 = k + random.nextInt(3) - 1; -diff --git a/src/main/java/net/minecraft/server/BlockMushroom.java b/src/main/java/net/minecraft/server/BlockMushroom.java -index bfc48d4..8fa8302 100644 ---- a/src/main/java/net/minecraft/server/BlockMushroom.java -+++ b/src/main/java/net/minecraft/server/BlockMushroom.java -@@ -23,7 +23,7 @@ public class BlockMushroom extends BlockFlower { - } - - public void b(World world, int i, int j, int k, Random random) { -- if (random.nextInt(25) == 0) { -+ if (random.nextInt((int) (world.growthOdds * 100 / world.getWorld().mushroomGrowthModifier * 25)) == 0) { // Spigot - byte b0 = 4; - int l = 5; - -diff --git a/src/main/java/net/minecraft/server/BlockMycel.java b/src/main/java/net/minecraft/server/BlockMycel.java -index 6dbf49f..afef94d 100644 ---- a/src/main/java/net/minecraft/server/BlockMycel.java -+++ b/src/main/java/net/minecraft/server/BlockMycel.java -@@ -37,7 +37,7 @@ public class BlockMycel extends Block { - } - // CraftBukkit end - } else if (world.getLightLevel(i, j + 1, k) >= 9) { -- for (int l = 0; l < 4; ++l) { -+ for (int l = 0; l < Math.max(4, Math.max(20, (int) (4 * 100F / world.growthOdds))); ++l) { // Spigot - int i1 = i + random.nextInt(3) - 1; - int j1 = j + random.nextInt(5) - 3; - int k1 = k + random.nextInt(3) - 1; -diff --git a/src/main/java/net/minecraft/server/BlockReed.java b/src/main/java/net/minecraft/server/BlockReed.java -index 399050a..66ad508 100644 ---- a/src/main/java/net/minecraft/server/BlockReed.java -+++ b/src/main/java/net/minecraft/server/BlockReed.java -@@ -24,7 +24,7 @@ public class BlockReed extends Block { - if (l < 3) { - int i1 = world.getData(i, j, k); - -- if (i1 == 15) { -+ if (i1 >= (byte) range(3, (world.growthOdds * 100 / world.getWorld().sugarGrowthModifier * 15 / 100F) + 0.5F, 15)) { // Spigot - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j + 1, k, this.id, 0); // CraftBukkit - world.setData(i, j, k, 0); - } else { -diff --git a/src/main/java/net/minecraft/server/BlockSapling.java b/src/main/java/net/minecraft/server/BlockSapling.java -index 9c94399..e8b0f96 100644 ---- a/src/main/java/net/minecraft/server/BlockSapling.java -+++ b/src/main/java/net/minecraft/server/BlockSapling.java -@@ -27,7 +27,7 @@ public class BlockSapling extends BlockFlower { - if (world.getLightLevel(i, j + 1, k) >= 9 && random.nextInt(7) == 0) { - int l = world.getData(i, j, k); - -- if ((l & 8) == 0) { -+ if (world.getLightLevel(i, j + 1, k) >= 9 && (random.nextInt(Math.max(2, (int) ((world.growthOdds * 100 / world.getWorld().treeGrowthModifier * 7 / 100F) + 0.5F))) == 0)) { // Spigot - world.setData(i, j, k, l | 8); - } else { - this.grow(world, i, j, k, random, false, null, null); // CraftBukkit - added bonemeal, player and itemstack -diff --git a/src/main/java/net/minecraft/server/BlockStem.java b/src/main/java/net/minecraft/server/BlockStem.java -index ff1b89f..dfaf45d 100644 ---- a/src/main/java/net/minecraft/server/BlockStem.java -+++ b/src/main/java/net/minecraft/server/BlockStem.java -@@ -27,7 +27,7 @@ public class BlockStem extends BlockFlower { - if (world.getLightLevel(i, j + 1, k) >= 9) { - float f = this.n(world, i, j, k); - -- if (random.nextInt((int) (25.0F / f) + 1) == 0) { -+ if (random.nextInt((int) ((world.growthOdds * 100 / ((this.id == Block.PUMPKIN_STEM.id) ? world.getWorld().pumpkinGrowthModifier : world.getWorld().melonGrowthModifier) / 25.0F) / f) + 1) == 0) { // Spigot - int l = world.getData(i, j, k); - - if (l < 7) { -diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java -index 88c33d0..e5e60a9 100644 ---- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java -+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java -@@ -13,8 +13,7 @@ import java.util.Set; - - public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - -- private List a = new ArrayList(); -- private Set b = new HashSet(); -+ private java.util.LinkedHashMap pendingSaves = new java.util.LinkedHashMap(); // Spigot - private Object c = new Object(); - private final File d; - -@@ -27,15 +26,12 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j); - - synchronized (this.c) { -- if (this.b.contains(chunkcoordintpair)) { -- for (int k = 0; k < this.a.size(); ++k) { -- if (((PendingChunkToSave) this.a.get(k)).a.equals(chunkcoordintpair)) { -- return true; -- } -- } -+ // Spigot start -+ if (pendingSaves.containsKey(chunkcoordintpair)) { -+ return true; - } - } -- -+ // Spigot end - return RegionFileCache.a(this.d, i, j).chunkExists(i & 31, j & 31); - } - // CraftBukkit end -@@ -60,6 +56,12 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - Object object = this.c; - - synchronized (this.c) { -+ // Spigot start -+ PendingChunkToSave pendingchunktosave = pendingSaves.get(chunkcoordintpair); -+ if (pendingchunktosave != null) { -+ nbttagcompound = pendingchunktosave.b; -+ } -+ /* - if (this.b.contains(chunkcoordintpair)) { - for (int k = 0; k < this.a.size(); ++k) { - if (((PendingChunkToSave) this.a.get(k)).a.equals(chunkcoordintpair)) { -@@ -68,6 +70,7 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - } - } - } -+ */// Spigot end - } - - if (nbttagcompound == null) { -@@ -134,6 +137,11 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - Object object = this.c; - - synchronized (this.c) { -+ // Spigot start -+ if (this.pendingSaves.put(chunkcoordintpair, new PendingChunkToSave(chunkcoordintpair, nbttagcompound)) != null) { -+ return; -+ } -+ /* - if (this.b.contains(chunkcoordintpair)) { - for (int i = 0; i < this.a.size(); ++i) { - if (((PendingChunkToSave) this.a.get(i)).a.equals(chunkcoordintpair)) { -@@ -145,6 +153,7 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - - this.a.add(new PendingChunkToSave(chunkcoordintpair, nbttagcompound)); - this.b.add(chunkcoordintpair); -+ */// Spigot end - FileIOThread.a.a(this); - } - } -@@ -154,12 +163,20 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader { - Object object = this.c; - - synchronized (this.c) { -+ // Spigot start -+ if (this.pendingSaves.isEmpty()) { -+ return false; -+ } -+ pendingchunktosave = this.pendingSaves.values().iterator().next(); -+ this.pendingSaves.remove(pendingchunktosave.a); -+ /* - if (this.a.isEmpty()) { - return false; - } - - pendingchunktosave = (PendingChunkToSave) this.a.remove(0); - this.b.remove(pendingchunktosave.a); -+ */// Spigot end - } - - if (pendingchunktosave != null) { -diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java -index 90e0636..051cf6d 100644 ---- a/src/main/java/net/minecraft/server/ChunkSection.java -+++ b/src/main/java/net/minecraft/server/ChunkSection.java -@@ -219,7 +219,7 @@ public class ChunkSection { - } - - public void a(byte[] abyte) { -- this.blockIds = abyte; -+ this.blockIds = validateByteArray(abyte); // Spigot - validate - } - - public void a(NibbleArray nibblearray) { -@@ -236,19 +236,38 @@ public class ChunkSection { - return; - } - // CraftBukkit end -- -- this.extBlockIds = nibblearray; -+ this.extBlockIds = validateNibbleArray(nibblearray); // Spigot - validate - } - - public void b(NibbleArray nibblearray) { -- this.blockData = nibblearray; -+ this.blockData = validateNibbleArray(nibblearray); // Spigot - validate - } - - public void c(NibbleArray nibblearray) { -- this.blockLight = nibblearray; -+ this.blockLight = validateNibbleArray(nibblearray); // Spigot - validate - } - - public void d(NibbleArray nibblearray) { -- this.skyLight = nibblearray; -+ this.skyLight = validateNibbleArray(nibblearray); // Spigot - validate -+ } -+ -+ // Spigot start - validate/correct nibble array -+ private static final NibbleArray validateNibbleArray(NibbleArray na) { -+ if ((na != null) && (na.a.length < 2048)) { -+ NibbleArray newna = new NibbleArray(4096, 4); -+ System.arraycopy(na.a, 0, newna.a, 0, na.a.length); -+ na = newna; -+ } -+ return na; -+ } -+ // Validate/correct byte array -+ private static final byte[] validateByteArray(byte[] ba) { -+ if ((ba != null) && (ba.length < 4096)) { -+ byte[] newba = new byte[4096]; -+ System.arraycopy(ba, 0, newba, 0, ba.length); -+ ba = newba; -+ } -+ return ba; - } -+ // Spigot end - } -diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java -index 1cb66df..aefc806 100644 ---- a/src/main/java/net/minecraft/server/EntityItem.java -+++ b/src/main/java/net/minecraft/server/EntityItem.java -@@ -61,6 +61,7 @@ public class EntityItem extends Entity { - this.lastTick = currentTick; - // CraftBukkit end - -+ if (lastTick % 2 == 0) { // Spigot - this.lastX = this.locX; - this.lastY = this.locY; - this.lastZ = this.locZ; -@@ -99,7 +100,7 @@ public class EntityItem extends Entity { - if (this.onGround) { - this.motY *= -0.5D; - } -- -+ } // Spigot - ++this.age; - if (!this.world.isStatic && this.age >= 6000) { - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java -index 86e6ea9..76135a2 100644 ---- a/src/main/java/net/minecraft/server/EntityPlayer.java -+++ b/src/main/java/net/minecraft/server/EntityPlayer.java -@@ -48,6 +48,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - public int newTotalExp = 0; - public boolean keepLevel = false; - // CraftBukkit end -+ public java.util.Set sentFrames = new java.util.HashSet(); // Spigot - - public EntityPlayer(MinecraftServer minecraftserver, World world, String s, PlayerInteractManager playerinteractmanager) { - super(world); -diff --git a/src/main/java/net/minecraft/server/EntitySquid.java b/src/main/java/net/minecraft/server/EntitySquid.java -index 961d83a..188d477 100644 ---- a/src/main/java/net/minecraft/server/EntitySquid.java -+++ b/src/main/java/net/minecraft/server/EntitySquid.java -@@ -63,10 +63,6 @@ public class EntitySquid extends EntityWaterAnimal { - // CraftBukkit end - } - -- public boolean H() { -- return this.world.a(this.boundingBox.grow(0.0D, -0.6000000238418579D, 0.0D), Material.WATER, (Entity) this); -- } -- - public void c() { - super.c(); - this.e = this.d; -diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -index a026c4c..cb91e30 100644 ---- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java -+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -@@ -84,6 +84,7 @@ public class EntityTrackerEntry { - while (j0.hasNext()) { - EntityHuman j1 = (EntityHuman) j0.next(); - EntityPlayer j2 = (EntityPlayer) j1; -+ if (j2.sentFrames.contains(i4.uniqueId)) continue; // Spigot - - i7.a(j2, i5); - if (j2.playerConnection.lowPriorityCount() <= 5) { -@@ -91,6 +92,7 @@ public class EntityTrackerEntry { - - if (j3 != null) { - j2.playerConnection.sendPacket(j3); -+ j2.sentFrames.add(i4.uniqueId); // Spigot - } - } - } -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2f20038..b0baa85 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -86,6 +86,11 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo - public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); - public int autosavePeriod; - // CraftBukkit end -+ // Spigot start -+ private static final int TPS = 20; -+ private static final int TICK_TIME = 1000000000 / TPS; -+ public static double currentTPS = 0; -+ // Spigot end - - public MinecraftServer(OptionSet options) { // CraftBukkit - signature file -> OptionSet - l = this; -@@ -397,39 +402,20 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo - public void run() { - try { - if (this.init()) { -- long i = System.currentTimeMillis(); -- -- for (long j = 0L; this.isRunning; this.Q = true) { -- long k = System.currentTimeMillis(); -- long l = k - i; -- -- if (l > 2000L && i - this.R >= 15000L) { -- if (this.server.getWarnOnOverload()) // CraftBukkit - Added option to suppress warning messages -- log.warning("Can\'t keep up! Did the system time change, or is the server overloaded?"); -- l = 2000L; -- this.R = i; -+ // Spigot start -+ for (long lastTick = 0L; this.isRunning; this.Q = true) { -+ long curTime = System.nanoTime(); -+ long wait = TICK_TIME - (curTime - lastTick); -+ if (wait > 0) { -+ Thread.sleep(wait / 1000000); -+ continue; - } -- -- if (l < 0L) { -- log.warning("Time ran backwards! Did the system time change?"); -- l = 0L; -- } -- -- j += l; -- i = k; -- if (this.worlds.get(0).everyoneDeeplySleeping()) { // CraftBukkit -- this.q(); -- j = 0L; -- } else { -- while (j > 50L) { -- MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit -- j -= 50L; -- this.q(); -- } -- } -- -- Thread.sleep(1L); -+ currentTPS = (currentTPS * 0.95) + (1E9 / (curTime - lastTick) * 0.05); -+ lastTick = curTime; -+ MinecraftServer.currentTick++; -+ this.q(); - } -+ // Spigot end - } else { - this.a((CrashReport) null); - } -@@ -454,6 +440,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo - - this.a(crashreport); - } finally { -+ org.bukkit.craftbukkit.util.WatchdogThread.stopping(); // Spigot - try { - this.stop(); - this.isStopped = true; -@@ -605,6 +592,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo - } - - this.methodProfiler.b(); -+ org.bukkit.craftbukkit.util.WatchdogThread.tick(); // Spigot - } - - public boolean getAllowNether() { -@@ -708,6 +696,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo - dedicatedserver.an(); - } - */ -+ dedicatedserver.primaryThread.setUncaughtExceptionHandler(new org.bukkit.craftbukkit.util.ExceptionHandler()); // Spigot - - dedicatedserver.primaryThread.start(); - // Runtime.getRuntime().addShutdownHook(new ThreadShutdown(dedicatedserver)); -diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java -index dd29094..4a213bc 100644 ---- a/src/main/java/net/minecraft/server/PlayerConnection.java -+++ b/src/main/java/net/minecraft/server/PlayerConnection.java -@@ -851,8 +851,19 @@ public class PlayerConnection extends Connection { - - this.chat(s, packet3chat.a_()); - -+ // Spigot start -+ boolean isCounted = true; -+ if (server.spamGuardExclusions != null) { -+ for (String excluded : server.spamGuardExclusions) { -+ if (s.startsWith(excluded)) { -+ isCounted = false; -+ break; -+ } -+ } -+ } - // This section stays because it is only applicable to packets -- if (chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.name)) { // CraftBukkit use thread-safe spam -+ if (isCounted && chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.name)) { // CraftBukkit use thread-safe spam -+ // Spigot end - // CraftBukkit start - if (packet3chat.a_()) { - Waitable waitable = new Waitable() { -@@ -975,7 +986,7 @@ public class PlayerConnection extends Connection { - } - - try { -- logger.info(event.getPlayer().getName() + " issued server command: " + event.getMessage()); // CraftBukkit -+ if (server.logCommands) logger.info(event.getPlayer().getName() + " issued server command: " + event.getMessage()); // Spigot - if (this.server.dispatchCommand(event.getPlayer(), event.getMessage().substring(1))) { - return; - } -@@ -1371,8 +1382,9 @@ public class PlayerConnection extends Connection { - flag = false; - } else { - for (i = 0; i < packet130updatesign.lines[j].length(); ++i) { -- if (SharedConstants.allowedCharacters.indexOf(packet130updatesign.lines[j].charAt(i)) < 0) { -+ if (!SharedConstants.isAllowedChatCharacter(packet130updatesign.lines[j].charAt(i))) { - flag = false; -+ break; - } - } - } -diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java -index c43a6ed..ee241af 100644 ---- a/src/main/java/net/minecraft/server/PlayerList.java -+++ b/src/main/java/net/minecraft/server/PlayerList.java -@@ -250,7 +250,7 @@ public abstract class PlayerList { - - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, s1); - } else if (!this.isWhitelisted(s)) { -- event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, "You are not white-listed on this server!"); -+ event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, cserver.whitelistMessage); // Spigot - } else { - String s2 = socketaddress.toString(); - -@@ -822,7 +822,13 @@ public abstract class PlayerList { - - public void r() { - while (!this.players.isEmpty()) { -- ((EntityPlayer) this.players.get(0)).playerConnection.disconnect(this.server.server.getShutdownMessage()); // CraftBukkit - add custom shutdown message -+ // Spigot start -+ EntityPlayer p = (EntityPlayer) this.players.get(0); -+ p.playerConnection.disconnect(this.server.server.getShutdownMessage()); -+ if ((!this.players.isEmpty()) && (this.players.get(0) == p)) { -+ this.players.remove(0); // Prevent shutdown hang if already disconnected -+ } -+ // Spigot end - } - } - -diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java -index a1ed84c..576cbd3 100644 ---- a/src/main/java/net/minecraft/server/SpawnerCreature.java -+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java -@@ -16,6 +16,7 @@ public final class SpawnerCreature { - - private static LongObjectHashMap b = new LongObjectHashMap(); // CraftBukkit - HashMap -> LongObjectHashMap - protected static final Class[] a = new Class[] { EntitySpider.class, EntityZombie.class, EntitySkeleton.class}; -+ private static byte spawnRadius = 0; // Spigot - - protected static ChunkPosition getRandomPosition(World world, int i, int j) { - Chunk chunk = world.getChunkAt(i, j); -@@ -34,13 +35,21 @@ public final class SpawnerCreature { - - int i; - int j; -+ // Spigot start - limit radius to spawn distance (chunks aren't loaded) -+ if (spawnRadius == 0) { -+ spawnRadius = (byte) worldserver.getServer().getViewDistance(); -+ if (spawnRadius > 8) { -+ spawnRadius = 8; -+ } -+ } -+ // Spigot end - - for (i = 0; i < worldserver.players.size(); ++i) { - EntityHuman entityhuman = (EntityHuman) worldserver.players.get(i); - int k = MathHelper.floor(entityhuman.locX / 16.0D); - - j = MathHelper.floor(entityhuman.locZ / 16.0D); -- byte b0 = 8; -+ byte b0 = spawnRadius; // Spigot - replace 8 with view distance constrained value - - for (int l = -b0; l <= b0; ++l) { - for (int i1 = -b0; i1 <= b0; ++i1) { -@@ -88,13 +97,15 @@ public final class SpawnerCreature { - if (limit == 0) { - return 0; - } -+ int mobcnt = 0; - // CraftBukkit end - -- if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2) && worldserver.a(enumcreaturetype.a()) <= limit * b.size() / 256) { // CraftBukkit - use per-world limits -+ if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2) && (mobcnt = worldserver.a(enumcreaturetype.a())) <= limit * b.size() / 256) { // CraftBukkit - use per-world limits - Iterator iterator = b.keySet().iterator(); - -+ int moblimit = (limit * b.size() / 256) - mobcnt + 1; // CraftBukkit - up to 1 more than limit - label110: -- while (iterator.hasNext()) { -+ while (iterator.hasNext() && (moblimit > 0)) { // Spigot - while more allowed - // CraftBukkit start - long key = ((Long) iterator.next()).longValue(); - -@@ -157,6 +168,12 @@ public final class SpawnerCreature { - // CraftBukkit - added a reason for spawning this creature - worldserver.addEntity(entityliving, SpawnReason.NATURAL); - a(entityliving, worldserver, f, f1, f2); -+ // Spigot start -+ moblimit--; -+ if (moblimit <= 0) { // If we're past limit, stop spawn -+ continue label110; -+ } -+ // Spigot end - if (j2 >= entityliving.bv()) { - continue label110; - } -diff --git a/src/main/java/net/minecraft/server/ThreadLoginVerifier.java b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java -index 0686ba0..58d30eb 100644 ---- a/src/main/java/net/minecraft/server/ThreadLoginVerifier.java -+++ b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java -@@ -28,6 +28,29 @@ class ThreadLoginVerifier extends Thread { - - public void run() { - try { -+ // Spigot start -+ if (((CraftServer) org.bukkit.Bukkit.getServer()).ipFilter) { -+ try { -+ String ip = this.pendingConnection.getSocket().getInetAddress().getHostAddress(); -+ String[] split = ip.split("\\."); -+ StringBuilder lookup = new StringBuilder(); -+ for (int i = split.length - 1; i >= 0; i--) { -+ lookup.append(split[i]); -+ lookup.append("."); -+ } -+ if (!ip.contains("127.0.0.1")) { -+ lookup.append("xbl.spamhaus.org."); -+ if (java.net.InetAddress.getByName(lookup.toString()) != null) { -+ this.pendingConnection.networkManager.queue(new Packet255KickDisconnect("Your IP address (" + ip + ") is flagged as unsafe by spamhaus.org/xbl")); -+ this.pendingConnection.networkManager.d(); -+ this.pendingConnection.c = true; -+ return; -+ } -+ } -+ } catch (Exception ex) { -+ } -+ } -+ // Spigot end - String s = (new BigInteger(MinecraftEncryption.a(PendingConnection.a(this.pendingConnection), PendingConnection.b(this.pendingConnection).F().getPublic(), PendingConnection.c(this.pendingConnection)))).toString(16); - URL url = new URL("http://session.minecraft.net/game/checkserver.jsp?user=" + URLEncoder.encode(PendingConnection.d(this.pendingConnection), "UTF-8") + "&serverId=" + URLEncoder.encode(s, "UTF-8")); - BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(url.openStream())); -diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index e2fd0df..c50b814 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -64,7 +64,8 @@ public abstract class World implements IBlockAccess { - // CraftBukkit start - public, longhashset - public boolean allowMonsters = true; - public boolean allowAnimals = true; -- protected LongHashSet chunkTickList = new LongHashSet(); -+ protected gnu.trove.map.hash.TLongShortHashMap chunkTickList; // Spigot -+ private org.bukkit.craftbukkit.util.LightningSimulator lightningSim = new org.bukkit.craftbukkit.util.LightningSimulator(this); // Spigot - public long ticksPerAnimalSpawns; - public long ticksPerMonsterSpawns; - // CraftBukkit end -@@ -72,7 +73,20 @@ public abstract class World implements IBlockAccess { - int[] H; - private List O; - public boolean isStatic; -+ // Spigot start - -+ public static final long chunkToKey(int x, int z) { -+ long k = ((((long)x) & 0xFFFF0000L) << 16) | ((((long)x) & 0x0000FFFFL) << 0); -+ k |= ((((long)z) & 0xFFFF0000L) << 32) | ((((long)z) & 0x0000FFFFL) << 16); -+ return k; -+ } -+ public static final int keyToX(long k) { -+ return (int)(((k >> 16) & 0xFFFF0000) | (k & 0x0000FFFF)); -+ } -+ public static final int keyToZ(long k) { -+ return (int)(((k >> 32) & 0xFFFF0000L) | ((k >> 16) & 0x0000FFFF)); -+ } -+ // Spigot end - public BiomeBase getBiome(int i, int j) { - if (this.isLoaded(i, 0, j)) { - Chunk chunk = this.getChunkAtWorldCoords(i, j); -@@ -98,6 +112,7 @@ public abstract class World implements IBlockAccess { - int lastXAccessed = Integer.MIN_VALUE; - int lastZAccessed = Integer.MIN_VALUE; - final Object chunkLock = new Object(); -+ private byte chunkTickRadius; - - public CraftWorld getWorld() { - return this.world; -@@ -110,11 +125,18 @@ public abstract class World implements IBlockAccess { - // Changed signature - public World(IDataManager idatamanager, String s, WorldSettings worldsettings, WorldProvider worldprovider, MethodProfiler methodprofiler, ChunkGenerator gen, org.bukkit.World.Environment env) { - this.generator = gen; -+ this.worldData = idatamanager.getWorldData(); // Spigot - this.world = new CraftWorld((WorldServer) this, gen, env); - this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit - this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns(); // CraftBukkit -+ this.chunkTickRadius = (byte)((this.getServer().getViewDistance() < 7) ? this.getServer().getViewDistance() : 7); // CraftBukkit - don't tick chunks we don't load for player - // CraftBukkit end - -+ // Spigot start -+ this.chunkTickList = new gnu.trove.map.hash.TLongShortHashMap(getWorld().growthPerTick * 5, 0.7f, Long.MIN_VALUE, Short.MIN_VALUE); -+ chunkTickList.setAutoCompactionFactor(0.0F); -+ // Spigot end -+ - this.N = this.random.nextInt(12000); - this.H = new int['\u8000']; - this.O = new UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList -@@ -122,7 +144,7 @@ public abstract class World implements IBlockAccess { - this.dataManager = idatamanager; - this.methodProfiler = methodprofiler; - this.worldMaps = new WorldMapCollection(idatamanager); -- this.worldData = idatamanager.getWorldData(); -+ // this.worldData = idatamanager.getWorldData(); Moved up - if (worldprovider != null) { - this.worldProvider = worldprovider; - } else if (this.worldData != null && this.worldData.j() != 0) { -@@ -276,14 +298,14 @@ public abstract class World implements IBlockAccess { - // CraftBukkit start - public Chunk getChunkAt(int i, int j) { - Chunk result = null; -- synchronized (this.chunkLock) { -+ // Spigot start - remove sync - if (this.lastChunkAccessed == null || this.lastXAccessed != i || this.lastZAccessed != j) { - this.lastChunkAccessed = this.chunkProvider.getOrCreateChunk(i, j); - this.lastXAccessed = i; - this.lastZAccessed = j; - } - result = this.lastChunkAccessed; -- } -+ // Spigot end - return result; - } - // CraftBukkit end -@@ -903,6 +925,47 @@ public abstract class World implements IBlockAccess { - event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason); - } else if (entity instanceof EntityItem) { - event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity); -+ // Spigot start -+ ItemStack item = ((EntityItem) entity).getItemStack(); -+ int maxSize = item.getMaxStackSize(); -+ if (item.count < maxSize) { -+ double radius = this.getWorld().itemMergeRadius; -+ if (radius > 0) { -+ List entities = this.getEntities(entity, entity.boundingBox.grow(radius, radius, radius)); -+ for (Entity e : entities) { -+ if (e instanceof EntityItem) { -+ EntityItem loopItem = (EntityItem) e; -+ ItemStack loopStack = loopItem.getItemStack(); -+ if (!loopItem.dead && loopStack.id == item.id && loopStack.getData() == item.getData()) { -+ if (loopStack.tag == null || item.tag == null || !loopStack.tag.equals(item.tag)) { -+ int toAdd = Math.min(loopStack.count, maxSize - item.count); -+ item.count += toAdd; -+ loopStack.count -= toAdd; -+ if (loopStack.count <= 0) { -+ loopItem.die(); -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } else if (entity instanceof EntityExperienceOrb) { -+ EntityExperienceOrb xp = (EntityExperienceOrb) entity; -+ double radius = this.getWorld().expMergeRadius; -+ if (radius > 0) { -+ List entities = this.getEntities(entity, entity.boundingBox.grow(radius, radius, radius)); -+ for (Entity e : entities) { -+ if (e instanceof EntityExperienceOrb) { -+ EntityExperienceOrb loopItem = (EntityExperienceOrb) e; -+ if (!loopItem.dead) { -+ xp.value += loopItem.value; -+ loopItem.die(); -+ } -+ } -+ } -+ } -+ // Spigot end - } else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Projectile) { - // Not all projectiles extend EntityProjectile, so check for Bukkit interface instead - event = CraftEventFactory.callProjectileLaunchEvent(entity); -@@ -995,6 +1058,39 @@ public abstract class World implements IBlockAccess { - int i1 = MathHelper.floor(axisalignedbb.c); - int j1 = MathHelper.floor(axisalignedbb.f + 1.0D); - -+ // Spigot start -+ int ystart = ((k - 1) < 0) ? 0 : (k - 1); -+ for (int chunkx = (i >> 4); chunkx <= ((j - 1) >> 4); chunkx++) { -+ int cx = chunkx << 4; -+ for (int chunkz = (i1 >> 4); chunkz <= ((j1 - 1) >> 4); chunkz++) { -+ if (!this.isChunkLoaded(chunkx, chunkz)) { -+ continue; -+ } -+ int cz = chunkz << 4; -+ Chunk chunk = this.getChunkAt(chunkx, chunkz); -+ // Compute ranges within chunk -+ int xstart = (i < cx)?cx:i; -+ int xend = (j < (cx+16))?j:(cx+16); -+ int zstart = (i1 < cz)?cz:i1; -+ int zend = (j1 < (cz+16))?j1:(cz+16); -+ // Loop through blocks within chunk -+ for (int x = xstart; x < xend; x++) { -+ for (int z = zstart; z < zend; z++) { -+ for (int y = ystart; y < l; y++) { -+ int blkid = chunk.getTypeId(x - cx, y, z - cz); -+ if (blkid > 0) { -+ Block block = Block.byId[blkid]; -+ -+ if (block != null) { -+ block.a(this, x, y, z, axisalignedbb, this.L, entity); -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ /* - for (int k1 = i; k1 < j; ++k1) { - for (int l1 = i1; l1 < j1; ++l1) { - if (this.isLoaded(k1, 64, l1)) { -@@ -1008,6 +1104,7 @@ public abstract class World implements IBlockAccess { - } - } - } -+ */// Spigot end - - double d0 = 0.25D; - List list = this.getEntities(entity, axisalignedbb.grow(d0, d0, d0)); -@@ -1315,7 +1412,37 @@ public abstract class World implements IBlockAccess { - this.entityJoinedWorld(entity, true); - } - -- public void entityJoinedWorld(Entity entity, boolean flag) { -+ // Spigot start -+ public int tickEntityExceptions = 0; -+ public void entityJoinedWorld(final Entity entity, final boolean flag) { -+ if (entity == null) { -+ return; -+ } -+ try { -+ tickEntity(entity, flag); -+ } catch (Exception e) { -+ try { -+ tickEntityExceptions++; -+ List report = new ArrayList(); -+ report.add("Spigot has detected an unexpected exception while handling"); -+ if (!(entity instanceof EntityPlayer)) { -+ report.add("entity " + entity.toString() + " (id: " + entity.id + ")"); -+ report.add("Spigot will kill the entity from the game instead of crashing your server."); -+ entity.die(); -+ } else { -+ report.add("player '" + ((EntityPlayer) entity).name + "'. They will be kicked instead of crashing your server."); -+ ((EntityPlayer) entity).getBukkitEntity().kickPlayer("The server experienced and error and was forced to kick you. Please re-login."); -+ } -+ org.bukkit.craftbukkit.util.ExceptionReporter.handle(e, report.toArray(new String[0])); -+ } catch (Throwable t) { -+ org.bukkit.craftbukkit.util.ExceptionReporter.handle(t, "Spigot has detected an unexpected exception while attempting to handle an exception (yes you read that correctly)."); -+ Bukkit.shutdown(); -+ } -+ } -+ } -+ -+ public void tickEntity(Entity entity, boolean flag) { -+ // Spigot end - int i = MathHelper.floor(entity.locX); - int j = MathHelper.floor(entity.locZ); - byte b0 = 32; -@@ -1815,6 +1942,7 @@ public abstract class World implements IBlockAccess { - - protected void n() { - if (!this.worldProvider.f) { -+ lightningSim.onTick(); // Spigot - int i = this.worldData.getThunderDuration(); - - if (i <= 0) { -@@ -1896,6 +2024,11 @@ public abstract class World implements IBlockAccess { - this.worldData.setWeatherDuration(1); - } - -+ // Spigot start -+ public int aggregateTicks = 1; -+ protected float modifiedOdds = 100F; -+ public float growthOdds = 100F; -+ - protected void z() { - // this.chunkTickList.clear(); // CraftBukkit - removed - this.methodProfiler.a("buildList"); -@@ -1905,25 +2038,42 @@ public abstract class World implements IBlockAccess { - int j; - int k; - -+ final int optimalChunks = this.getWorld().growthPerTick; -+ -+ if (optimalChunks <= 0) return; -+ if (players.size() == 0) return; -+ //Keep chunks with growth inside of the optimal chunk range -+ int chunksPerPlayer = Math.min(200, Math.max(1, (int)(((optimalChunks - players.size()) / (double)players.size()) + 0.5))); -+ int randRange = 3 + chunksPerPlayer / 30; -+ if(randRange > chunkTickRadius) { // Limit to normal tick radius - including view distance -+ randRange = chunkTickRadius; -+ } -+ //odds of growth happening vs growth happening in vanilla -+ final float modifiedOdds = Math.max(35, Math.min(100, ((chunksPerPlayer + 1) * 100F) / 15F)); -+ this.modifiedOdds = modifiedOdds; -+ this.growthOdds = modifiedOdds; -+ - for (i = 0; i < this.players.size(); ++i) { - entityhuman = (EntityHuman) this.players.get(i); -- j = MathHelper.floor(entityhuman.locX / 16.0D); -- k = MathHelper.floor(entityhuman.locZ / 16.0D); -- byte b0 = 7; -- -- for (int l = -b0; l <= b0; ++l) { -- for (int i1 = -b0; i1 <= b0; ++i1) { -- // CraftBukkit start - don't tick chunks queued for unload -- ChunkProviderServer chunkProviderServer = ((WorldServer) entityhuman.world).chunkProviderServer; -- if (chunkProviderServer.unloadQueue.contains(l + j, i1 + k)) { -- continue; -- } -- // CraftBukkit end -- -- this.chunkTickList.add(org.bukkit.craftbukkit.util.LongHash.toLong(l + j, i1 + k)); // CraftBukkit -+ int chunkX = MathHelper.floor(entityhuman.locX / 16.0D); -+ int chunkZ = MathHelper.floor(entityhuman.locZ / 16.0D); -+ -+ //Always update the chunk the player is on -+ long key = chunkToKey(chunkX, chunkZ); -+ int existingPlayers = Math.max(0, chunkTickList.get(key)); //filter out -1's -+ chunkTickList.put(key, (short) (existingPlayers + 1)); -+ -+ //Check and see if we update the chunks surrounding the player this tick -+ for (int chunk = 0; chunk < chunksPerPlayer; chunk++) { -+ int dx = (random.nextBoolean() ? 1 : -1) * random.nextInt(randRange); -+ int dz = (random.nextBoolean() ? 1 : -1) * random.nextInt(randRange); -+ long hash = chunkToKey(dx + chunkX, dz + chunkZ); -+ if (!chunkTickList.contains(hash) && this.isChunkLoaded(dx + chunkX, dz + chunkZ)) { -+ chunkTickList.put(hash, (short) -1); //no players - } - } - } -+ // Spigot End - - this.methodProfiler.b(); - if (this.N > 0) { -@@ -1931,7 +2081,7 @@ public abstract class World implements IBlockAccess { - } - - this.methodProfiler.a("playerCheckLight"); -- if (!this.players.isEmpty()) { -+ if (!this.players.isEmpty() && this.getWorld().randomLightingUpdates) { // Spigot - i = this.random.nextInt(this.players.size()); - entityhuman = (EntityHuman) this.players.get(i); - j = MathHelper.floor(entityhuman.locX) + this.random.nextInt(11) - 5; -@@ -1970,9 +2120,16 @@ public abstract class World implements IBlockAccess { - chunk.o(); - } - -+ // Spigot start - protected void g() { -+ try { - this.z(); - } -+ catch (Exception e) { -+ org.bukkit.craftbukkit.util.ExceptionReporter.handle(e, "Spigot has detected an unexpected exception while ticking chunks"); -+ } -+ } -+ // Spigot end - - public boolean w(int i, int j, int k) { - return this.c(i, j, k, false); -@@ -2310,7 +2467,10 @@ public abstract class World implements IBlockAccess { - } - - public List getEntities(Entity entity, AxisAlignedBB axisalignedbb) { -- this.O.clear(); -+ // Spigot start -+ // this.O.clear(); -+ ArrayList entities = new ArrayList(); -+ // Spigot end - int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D); - int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D); - int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D); -@@ -2319,12 +2479,12 @@ public abstract class World implements IBlockAccess { - for (int i1 = i; i1 <= j; ++i1) { - for (int j1 = k; j1 <= l; ++j1) { - if (this.isChunkLoaded(i1, j1)) { -- this.getChunkAt(i1, j1).a(entity, axisalignedbb, this.O); -+ this.getChunkAt(i1, j1).a(entity, axisalignedbb, entities); // Spigot - } - } - } - -- return this.O; -+ return entities; // Spigot - } - - public List a(Class oclass, AxisAlignedBB axisalignedbb) { -diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index b426d5d..6de6b12 100644 ---- a/src/main/java/net/minecraft/server/WorldServer.java -+++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -1,5 +1,7 @@ - package net.minecraft.server; - -+import gnu.trove.iterator.TLongShortIterator; -+ - import java.util.ArrayList; - import java.util.Collection; - import java.util.HashSet; -@@ -12,6 +14,7 @@ import java.util.TreeSet; - // CraftBukkit start - import org.bukkit.block.BlockState; - import org.bukkit.craftbukkit.util.LongHash; -+import org.bukkit.craftbukkit.util.LongObjectHashMap; - - import org.bukkit.event.block.BlockFormEvent; - import org.bukkit.event.weather.LightningStrikeEvent; -@@ -24,7 +27,7 @@ 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 L; -+ private LongObjectHashMap> L; // CraftBukkit - change to something chunk friendly - private TreeSet M; - public ChunkProviderServer chunkProviderServer; - public boolean savingDisabled; -@@ -52,7 +55,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - } - - if (this.L == null) { -- this.L = new HashSet(); -+ this.L = new LongObjectHashMap>(); // CraftBukkit - } - - if (this.M == null) { -@@ -157,6 +160,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - SpawnerCreature.spawnEntities(this, this.allowMonsters && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.allowAnimals && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L), this.worldData.getTime() % 400L == 0L); - } - // CraftBukkit end -+ this.getWorld().processChunkGC(); // Spigot - this.methodProfiler.c("chunkSource"); - this.chunkProvider.unloadChunks(); - int j = this.a(1.0F); -@@ -267,15 +271,31 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - } - - protected void g() { -+ // Spigot start -+ this.aggregateTicks--; -+ if (this.aggregateTicks != 0) return; -+ aggregateTicks = this.getWorld().aggregateTicks; -+ // Spigot end - super.g(); - int i = 0; - int j = 0; - // CraftBukkit start -- // Iterator iterator = this.chunkTickList.iterator(); -+ // Iterator iterator = this.chunkTickList.iterator(); // CraftBukkit - -- for (long chunkCoord : this.chunkTickList.popAll()) { -- int chunkX = LongHash.msw(chunkCoord); -- int chunkZ = LongHash.lsw(chunkCoord); -+ // CraftBukkit start -+ // Spigot start -+ for (TLongShortIterator iter = chunkTickList.iterator(); iter.hasNext();) { -+ iter.advance(); -+ long chunkCoord = iter.key(); -+ int chunkX = World.keyToX(chunkCoord); -+ int chunkZ = World.keyToZ(chunkCoord); -+ // If unloaded, or in procedd of being unloaded, drop it -+ if ((!this.isChunkLoaded(chunkX, chunkZ)) || (this.chunkProviderServer.unloadQueue.contains(chunkX, chunkZ))) { -+ iter.remove(); -+ continue; -+ } -+ int players = iter.value(); -+ // Spigot end - // ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next(); - int k = chunkX * 16; - int l = chunkZ * 16; -@@ -293,16 +313,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - int k1; - int l1; - -- if (this.random.nextInt(100000) == 0 && this.N() && this.M()) { -- this.k = this.k * 3 + 1013904223; -- i1 = this.k >> 2; -- j1 = k + (i1 & 15); -- k1 = l + (i1 >> 8 & 15); -- l1 = this.h(j1, k1); -- if (this.D(j1, l1, k1)) { -- this.strikeLightning(new EntityLightning(this, (double) j1, (double) l1, (double) k1)); -- } -- } -+ // Spigot - remove lightning code - - this.methodProfiler.c("iceandsnow"); - int i2; -@@ -373,6 +384,14 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - - if (block != null && block.isTicking()) { - ++i; -+ // Spigot start -+ if (players < 1) { -+ //grow fast if no players are in this chunk -+ this.growthOdds = modifiedOdds; -+ } else { -+ this.growthOdds = 100; -+ } -+ // Spigot end - block.b(this, k2 + k, i3 + chunksection.d(), l2 + l, this.random); - } - } -@@ -413,10 +432,11 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - nextticklistentry.a(j1); - } - -- if (!this.L.contains(nextticklistentry)) { -- this.L.add(nextticklistentry); -- this.M.add(nextticklistentry); -- } -+ // if (!this.L.contains(nextticklistentry)) { -+ // this.L.add(nextticklistentry); -+ // this.M.add(nextticklistentry); -+ // } -+ addNextTickIfNeeded(nextticklistentry); // CraftBukkit - } - } - -@@ -427,10 +447,11 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - nextticklistentry.a((long) i1 + this.worldData.getTime()); - } - -- if (!this.L.contains(nextticklistentry)) { -- this.L.add(nextticklistentry); -- this.M.add(nextticklistentry); -- } -+ //if (!this.L.contains(nextticklistentry)) { -+ // this.L.add(nextticklistentry); -+ // this.M.add(nextticklistentry); -+ //} -+ addNextTickIfNeeded(nextticklistentry); // CraftBukkit - } - - public void tickEntities() { -@@ -452,9 +473,9 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - public boolean a(boolean flag) { - int i = this.M.size(); - -- if (i != this.L.size()) { -- throw new IllegalStateException("TickNextTick list out of synch"); -- } else { -+ //if (i != this.L.size()) { // Spigot -+ // throw new IllegalStateException("TickNextTick list out of synch"); // Spigot -+ //} else { // Spigot - if (i > 1000) { - // CraftBukkit start - if the server has too much to process over time, try to alleviate that - if (i > 20 * 1000) { -@@ -472,8 +493,11 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - break; - } - -- this.M.remove(nextticklistentry); -- this.L.remove(nextticklistentry); -+ // Spigot start -+ //this.M.remove(nextticklistentry); -+ //this.L.remove(nextticklistentry); -+ this.removeNextTickIfNeeded(nextticklistentry); -+ // Spigot end - byte b0 = 8; - - if (this.d(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) { -@@ -502,10 +526,12 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - } - - return !this.M.isEmpty(); -- } -+ // } // Spigot - } - - public List a(Chunk chunk, boolean flag) { -+ return this.getNextTickEntriesForChunk(chunk, flag); // Spigot -+ /* Spigot start - ArrayList arraylist = null; - ChunkCoordIntPair chunkcoordintpair = chunk.l(); - int i = chunkcoordintpair.x << 4; -@@ -532,6 +558,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - } - - return arraylist; -+ // Spigot end */ - } - - public void entityJoinedWorld(Entity entity, boolean flag) { -@@ -610,7 +637,7 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - } - - if (this.L == null) { -- this.L = new HashSet(); -+ this.L = new LongObjectHashMap>(); - } - - if (this.M == null) { -@@ -883,4 +910,48 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate - public PortalTravelAgent s() { - return this.P; - } -+ -+ // Spigot start -+ private void addNextTickIfNeeded(NextTickListEntry ent) { -+ long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4); -+ Set chunkset = L.get(coord); -+ if (chunkset == null) { -+ chunkset = new HashSet(); -+ L.put(coord, chunkset); -+ } else if (chunkset.contains(ent)) { -+ return; -+ } -+ chunkset.add(ent); -+ M.add(ent); -+ } -+ -+ private void removeNextTickIfNeeded(NextTickListEntry ent) { -+ long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4); -+ Set chunkset = L.get(coord); -+ if (chunkset == null) { -+ return; -+ } -+ if (chunkset.remove(ent)) { -+ M.remove(ent); -+ if (chunkset.isEmpty()) { -+ L.remove(coord); -+ } -+ } -+ } -+ -+ private List getNextTickEntriesForChunk(Chunk chunk, boolean remove) { -+ long coord = LongHash.toLong(chunk.x, chunk.z); -+ Set chunkset = L.get(coord); -+ if (chunkset == null) { -+ return null; -+ } -+ List list = new ArrayList(chunkset); -+ if (remove) { -+ L.remove(coord); -+ M.removeAll(list); -+ chunkset.clear(); -+ } -+ return list; -+ } -+ // Spigot end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 936cbc6..67593d5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -146,7 +146,7 @@ public final class CraftServer implements Server { - protected final MinecraftServer console; - protected final DedicatedPlayerList playerList; - private final Map worlds = new LinkedHashMap(); -- private YamlConfiguration configuration; -+ protected YamlConfiguration configuration; // Spigot private -> protected - private final Yaml yaml = new Yaml(new SafeConstructor()); - private final Map offlinePlayers = new MapMaker().softValues().makeMap(); - private final AutoUpdater updater; -@@ -166,6 +166,14 @@ public final class CraftServer implements Server { - private final class BooleanWrapper { - private boolean value = true; - } -+ // Spigot start -+ public String whitelistMessage = "You are not white-listed on this server!"; -+ public String stopMessage = "Server restarting. Brb"; -+ public boolean logCommands = true; -+ public boolean ipFilter = false; -+ public boolean commandComplete = true; -+ public List spamGuardExclusions; -+ // Spigot end - - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); -@@ -208,12 +216,37 @@ public final class CraftServer implements Server { - chunkGCLoadThresh = configuration.getInt("chunk-gc.load-threshold"); - - updater = new AutoUpdater(new BukkitDLUpdaterService(configuration.getString("auto-updater.host")), getLogger(), configuration.getString("auto-updater.preferred-channel")); -- updater.setEnabled(configuration.getBoolean("auto-updater.enabled")); -+ updater.setEnabled(false); - updater.setSuggestChannels(configuration.getBoolean("auto-updater.suggest-channels")); - updater.getOnBroken().addAll(configuration.getStringList("auto-updater.on-broken")); - updater.getOnUpdate().addAll(configuration.getStringList("auto-updater.on-update")); - updater.check(serverVersion); - -+ // Spigot start -+ commandMap.register("bukkit", new org.bukkit.craftbukkit.command.RestartCommand("restart")); -+ commandMap.register("bukkit", new org.bukkit.craftbukkit.command.TicksPerSecondCommand("tps")); -+ -+ org.bukkit.craftbukkit.util.WatchdogThread.startThread(configuration.getInt("settings.timeout-time", 180), configuration.getBoolean("settings.restart-on-crash", false)); -+ -+ whitelistMessage = configuration.getString("settings.whitelist-message", whitelistMessage); -+ stopMessage = configuration.getString("settings.stop-message", stopMessage); -+ logCommands = configuration.getBoolean("settings.log-commands", true); -+ ipFilter = configuration.getBoolean("settings.filter-unsafe-ips", false); -+ commandComplete = configuration.getBoolean("settings.command-complete", true); -+ spamGuardExclusions = configuration.getStringList("settings.spam-exclusions"); -+ -+ org.bukkit.craftbukkit.util.LightningSimulator.configure(configuration); -+ -+ try { -+ configuration.save(getConfigFile()); -+ } catch (IOException e) { -+ } -+ try { -+ new org.bukkit.craftbukkit.util.Metrics().start(); -+ } catch (IOException e) { -+ getLogger().log(Level.SEVERE, "Could not start metrics", e); -+ } -+ // Spigot end - loadPlugins(); - enablePlugins(PluginLoadOrder.STARTUP); - } -@@ -222,7 +255,7 @@ public final class CraftServer implements Server { - return (File) console.options.valueOf("bukkit-settings"); - } - -- private void saveConfig() { -+ public void saveConfig() { // Spigot private -> public - try { - configuration.save(getConfigFile()); - } catch (IOException ex) { -@@ -1036,11 +1069,8 @@ public final class CraftServer implements Server { - return count; - } - -+ // Spigot start - public OfflinePlayer getOfflinePlayer(String name) { -- return getOfflinePlayer(name, true); -- } -- -- public OfflinePlayer getOfflinePlayer(String name, boolean search) { - OfflinePlayer result = getPlayerExact(name); - String lname = name.toLowerCase(); - -@@ -1048,17 +1078,7 @@ public final class CraftServer implements Server { - result = offlinePlayers.get(lname); - - if (result == null) { -- if (search) { -- WorldNBTStorage storage = (WorldNBTStorage) console.worlds.get(0).getDataManager(); -- for (String dat : storage.getPlayerDir().list(new DatFileFilter())) { -- String datName = dat.substring(0, dat.length() - 4); -- if (datName.equalsIgnoreCase(name)) { -- name = datName; -- break; -- } -- } -- } -- -+ // Spigot end - result = new CraftOfflinePlayer(this, name); - offlinePlayers.put(lname, result); - } -@@ -1196,7 +1216,7 @@ public final class CraftServer implements Server { - Set players = new HashSet(); - - for (String file : files) { -- players.add(getOfflinePlayer(file.substring(0, file.length() - 4), false)); -+ players.add(getOfflinePlayer(file.substring(0, file.length() - 4))); // Spigot - } - players.addAll(Arrays.asList(getOnlinePlayers())); - -@@ -1302,7 +1322,7 @@ public final class CraftServer implements Server { - public List tabCompleteCommand(Player player, String message) { - List completions = null; - try { -- completions = getCommandMap().tabComplete(player, message.substring(1)); -+ completions = (commandComplete) ? getCommandMap().tabComplete(player, message.substring(1)) : null; // Spigot - } catch (CommandException ex) { - player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command"); - getLogger().log(Level.SEVERE, "Exception when " + player.getName() + " attempted to tab complete " + message, ex); -@@ -1338,4 +1358,52 @@ public final class CraftServer implements Server { - public CraftItemFactory getItemFactory() { - return CraftItemFactory.instance(); - } -+ -+ // Spigot start -+ public void restart() { -+ try { -+ String startupScript = configuration.getString("settings.restart-script-location", ""); -+ File file = new File(startupScript); -+ if (file.isFile()) { -+ System.out.println("Attempting to restart with " + startupScript); -+ -+ // Kick all players -+ for (Player p : this.getOnlinePlayers()) { -+ ((org.bukkit.craftbukkit.entity.CraftPlayer) p).kickPlayer("Server is restarting", true); -+ } -+ // Give the socket a chance to send the packets -+ try { -+ Thread.sleep(100); -+ } catch (InterruptedException ex) { -+ } -+ // Close the socket so we can rebind with the new process -+ this.getServer().ae().a(); -+ -+ // Give time for it to kick in -+ try { -+ Thread.sleep(100); -+ } catch (InterruptedException ex) { -+ } -+ -+ // Actually shutdown -+ try { -+ this.getServer().stop(); -+ } catch (Throwable t) { -+ } -+ -+ String os = System.getProperty("os.name").toLowerCase(); -+ if (os.contains("win")) { -+ Runtime.getRuntime().exec("cmd /c start " + file.getPath()); -+ } else { -+ Runtime.getRuntime().exec(file.getPath()); -+ } -+ System.exit(0); -+ } else { -+ System.out.println("Startup script '" + startupScript + "' does not exist!"); -+ } -+ } catch (Exception ex) { -+ ex.printStackTrace(); -+ } -+ } -+ // Spigot end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index cb20066..3544aa3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -73,7 +73,81 @@ public class CraftWorld implements World { - if (server.chunkGCPeriod > 0) { - chunkGCTickCount = rand.nextInt(server.chunkGCPeriod); - } -- } -+ // Spigot Start -+ org.bukkit.configuration.file.YamlConfiguration configuration = server.configuration; -+ String name; -+ if (world.worldData == null || world.worldData.getName() == null) { -+ name = "default"; -+ } else { -+ name = world.worldData.getName().replaceAll(" ", "_"); -+ } -+ -+ //load defaults first -+ growthPerTick = configuration.getInt("world-settings.default.growth-chunks-per-tick", growthPerTick); -+ itemMergeRadius = configuration.getDouble("world-settings.default.item-merge-radius", itemMergeRadius); -+ expMergeRadius = configuration.getDouble("world-settings.default.exp-merge-radius", expMergeRadius); -+ randomLightingUpdates = configuration.getBoolean("world-settings.default.random-light-updates", randomLightingUpdates); -+ mobSpawnRange = configuration.getInt("world-settings.default.mob-spawn-range", mobSpawnRange); -+ aggregateTicks = Math.max(1, configuration.getInt("world-settings.default.aggregate-chunkticks", aggregateTicks)); -+ -+ wheatGrowthModifier = configuration.getInt("world-settings.default.wheat-growth-modifier", wheatGrowthModifier); -+ cactusGrowthModifier = configuration.getInt("world-settings.default.cactus-growth-modifier", cactusGrowthModifier); -+ melonGrowthModifier = configuration.getInt("world-settings.default.melon-growth-modifier", melonGrowthModifier); -+ pumpkinGrowthModifier = configuration.getInt("world-settings.default.pumpkin-growth-modifier", pumpkinGrowthModifier); -+ sugarGrowthModifier = configuration.getInt("world-settings.default.sugar-growth-modifier", sugarGrowthModifier); -+ treeGrowthModifier = configuration.getInt("world-settings.default.tree-growth-modifier", treeGrowthModifier); -+ mushroomGrowthModifier = configuration.getInt("world-settings.default.mushroom-growth-modifier", mushroomGrowthModifier); -+ -+ //override defaults with world specific, if they exist -+ growthPerTick = configuration.getInt("world-settings." + name + ".growth-chunks-per-tick", growthPerTick); -+ itemMergeRadius = configuration.getDouble("world-settings." + name + ".item-merge-radius", itemMergeRadius); -+ expMergeRadius = configuration.getDouble("world-settings." + name + ".exp-merge-radius", expMergeRadius); -+ randomLightingUpdates = configuration.getBoolean("world-settings." + name + ".random-light-updates", randomLightingUpdates); -+ mobSpawnRange = configuration.getInt("world-settings." + name + ".mob-spawn-range", mobSpawnRange); -+ aggregateTicks = Math.max(1, configuration.getInt("world-settings." + name + ".aggregate-chunkticks", aggregateTicks)); -+ -+ wheatGrowthModifier = configuration.getInt("world-settings." + name + ".wheat-growth-modifier", wheatGrowthModifier); -+ cactusGrowthModifier = configuration.getInt("world-settings." + name + ".cactus-growth-modifier", cactusGrowthModifier); -+ melonGrowthModifier = configuration.getInt("world-settings." + name + ".melon-growth-modifier", melonGrowthModifier); -+ pumpkinGrowthModifier = configuration.getInt("world-settings." + name + ".pumpkin-growth-modifier", pumpkinGrowthModifier); -+ sugarGrowthModifier = configuration.getInt("world-settings." + name + ".sugar-growth-modifier", sugarGrowthModifier); -+ treeGrowthModifier = configuration.getInt("world-settings." + name + ".tree-growth-modifier", treeGrowthModifier); -+ mushroomGrowthModifier = configuration.getInt("world-settings." + name + ".mushroom-growth-modifier", mushroomGrowthModifier); -+ -+ server.getLogger().info("-------------- Spigot ----------------"); -+ server.getLogger().info("-------- World Settings For [" + name + "] --------"); -+ server.getLogger().info("Growth Per Chunk: " + growthPerTick); -+ server.getLogger().info("Item Merge Radius: " + itemMergeRadius); -+ server.getLogger().info("Experience Merge Radius: " + expMergeRadius); -+ server.getLogger().info("Random Lighting Updates: " + randomLightingUpdates); -+ server.getLogger().info("Mob Spawn Range: " + mobSpawnRange); -+ server.getLogger().info("Aggregate Ticks: " + aggregateTicks); -+ server.getLogger().info("Wheat Growth Modifier: " + wheatGrowthModifier); -+ server.getLogger().info("Cactus Growth Modifier: " + cactusGrowthModifier); -+ server.getLogger().info("Melon Growth Modifier: " + melonGrowthModifier); -+ server.getLogger().info("Pumpkin Growth Modifier: " + pumpkinGrowthModifier); -+ server.getLogger().info("Sugar Growth Modifier: " + sugarGrowthModifier); -+ server.getLogger().info("Tree Growth Modifier: " + treeGrowthModifier); -+ server.getLogger().info("Mushroom Growth Modifier: " + mushroomGrowthModifier); -+ server.getLogger().info("-------------------------------------------------"); -+ // Spigot end -+ } -+ // Spigot Start -+ public int growthPerTick = 650; -+ public double itemMergeRadius = 3; -+ public double expMergeRadius = 3; -+ public boolean randomLightingUpdates = false; -+ public int mobSpawnRange = 4; -+ public int aggregateTicks = 4; -+ //Crop growth rates: -+ public int wheatGrowthModifier = 100; -+ public int cactusGrowthModifier = 100; -+ public int melonGrowthModifier = 100; -+ public int pumpkinGrowthModifier = 100; -+ public int sugarGrowthModifier = 100; -+ public int treeGrowthModifier = 100; -+ public int mushroomGrowthModifier = 100; -+ // Spigot end - - public Block getBlockAt(int x, int y, int z) { - return getChunkAt(x >> 4, z >> 4).getBlock(x & 0xF, y & 0xFF, z & 0xF); -diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -index 48cf5ba..1d4764c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -@@ -40,7 +40,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider 19.2D) { -+ color = ChatColor.GREEN; -+ } else if (tps > 17.4D) { -+ color = ChatColor.YELLOW; -+ } else { -+ color = ChatColor.RED; -+ } -+ -+ sender.sendMessage(ChatColor.GOLD + "[TPS] " + color + tps); -+ -+ return true; -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 90abcce..3e9df39 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -212,10 +212,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - - public void kickPlayer(String message) { -+ // Spigot start -+ kickPlayer(message, false); -+ } -+ -+ public void kickPlayer(String message, boolean async){ - if (getHandle().playerConnection == null) return; -+ if (!async && !Bukkit.isPrimaryThread()) throw new IllegalStateException("Cannot kick player from asynchronous thread!"); // Spigot - - getHandle().playerConnection.disconnect(message == null ? "" : message); - } -+ // Spigot end - - public void setCompassTarget(Location loc) { - if (getHandle().playerConnection == null) return; -diff --git a/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java b/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java -index f027900..efc7889 100644 ---- a/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java -+++ b/src/main/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterService.java -@@ -1,6 +1,6 @@ - package org.bukkit.craftbukkit.updater; - --import com.google.gson.*; -+// import com.google.gson.*; // Spigot - import java.io.IOException; - import java.io.InputStreamReader; - import java.io.UnsupportedEncodingException; -@@ -16,7 +16,7 @@ import java.util.logging.Logger; - public class BukkitDLUpdaterService { - private static final String API_PREFIX_ARTIFACT = "/api/1.0/downloads/projects/craftbukkit/view/"; - private static final String API_PREFIX_CHANNEL = "/api/1.0/downloads/channels/"; -- private static final DateDeserializer dateDeserializer = new DateDeserializer(); -+ // private static final DateDeserializer dateDeserializer = new DateDeserializer(); // Spigot - private final String host; - - public BukkitDLUpdaterService(String host) { -@@ -47,8 +47,11 @@ public class BukkitDLUpdaterService { - URLConnection connection = url.openConnection(); - connection.setRequestProperty("User-Agent", getUserAgent()); - reader = new InputStreamReader(connection.getInputStream()); -- Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); -- return gson.fromJson(reader, ArtifactDetails.class); -+ // Spigot start -+ // Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); -+ // return gson.fromJson(reader, ArtifactDetails.class); -+ // Spigot end -+ return null; - } finally { - if (reader != null) { - reader.close(); -@@ -76,10 +79,13 @@ public class BukkitDLUpdaterService { - URLConnection connection = url.openConnection(); - connection.setRequestProperty("User-Agent", getUserAgent()); - reader = new InputStreamReader(connection.getInputStream()); -- Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); -- ArtifactDetails.ChannelDetails fromJson = gson.fromJson(reader, ArtifactDetails.ChannelDetails.class); -+ // Spigot start -+ // Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateDeserializer).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); -+ // ArtifactDetails.ChannelDetails fromJson = gson.fromJson(reader, ArtifactDetails.ChannelDetails.class); - -- return fromJson; -+ //return fromJson; -+ // Spigot end -+ return null; - } finally { - if (reader != null) { - reader.close(); -@@ -87,7 +93,9 @@ public class BukkitDLUpdaterService { - } - } - -- static class DateDeserializer implements JsonDeserializer { -+ // Spigot start -+ /* -+ static class DateDeserializer implements JsonDeserializer { - private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - public Date deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException { -@@ -97,5 +105,5 @@ public class BukkitDLUpdaterService { - throw new JsonParseException("Date is not formatted correctly", ex); - } - } -- } -+ }*/// Spigot end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/ExceptionHandler.java b/src/main/java/org/bukkit/craftbukkit/util/ExceptionHandler.java -new file mode 100644 -index 0000000..392155e ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/ExceptionHandler.java -@@ -0,0 +1,31 @@ -+package org.bukkit.craftbukkit.util; -+ -+import java.lang.Thread.UncaughtExceptionHandler; -+import java.util.logging.Level; -+import java.util.logging.Logger; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.CraftServer; -+ -+public class ExceptionHandler implements UncaughtExceptionHandler { -+ -+ public void uncaughtException(Thread t, Throwable e) { -+ Logger log = ((CraftServer) Bukkit.getServer()).getLogger(); -+ log.log(Level.SEVERE, "The server has crashed!"); -+ log.log(Level.SEVERE, "Please report this to md_5!"); -+ log.log(Level.SEVERE, "Begin Exception Trace:"); -+ log.log(Level.SEVERE, ""); -+ StackTraceElement[] stack = e.getStackTrace(); -+ for (int line = 0; line < stack.length; line++) { -+ log.log(Level.SEVERE, " " + stack[line].toString()); -+ } -+ log.log(Level.SEVERE, "End Exception Trace:"); -+ log.log(Level.SEVERE, ""); -+ log.log(Level.SEVERE, "Begin Thread Stack Trace:"); -+ stack = t.getStackTrace(); -+ for (int line = 0; line < stack.length; line++) { -+ log.log(Level.SEVERE, " " + stack[line].toString()); -+ } -+ log.log(Level.SEVERE, "End Exception Trace:"); -+ log.log(Level.SEVERE, ""); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/ExceptionReporter.java b/src/main/java/org/bukkit/craftbukkit/util/ExceptionReporter.java -new file mode 100644 -index 0000000..1d0e284 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/ExceptionReporter.java -@@ -0,0 +1,26 @@ -+package org.bukkit.craftbukkit.util; -+ -+import org.bukkit.Bukkit; -+ -+public final class ExceptionReporter { -+ -+ public static void handle(Throwable t, String... messages) { -+ for (String message : messages) { -+ Bukkit.getLogger().severe(message); -+ } -+ Bukkit.getLogger().severe("Spigot recommends you report this to md_5"); -+ Bukkit.getLogger().severe(""); -+ Bukkit.getLogger().severe("Spigot version: " + Bukkit.getBukkitVersion()); -+ Bukkit.getLogger().severe("Exception Trace Begins:"); -+ StackTraceElement[] stack = t.getStackTrace(); -+ for (int line = 0; line < stack.length; line++) { -+ Bukkit.getLogger().severe(" " + stack[line].toString()); -+ } -+ Bukkit.getLogger().severe("Exception Trace Ends."); -+ Bukkit.getLogger().severe(""); -+ } -+ -+ public static void handle(Throwable t) { -+ handle(t, "Spigot has encountered an unexpected exception!"); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java b/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java -new file mode 100644 -index 0000000..e8a7725 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java -@@ -0,0 +1,34 @@ -+package org.bukkit.craftbukkit.util; -+ -+public class FlatMap { -+ -+ private static final int FLAT_LOOKUP_SIZE = 512; -+ private final Object[][] flatLookup = new Object[FLAT_LOOKUP_SIZE * 2][FLAT_LOOKUP_SIZE * 2]; -+ -+ public void put(long msw, long lsw, V value) { -+ long acx = Math.abs(msw); -+ long acz = Math.abs(lsw); -+ if (acx < FLAT_LOOKUP_SIZE && acz < FLAT_LOOKUP_SIZE) { -+ flatLookup[(int) (msw + FLAT_LOOKUP_SIZE)][(int) (lsw + FLAT_LOOKUP_SIZE)] = value; -+ } -+ } -+ -+ public void put(long key, V value) { -+ put(LongHash.msw(key), LongHash.lsw(key), value); -+ -+ } -+ -+ public V get(long msw, long lsw) { -+ long acx = Math.abs(msw); -+ long acz = Math.abs(lsw); -+ if (acx < FLAT_LOOKUP_SIZE && acz < FLAT_LOOKUP_SIZE) { -+ return (V) flatLookup[(int) (msw + FLAT_LOOKUP_SIZE)][(int) (lsw + FLAT_LOOKUP_SIZE)]; -+ } else { -+ return null; -+ } -+ } -+ -+ public V get(long key) { -+ return get(LongHash.msw(key), LongHash.lsw(key)); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/LightningSimulator.java b/src/main/java/org/bukkit/craftbukkit/util/LightningSimulator.java -new file mode 100644 -index 0000000..3b12b19 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/LightningSimulator.java -@@ -0,0 +1,184 @@ -+package org.bukkit.craftbukkit.util; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Random; -+import net.minecraft.server.EntityLightning; -+import net.minecraft.server.EntityPlayer; -+import net.minecraft.server.MathHelper; -+import net.minecraft.server.World; -+import org.bukkit.Bukkit; -+import org.bukkit.configuration.file.YamlConfiguration; -+import org.bukkit.event.weather.ThunderChangeEvent; -+ -+public class LightningSimulator { -+ -+ private static final int MAX_LIGHTNING_BRANCHES = 5; -+ final World world; -+ final HashMap playerCountdown = new HashMap(); -+ Intensity stormIntensity = null; -+ boolean canceled = false; -+ -+ public LightningSimulator(World world) { -+ this.world = world; -+ } -+ -+ public static void configure(YamlConfiguration configuration) { -+ Bukkit.getLogger().info("--------Setting up Storm Configuration--------"); -+ for (Intensity intensity : Intensity.values()) { -+ String nameFormatted = intensity.name().toLowerCase().replaceAll("_", "-"); -+ intensity.chance = configuration.getInt("storm-settings." + nameFormatted + ".chance", intensity.chance); -+ intensity.baseTicks = configuration.getInt("storm-settings." + nameFormatted + ".lightning-delay", intensity.baseTicks); -+ intensity.randomTicks = configuration.getInt("storm-settings." + nameFormatted + ".lightning-random-delay", intensity.randomTicks); -+ Bukkit.getLogger().info(" Storm Type: " + nameFormatted); -+ Bukkit.getLogger().info(" Chance: " + intensity.chance); -+ Bukkit.getLogger().info(" Lightning Delay Ticks: " + intensity.baseTicks); -+ Bukkit.getLogger().info(" Lightning Random Delay Ticks: " + intensity.randomTicks); -+ } -+ Bukkit.getLogger().info("--------Finished Storm Configuration--------"); -+ } -+ -+ public void onTick() { -+ try { -+ updatePlayerTimers(); -+ } catch (Exception e) { -+ System.out.println("Spigot failed to calculate lightning for the server"); -+ System.out.println("Please report this to md_5"); -+ System.out.println("Spigot Version: " + Bukkit.getBukkitVersion()); -+ e.printStackTrace(); -+ } -+ } -+ -+ public void updatePlayerTimers() { -+ if (world.getWorld().hasStorm()) { -+ if (canceled) { -+ return; -+ } -+ if (stormIntensity == null) { -+ ThunderChangeEvent thunder = new ThunderChangeEvent(world.getWorld(), true); -+ Bukkit.getPluginManager().callEvent(thunder); -+ if (thunder.isCancelled()) { -+ canceled = true; -+ return; -+ } -+ stormIntensity = Intensity.getRandomIntensity(world.random); -+ System.out.println("Started a storm of type " + stormIntensity.name() + " in world [" + world.worldData.getName() + "]"); -+ } -+ List toStrike = new ArrayList(); -+ for (Object o : world.players) { -+ if (o instanceof EntityPlayer) { -+ EntityPlayer player = (EntityPlayer) o; -+ Integer ticksLeft = playerCountdown.get(player); -+ if (ticksLeft == null) { -+ playerCountdown.put(player, getTicksBeforeNextLightning(world.random)); -+ } else if (ticksLeft == 1) { -+ //weed out dc'd players -+ if (!player.playerConnection.disconnected) { -+ toStrike.add(player); -+ playerCountdown.put(player, getTicksBeforeNextLightning(world.random)); -+ } -+ } else { -+ playerCountdown.put(player, ticksLeft - 1); -+ } -+ } -+ } -+ strikePlayers(toStrike); -+ } else { -+ stormIntensity = null; -+ canceled = false; -+ } -+ } -+ -+ public void strikePlayers(List toStrike) { -+ for (EntityPlayer player : toStrike) { -+ final int posX = MathHelper.floor(player.locX); -+ final int posY = MathHelper.floor(player.locY); -+ final int posZ = MathHelper.floor(player.locZ); -+ for (int tries = 0; tries < 10; tries++) { -+ //pick a random chunk between -4, -4, to 4, 4 relative to the player's position to strike at -+ int cx = (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(5); -+ int cz = (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(5); -+ -+ //pick random coords to try to strike at inside the chunk (0, 0) to (15, 15) -+ int rx = world.random.nextInt(16); -+ int rz = world.random.nextInt(16); -+ -+ //pick a offset from the player's y position to strike at (-15 - +15) of their position -+ int offsetY = (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(15); -+ -+ int x = cx * 16 + rx + posX; -+ int y = posY + offsetY; -+ int z = cz * 16 + rz + posZ; -+ -+ if (isRainingAt(x, y, z)) { -+ int lightning = 1; -+ //30% chance of extra lightning at the spot -+ if (world.random.nextInt(10) < 3) { -+ lightning += world.random.nextInt(MAX_LIGHTNING_BRANCHES); -+ } -+ for (int strikes = 0; strikes < lightning; strikes++) { -+ double adjustX = 0.5D; -+ double adjustY = 0.0D; -+ double adjustZ = 0.5D; -+ //if there are extra strikes, tweak their placement slightly -+ if (strikes > 0) { -+ adjustX += (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(2); -+ adjustY += (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(8); -+ adjustZ += (world.random.nextBoolean() ? -1 : 1) * world.random.nextInt(2); -+ } -+ EntityLightning lightningStrike = new EntityLightning(world, x + adjustX, y + adjustY, z + adjustZ); -+ world.strikeLightning(lightningStrike); -+ } -+ //success, go to the next player -+ break; -+ } -+ } -+ } -+ } -+ -+ public int getTicksBeforeNextLightning(Random rand) { -+ return stormIntensity.baseTicks + rand.nextInt(stormIntensity.randomTicks); -+ } -+ -+ public boolean isRainingAt(int x, int y, int z) { -+ return world.D(x, y, z); -+ } -+} -+ -+enum Intensity { -+ -+ STRONG_ELECTRICAL_STORM(5, 10, 20), -+ ELECTRICAL_STORM(15, 40, 150), -+ STRONG_THUNDERSTORM(30, 60, 250), -+ THUNDERSTORM(50, 100, 500), -+ WEAK_THUNDERSTORM(75, 300, 1000), -+ RAINSTORM(100, 500, 2000); -+ int chance, baseTicks, randomTicks; -+ -+ Intensity(int chance, int baseTicks, int randomTicks) { -+ this.chance = chance; -+ this.baseTicks = baseTicks; -+ this.randomTicks = randomTicks; -+ } -+ -+ public static Intensity getRandomIntensity(Random rand) { -+ int r = rand.nextInt(100); -+ if (r < STRONG_ELECTRICAL_STORM.chance) { -+ return STRONG_ELECTRICAL_STORM; -+ } -+ if (r < ELECTRICAL_STORM.chance) { -+ return ELECTRICAL_STORM; -+ } -+ if (r < STRONG_THUNDERSTORM.chance) { -+ return STRONG_THUNDERSTORM; -+ } -+ if (r < THUNDERSTORM.chance) { -+ return THUNDERSTORM; -+ } -+ if (r < WEAK_THUNDERSTORM.chance) { -+ return WEAK_THUNDERSTORM; -+ } -+ return RAINSTORM; -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java -index 22c96c5..3f1617d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java -@@ -31,6 +31,8 @@ public class LongHashSet { - private int elements; - private long[] values; - private int modCount; -+ private static final Object PRESENT = new Object(); -+ private final FlatMap flat = new FlatMap(); - - public LongHashSet() { - this(INITIAL_SIZE); -@@ -56,10 +58,11 @@ public class LongHashSet { - } - - public boolean contains(int msw, int lsw) { -+ if (flat.get(msw, lsw) != null) return true; // Spigot - return contains(LongHash.toLong(msw, lsw)); - } - -- public boolean contains(long value) { -+ private boolean contains(long value) { // Spigot - int hash = hash(value); - int index = (hash & 0x7FFFFFFF) % values.length; - int offset = 1; -@@ -78,10 +81,11 @@ public class LongHashSet { - } - - public boolean add(int msw, int lsw) { -+ flat.put(msw, lsw, PRESENT); // Spigot - return add(LongHash.toLong(msw, lsw)); - } - -- public boolean add(long value) { -+ private boolean add(long value) { // Spigot - int hash = hash(value); - int index = (hash & 0x7FFFFFFF) % values.length; - int offset = 1; -@@ -125,10 +129,11 @@ public class LongHashSet { - } - - public void remove(int msw, int lsw) { -+ flat.put(msw, lsw, null); // Spigot - remove(LongHash.toLong(msw, lsw)); - } - -- public boolean remove(long value) { -+ private boolean remove(long value) { // Spigot - int hash = hash(value); - int index = (hash & 0x7FFFFFFF) % values.length; - int offset = 1; -diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java b/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java -index 01861cc..dbd33fa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java -@@ -28,6 +28,7 @@ public class LongObjectHashMap implements Cloneable, Serializable { - private transient V[][] values; - private transient int modCount; - private transient int size; -+ private final FlatMap flat = new FlatMap(); // Spigot - - public LongObjectHashMap() { - initialize(); -@@ -61,6 +62,8 @@ public class LongObjectHashMap implements Cloneable, Serializable { - } - - public V get(long key) { -+ V val = flat.get(key); // Spigot -+ if (val != null) return val; // Spigot - int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1)); - long[] inner = keys[index]; - if (inner == null) return null; -@@ -78,6 +81,7 @@ public class LongObjectHashMap implements Cloneable, Serializable { - } - - public V put(long key, V value) { -+ flat.put(key, value); // Spigot - int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1)); - long[] innerKeys = keys[index]; - V[] innerValues = values[index]; -@@ -124,6 +128,7 @@ public class LongObjectHashMap implements Cloneable, Serializable { - } - - public V remove(long key) { -+ flat.put(key, null); // Spigot - int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1)); - long[] inner = keys[index]; - if (inner == null) { -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Metrics.java b/src/main/java/org/bukkit/craftbukkit/util/Metrics.java -new file mode 100644 -index 0000000..da05b80 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/Metrics.java -@@ -0,0 +1,488 @@ -+package org.bukkit.craftbukkit.util; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.configuration.file.YamlConfiguration; -+import java.io.BufferedReader; -+import java.io.File; -+import java.io.IOException; -+import java.io.InputStreamReader; -+import java.io.OutputStreamWriter; -+import java.io.UnsupportedEncodingException; -+import java.net.Proxy; -+import java.net.URL; -+import java.net.URLConnection; -+import java.net.URLEncoder; -+import java.util.Collections; -+import java.util.HashSet; -+import java.util.Iterator; -+import java.util.LinkedHashSet; -+import java.util.Set; -+import java.util.UUID; -+ -+/** -+ *

The metrics class obtains data about a plugin and submits statistics -+ * about it to the metrics backend.

Public methods provided by this -+ * class:

-+ * -+ * Graph createGraph(String name);
-+ * void addCustomData(Metrics.Plotter plotter);
-+ * void start();
-+ *
-+ */ -+public class Metrics { -+ -+ /** -+ * The current revision number -+ */ -+ private final static int REVISION = 5; -+ /** -+ * The base url of the metrics domain -+ */ -+ private static final String BASE_URL = "http://mcstats.org"; -+ /** -+ * The url used to report a server's status -+ */ -+ private static final String REPORT_URL = "/report/%s"; -+ /** -+ * The file where guid and opt out is stored in -+ */ -+ private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml"; -+ /** -+ * The separator to use for custom data. This MUST NOT change unless you are -+ * hosting your own version of metrics and want to change it. -+ */ -+ private static final String CUSTOM_DATA_SEPARATOR = "~~"; -+ /** -+ * Interval of time to ping (in minutes) -+ */ -+ private final static int PING_INTERVAL = 5; -+ /** -+ * All of the custom graphs to submit to metrics -+ */ -+ private final Set graphs = Collections.synchronizedSet(new HashSet()); -+ /** -+ * The default graph, used for addCustomData when you don't want a specific -+ * graph -+ */ -+ private final Graph defaultGraph = new Graph("Default"); -+ /** -+ * The plugin configuration file -+ */ -+ private final YamlConfiguration configuration; -+ /** -+ * Unique server id -+ */ -+ private final String guid; -+ -+ public Metrics() throws IOException { -+ // load the config -+ File file = new File(CONFIG_FILE); -+ configuration = YamlConfiguration.loadConfiguration(file); -+ -+ // add some defaults -+ configuration.addDefault("opt-out", false); -+ configuration.addDefault("guid", UUID.randomUUID().toString()); -+ -+ // Do we need to create the file? -+ if (configuration.get("guid", null) == null) { -+ configuration.options().header("http://metrics.griefcraft.com").copyDefaults(true); -+ configuration.save(file); -+ } -+ -+ // Load the guid then -+ guid = configuration.getString("guid"); -+ -+ Graph graph = createGraph("Operating System"); -+ // Plot the total amount of protections -+ graph.addPlotter(new Metrics.Plotter(System.getProperty("os.name")) { -+ @Override -+ public int getValue() { -+ return 1; -+ } -+ }); -+ -+ graph = createGraph("System Cores"); -+ // Plot the total amount of protections -+ graph.addPlotter(new Metrics.Plotter(Integer.toString(Runtime.getRuntime().availableProcessors())) { -+ @Override -+ public int getValue() { -+ return 1; -+ } -+ }); -+ -+ graph = createGraph("System RAM"); -+ long RAM = Runtime.getRuntime().maxMemory() / 1024L / 1024L; -+ String plotName; -+ if (RAM < 1024) { -+ plotName = "< 1024mb"; -+ } else if (RAM < 2048) { -+ plotName = "1024-2048mb"; -+ } else if (RAM < 4096) { -+ plotName = "2048-4096mb"; -+ } else if (RAM < 8192) { -+ plotName = "4096-8192mb"; -+ } else if (RAM < 16384) { -+ plotName = "8192-16384mb"; -+ } else { -+ plotName = "16384+ mb"; -+ } -+ -+ // Plot the total amount of protections -+ graph.addPlotter(new Metrics.Plotter(plotName) { -+ @Override -+ public int getValue() { -+ return 1; -+ } -+ }); -+ } -+ -+ /** -+ * Construct and create a Graph that can be used to separate specific -+ * plotters to their own graphs on the metrics website. Plotters can be -+ * added to the graph object returned. -+ * -+ * @param name -+ * @return Graph object created. Will never return NULL under normal -+ * circumstances unless bad parameters are given -+ */ -+ public Graph createGraph(String name) { -+ if (name == null) { -+ throw new IllegalArgumentException("Graph name cannot be null"); -+ } -+ -+ // Construct the graph object -+ Graph graph = new Graph(name); -+ -+ // Now we can add our graph -+ graphs.add(graph); -+ -+ // and return back -+ return graph; -+ } -+ -+ /** -+ * Adds a custom data plotter to the default graph -+ * -+ * @param plotter -+ */ -+ public void addCustomData(Plotter plotter) { -+ if (plotter == null) { -+ throw new IllegalArgumentException("Plotter cannot be null"); -+ } -+ -+ // Add the plotter to the graph o/ -+ defaultGraph.addPlotter(plotter); -+ -+ // Ensure the default graph is included in the submitted graphs -+ graphs.add(defaultGraph); -+ } -+ -+ /** -+ * Start measuring statistics. This will immediately create an async -+ * repeating task as the plugin and send the initial data to the metrics -+ * backend, and then after that it will post in increments of PING_INTERVAL -+ * * 1200 ticks. -+ */ -+ public void start() { -+ // Did we opt out? -+ if (configuration.getBoolean("opt-out", false)) { -+ return; -+ } -+ -+ // Begin hitting the server with glorious data -+ new TimedThread(new Runnable() { -+ private boolean firstPost = true; -+ -+ public void run() { -+ try { -+ // We use the inverse of firstPost because if it is the first time we are posting, -+ // it is not a interval ping, so it evaluates to FALSE -+ // Each time thereafter it will evaluate to TRUE, i.e PING! -+ postPlugin(!firstPost); -+ -+ // After the first post we set firstPost to false -+ // Each post thereafter will be a ping -+ firstPost = false; -+ } catch (IOException e) { -+ System.err.println("[Metrics] " + e.getMessage()); -+ } -+ } -+ }, PING_INTERVAL * 60000).start(); -+ } -+ -+ /** -+ * Generic method that posts a plugin to the metrics website -+ */ -+ private void postPlugin(boolean isPing) throws IOException { -+ // Construct the post data -+ String data = encode("guid") + '=' + encode(guid) -+ + encodeDataPair("version", "Spigot 1.4") -+ + encodeDataPair("server", Bukkit.getVersion()) -+ + encodeDataPair("players", Integer.toString(Bukkit.getServer().getOnlinePlayers().length)) -+ + encodeDataPair("revision", String.valueOf(REVISION)); -+ -+ // If we're pinging, append it -+ if (isPing) { -+ data += encodeDataPair("ping", "true"); -+ } -+ -+ // Acquire a lock on the graphs, which lets us make the assumption we also lock everything -+ // inside of the graph (e.g plotters) -+ synchronized (graphs) { -+ Iterator iter = graphs.iterator(); -+ -+ while (iter.hasNext()) { -+ Graph graph = iter.next(); -+ -+ //System.out.println("Sending data for " + graph.getName()); -+ -+ // Because we have a lock on the graphs set already, it is reasonable to assume -+ // that our lock transcends down to the individual plotters in the graphs also. -+ // Because our methods are private, no one but us can reasonably access this list -+ // without reflection so this is a safe assumption without adding more code. -+ for (Plotter plotter : graph.getPlotters()) { -+ // The key name to send to the metrics server -+ // The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top -+ // Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME -+ String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName()); -+ -+ // The value to send, which for the foreseeable future is just the string -+ // value of plotter.getValue() -+ String value = Integer.toString(plotter.getValue()); -+ -+ //System.out.println("Plotter data for " + plotter.getColumnName() + " is " + plotter.getValue()); -+ -+ // Add it to the http post data :) -+ data += encodeDataPair(key, value); -+ } -+ } -+ } -+ -+ // Create the url -+ URL url = new URL(BASE_URL + String.format(REPORT_URL, "Spigot")); -+ -+ // Connect to the website -+ URLConnection connection; -+ -+ // Mineshafter creates a socks proxy, so we can safely bypass it -+ // It does not reroute POST requests so we need to go around it -+ if (isMineshafterPresent()) { -+ connection = url.openConnection(Proxy.NO_PROXY); -+ } else { -+ connection = url.openConnection(); -+ } -+ -+ connection.setDoOutput(true); -+ -+ // Write the data -+ OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); -+ writer.write(data); -+ writer.flush(); -+ -+ // System.out.println(data); -+ -+ // Now read the response -+ BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); -+ String response = reader.readLine(); -+ -+ // close resources -+ writer.close(); -+ reader.close(); -+ -+ if (response.startsWith("ERR")) { -+ throw new IOException(response); //Throw the exception -+ } else { -+ // Is this the first update this hour? -+ if (response.contains("OK This is your first update this hour")) { -+ synchronized (graphs) { -+ Iterator iter = graphs.iterator(); -+ -+ while (iter.hasNext()) { -+ Graph graph = iter.next(); -+ -+ for (Plotter plotter : graph.getPlotters()) { -+ plotter.reset(); -+ } -+ } -+ } -+ } -+ } -+ //if (response.startsWith("OK")) - We should get "OK" followed by an optional description if everything goes right -+ } -+ -+ /** -+ * Check if mineshafter is present. If it is, we need to bypass it to send -+ * POST requests -+ * -+ * @return -+ */ -+ private boolean isMineshafterPresent() { -+ try { -+ Class.forName("mineshafter.MineServer"); -+ return true; -+ } catch (Exception e) { -+ return false; -+ } -+ } -+ -+ /** -+ *

Encode a key/value data pair to be used in a HTTP post request. This -+ * INCLUDES a & so the first key/value pair MUST be included manually, -+ * e.g:

-+ * -+ * String httpData = encode("guid") + '=' + encode("1234") + encodeDataPair("authors") + ".."; -+ * -+ * -+ * @param key -+ * @param value -+ * @return -+ */ -+ private static String encodeDataPair(String key, String value) throws UnsupportedEncodingException { -+ return '&' + encode(key) + '=' + encode(value); -+ } -+ -+ /** -+ * Encode text as UTF-8 -+ * -+ * @param text -+ * @return -+ */ -+ private static String encode(String text) throws UnsupportedEncodingException { -+ return URLEncoder.encode(text, "UTF-8"); -+ } -+ -+ /** -+ * Represents a custom graph on the website -+ */ -+ public static class Graph { -+ -+ /** -+ * The graph's name, alphanumeric and spaces only :) If it does not -+ * comply to the above when submitted, it is rejected -+ */ -+ private final String name; -+ /** -+ * The set of plotters that are contained within this graph -+ */ -+ private final Set plotters = new LinkedHashSet(); -+ -+ public Graph(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Gets the graph's name -+ * -+ * @return -+ */ -+ public String getName() { -+ return name; -+ } -+ -+ /** -+ * Add a plotter to the graph, which will be used to plot entries -+ * -+ * @param plotter -+ */ -+ public void addPlotter(Plotter plotter) { -+ plotters.add(plotter); -+ } -+ -+ /** -+ * Remove a plotter from the graph -+ * -+ * @param plotter -+ */ -+ public void removePlotter(Plotter plotter) { -+ plotters.remove(plotter); -+ } -+ -+ /** -+ * Gets an unmodifiable set of the plotter objects in the graph -+ * -+ * @return -+ */ -+ public Set getPlotters() { -+ return Collections.unmodifiableSet(plotters); -+ } -+ -+ @Override -+ public int hashCode() { -+ return name.hashCode(); -+ } -+ -+ @Override -+ public boolean equals(Object object) { -+ if (!(object instanceof Graph)) { -+ return false; -+ } -+ -+ Graph graph = (Graph) object; -+ return graph.name.equals(name); -+ } -+ } -+ -+ /** -+ * Interface used to collect custom data for a plugin -+ */ -+ public static abstract class Plotter { -+ -+ /** -+ * The plot's name -+ */ -+ private final String name; -+ -+ /** -+ * Construct a plotter with the default plot name -+ */ -+ public Plotter() { -+ this("Default"); -+ } -+ -+ /** -+ * Construct a plotter with a specific plot name -+ * -+ * @param name -+ */ -+ public Plotter(String name) { -+ this.name = name; -+ } -+ -+ /** -+ * Get the current value for the plotted point -+ * -+ * @return -+ */ -+ public abstract int getValue(); -+ -+ /** -+ * Get the column name for the plotted point -+ * -+ * @return the plotted point's column name -+ */ -+ public String getColumnName() { -+ return name; -+ } -+ -+ /** -+ * Called after the website graphs have been updated -+ */ -+ public void reset() { -+ } -+ -+ @Override -+ public int hashCode() { -+ return getColumnName().hashCode() + getValue(); -+ } -+ -+ @Override -+ public boolean equals(Object object) { -+ if (!(object instanceof Plotter)) { -+ return false; -+ } -+ -+ Plotter plotter = (Plotter) object; -+ return plotter.name.equals(name) && plotter.getValue() == getValue(); -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/TimedThread.java b/src/main/java/org/bukkit/craftbukkit/util/TimedThread.java -new file mode 100644 -index 0000000..d8d2c7c ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/TimedThread.java -@@ -0,0 +1,37 @@ -+/* -+ * To change this template, choose Tools | Templates -+ * and open the template in the editor. -+ */ -+package org.bukkit.craftbukkit.util; -+ -+public class TimedThread extends Thread { -+ -+ final Runnable runnable; -+ final long time; -+ -+ public TimedThread(Runnable runnable, long time) { -+ super("Spigot Metrics Gathering Thread"); -+ setDaemon(true); -+ this.runnable = runnable; -+ this.time = time; -+ } -+ -+ @Override -+ public void run() { -+ try { -+ sleep(60000); -+ } catch (InterruptedException ie) { -+ } -+ -+ while (!isInterrupted()) { -+ try { -+ runnable.run(); -+ sleep(time); -+ } catch (InterruptedException ie) { -+ } catch (Exception ex) { -+ ex.printStackTrace(); -+ interrupt(); -+ } -+ } -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/WatchdogThread.java b/src/main/java/org/bukkit/craftbukkit/util/WatchdogThread.java -new file mode 100644 -index 0000000..9e92ea2 ---- /dev/null -+++ b/src/main/java/org/bukkit/craftbukkit/util/WatchdogThread.java -@@ -0,0 +1,88 @@ -+package org.bukkit.craftbukkit.util; -+ -+import java.util.Iterator; -+import java.util.Map; -+import java.util.Map.Entry; -+import java.util.concurrent.atomic.AtomicLong; -+import java.util.logging.Level; -+import java.util.logging.Logger; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.CraftServer; -+ -+public class WatchdogThread extends Thread { -+ -+ private static WatchdogThread instance; -+ private static final String LINE = "------------------------------"; -+ private AtomicLong lastTick = new AtomicLong(System.currentTimeMillis()); -+ private final long timeoutTime; -+ private final boolean restart; -+ private boolean stopping; -+ -+ private WatchdogThread(long timeoutTime, boolean restart) { -+ super("Spigot Watchdog Thread"); -+ this.timeoutTime = timeoutTime; -+ this.restart = restart; -+ } -+ -+ public static void startThread(int timeoutTime, boolean restart) { -+ if (instance == null) { -+ instance = new WatchdogThread(timeoutTime * 1000L, restart); -+ instance.start(); -+ } -+ instance.stopping = false; -+ } -+ -+ public static void tick() { -+ instance.lastTick.set(System.currentTimeMillis()); -+ } -+ -+ public static void stopping() { -+ if (instance != null) { -+ instance.stopping = true; -+ } -+ } -+ -+ @Override -+ public void run() { -+ while (!this.isInterrupted()) { -+ try { -+ sleep(10000); -+ } catch (InterruptedException ignore) { -+ } -+ if (stopping) -+ continue; -+ if (System.currentTimeMillis() > (lastTick.get() + timeoutTime)) { -+ Logger log = ((CraftServer) Bukkit.getServer()).getLogger(); -+ log.log(Level.SEVERE, "The server has stopped responding!"); -+ log.log(Level.SEVERE, "Please report this to md_5!"); -+ log.log(Level.SEVERE, "Spigot version: " + Bukkit.getBukkitVersion()); -+ log.log(Level.SEVERE, "Begin Exception Trace For All Threads:"); -+ Map traces = Thread.getAllStackTraces(); -+ Iterator> i = traces.entrySet().iterator(); -+ while (i.hasNext()) { -+ Entry entry = i.next(); -+ Thread thread = entry.getKey(); -+ if (thread.getState() != State.WAITING) { -+ System.err.println(LINE); -+ -+ log.log(Level.SEVERE, "Current Thread: " + thread.getName()); -+ log.log(Level.SEVERE, " PID: " + thread.getId() + " | Alive: " + thread.isAlive() + " | State: " + thread.getState()); -+ log.log(Level.SEVERE, " Stack:"); -+ StackTraceElement[] stack = entry.getValue(); -+ for (int line = 0; line < stack.length; line++) { -+ log.log(Level.SEVERE, " " + stack[line].toString()); -+ } -+ } -+ } -+ System.err.println(LINE); -+ -+ if (this.restart) { -+ ((CraftServer) Bukkit.getServer()).restart(); -+ } -+ -+ //Give up -+ this.interrupt(); -+ } -+ } -+ } -+} -diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml -index 61a95e3..e192700 100644 ---- a/src/main/resources/configurations/bukkit.yml -+++ b/src/main/resources/configurations/bukkit.yml -@@ -25,6 +25,61 @@ settings: - query-plugins: true - deprecated-verbose: default - shutdown-message: Server closed -+ restart-script-location: start.bat -+ timeout-time: 180 -+ restart-on-crash: false -+ filter-unsafe-ips: false -+ whitelist-message: You are not white-listed on this server! -+ log-commands: true -+ command-complete: true -+ spam-exclusions: -+ - /skill -+world-settings: -+ default: -+ growth-chunks-per-tick: 650 -+ mob-spawn-range: 4 -+ item-merge-radius: 3.5 -+ exp-merge-radius: 3.5 -+ random-light-updates: false -+ aggregate-chunkticks: 4 -+ wheat-growth-modifier: 100 -+ cactus-growth-modifier: 100 -+ melon-growth-modifier: 100 -+ pumpkin-growth-modifier: 100 -+ sugar-growth-modifier: 100 -+ tree-growth-modifier: 100 -+ mushroom-growth-modifier: 100 -+ world: -+ growth-chunks-per-tick: 1000 -+ world_nether: -+ growth-chunks-per-tick: 0 -+ random-light-updates: true -+ water-creatures-per-chunk: 0 -+storm-settings: -+ strong-electrical-storm: -+ chance: 5 -+ lightning-delay: 10 -+ lightning-random-delay: 20 -+ electrical-storm: -+ chance: 15 -+ lightning-delay: 40 -+ lightning-random-delay: 150 -+ strong-thunderstorm: -+ chance: 30 -+ lightning-delay: 60 -+ lightning-random-delay: 250 -+ thunderstorm: -+ chance: 50 -+ lightning-delay: 100 -+ lightning-random-delay: 500 -+ weak-thunderstorm: -+ chance: 75 -+ lightning-delay: 300 -+ lightning-random-delay: 1000 -+ rainstorm: -+ chance: 100 -+ lightning-delay: 500 -+ lightning-random-delay: 2000 - spawn-limits: - monsters: 70 - animals: 15 --- -1.7.10.4 - diff --git a/CraftBukkit-Patches/0002-Update-Maven-Shade-Plugin-to-version-2.0.-Fixes-BUKK.patch b/CraftBukkit-Patches/0002-Update-Maven-Shade-Plugin-to-version-2.0.-Fixes-BUKK.patch index 79dc14329..a4667f0c1 100644 --- a/CraftBukkit-Patches/0002-Update-Maven-Shade-Plugin-to-version-2.0.-Fixes-BUKK.patch +++ b/CraftBukkit-Patches/0002-Update-Maven-Shade-Plugin-to-version-2.0.-Fixes-BUKK.patch @@ -1,7 +1,7 @@ -From c17687209fb0774502789624c38b5e8879fc737a Mon Sep 17 00:00:00 2001 +From 93138ab48fdb33e2b18aab7b2a6e0637477f900b Mon Sep 17 00:00:00 2001 From: Agaricus Date: Wed, 19 Dec 2012 19:13:17 -0800 -Subject: [PATCH 02/13] Update Maven Shade Plugin to version 2.0. Fixes +Subject: [PATCH 02/15] Update Maven Shade Plugin to version 2.0. Fixes BUKKIT-3213 --- @@ -9,7 +9,7 @@ Subject: [PATCH 02/13] Update Maven Shade Plugin to version 2.0. Fixes 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml -index c923f94..b1c566a 100644 +index f331d53..4540fe2 100644 --- a/pom.xml +++ b/pom.xml @@ -215,7 +215,7 @@ diff --git a/CraftBukkit-Patches/0003-Address-BUKKIT-3286-by-firing-the-inventory-close-ev.patch b/CraftBukkit-Patches/0003-Address-BUKKIT-3286-by-firing-the-inventory-close-ev.patch index 36028bb15..19aa7f82c 100644 --- a/CraftBukkit-Patches/0003-Address-BUKKIT-3286-by-firing-the-inventory-close-ev.patch +++ b/CraftBukkit-Patches/0003-Address-BUKKIT-3286-by-firing-the-inventory-close-ev.patch @@ -1,7 +1,7 @@ -From dabb132cd8dd0b5940ee7f2a1c2ff37c5239e037 Mon Sep 17 00:00:00 2001 +From ddbd99b846d93e4a9685095f908af9164ad9bfc4 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 23 Dec 2012 17:09:40 +1100 -Subject: [PATCH 03/13] Address BUKKIT-3286 by firing the inventory close event +Subject: [PATCH 03/15] Address BUKKIT-3286 by firing the inventory close event when a secondary container is closed due to the player entity being destroyed. This covers all edge cases such as server stop / player kick / player quit. diff --git a/CraftBukkit-Patches/0004-Update-item-merge-logic.patch b/CraftBukkit-Patches/0004-Update-item-merge-logic.patch index a7e442a33..10bd23d5d 100644 --- a/CraftBukkit-Patches/0004-Update-item-merge-logic.patch +++ b/CraftBukkit-Patches/0004-Update-item-merge-logic.patch @@ -1,14 +1,14 @@ -From f1b9d9c2a5d620dc7aee11722fd329cd34dcb507 Mon Sep 17 00:00:00 2001 +From 3fcd0fe549bd3a463f3903910cff8c5b767cdc8f Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 23 Dec 2012 17:51:07 +1100 -Subject: [PATCH 04/13] Update item merge logic +Subject: [PATCH 04/15] Update item merge logic --- src/main/java/net/minecraft/server/World.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index c50b814..29ccbef 100644 +index 263cbd3..6e9b13d 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -927,6 +927,7 @@ public abstract class World implements IBlockAccess { diff --git a/CraftBukkit-Patches/0005-Include-NibbleArray-from-mc-dev-for-diff-visibility.patch b/CraftBukkit-Patches/0005-Include-NibbleArray-from-mc-dev-for-diff-visibility.patch index 347f5c6e3..5ff5743ee 100644 --- a/CraftBukkit-Patches/0005-Include-NibbleArray-from-mc-dev-for-diff-visibility.patch +++ b/CraftBukkit-Patches/0005-Include-NibbleArray-from-mc-dev-for-diff-visibility.patch @@ -1,7 +1,7 @@ -From 1971336996f8ac3eccdbc631a3d271890d97fc83 Mon Sep 17 00:00:00 2001 +From 0ae8cabe89ee22f70058b76f1a2820598c30c25a Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Fri, 14 Dec 2012 21:51:06 -0600 -Subject: [PATCH 05/13] Include NibbleArray from mc-dev for diff visibility +Subject: [PATCH 05/15] Include NibbleArray from mc-dev for diff visibility --- .../java/net/minecraft/server/NibbleArray.java | 40 ++++++++++++++++++++++ diff --git a/CraftBukkit-Patches/0006-Implement-lightening-of-NibbleArrays-only-allocate-b.patch b/CraftBukkit-Patches/0006-Implement-lightening-of-NibbleArrays-only-allocate-b.patch index d5938effe..af3aac9d3 100644 --- a/CraftBukkit-Patches/0006-Implement-lightening-of-NibbleArrays-only-allocate-b.patch +++ b/CraftBukkit-Patches/0006-Implement-lightening-of-NibbleArrays-only-allocate-b.patch @@ -1,7 +1,7 @@ -From ccb92789b659c2610a7b8f23740197ed784b749a Mon Sep 17 00:00:00 2001 +From f1565b3a54d4f0b94a36ff66760478508ce00ee7 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 23 Dec 2012 14:46:23 -0600 -Subject: [PATCH 06/13] Implement 'lightening' of NibbleArrays - only allocate +Subject: [PATCH 06/15] Implement 'lightening' of NibbleArrays - only allocate buffers when non-trivial value Saving from 40-45% of memory use by chunk section data. diff --git a/CraftBukkit-Patches/0007-Return-LOHS-to-full-operation.patch b/CraftBukkit-Patches/0007-Return-LOHS-to-full-operation.patch index 43df135f7..256b6aa8b 100644 --- a/CraftBukkit-Patches/0007-Return-LOHS-to-full-operation.patch +++ b/CraftBukkit-Patches/0007-Return-LOHS-to-full-operation.patch @@ -1,7 +1,7 @@ -From cb844f20abeb6fc8a6a9f6492307c7b5ed62b765 Mon Sep 17 00:00:00 2001 +From 4456a6d332e982dad87fe1bc8d1185fe3f1ac55b Mon Sep 17 00:00:00 2001 From: md_5 Date: Mon, 7 Jan 2013 09:57:30 +1100 -Subject: [PATCH 07/13] Return LOHS to full operation. +Subject: [PATCH 07/15] Return LOHS to full operation. --- src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java | 4 ++-- diff --git a/CraftBukkit-Patches/0008-Update-timeout-time-to-new-default-value.patch b/CraftBukkit-Patches/0008-Update-timeout-time-to-new-default-value.patch index 0adcc7de3..9f97e3fdf 100644 --- a/CraftBukkit-Patches/0008-Update-timeout-time-to-new-default-value.patch +++ b/CraftBukkit-Patches/0008-Update-timeout-time-to-new-default-value.patch @@ -1,7 +1,7 @@ -From ac06044ae6bcc052df0c71fe3c7fcacef84467bc Mon Sep 17 00:00:00 2001 +From 7a538410153ecb475e4b2cc69913b132a42a035d Mon Sep 17 00:00:00 2001 From: md_5 Date: Thu, 10 Jan 2013 12:33:37 +1100 -Subject: [PATCH 08/13] Update timeout time to new default value. +Subject: [PATCH 08/15] Update timeout time to new default value. --- src/main/java/org/bukkit/craftbukkit/CraftServer.java | 9 ++++++++- diff --git a/CraftBukkit-Patches/0009-Per-world-view-distance.patch b/CraftBukkit-Patches/0009-Per-world-view-distance.patch index 332545b76..47c3442e9 100644 --- a/CraftBukkit-Patches/0009-Per-world-view-distance.patch +++ b/CraftBukkit-Patches/0009-Per-world-view-distance.patch @@ -1,7 +1,7 @@ -From 3118b5b6884ef2b1e21e87e00e14a984ef738776 Mon Sep 17 00:00:00 2001 +From 17203117557c367c378a202bf378d23ff15f685f Mon Sep 17 00:00:00 2001 From: md_5 Date: Sat, 12 Jan 2013 19:57:45 +1100 -Subject: [PATCH 09/13] Per world view distance. +Subject: [PATCH 09/15] Per world view distance. --- src/main/java/net/minecraft/server/WorldServer.java | 2 +- diff --git a/CraftBukkit-Patches/0010-Fix-various-crop-growth-modifier-formula-issues.patch b/CraftBukkit-Patches/0010-Fix-various-crop-growth-modifier-formula-issues.patch index 886f7d728..301624575 100644 --- a/CraftBukkit-Patches/0010-Fix-various-crop-growth-modifier-formula-issues.patch +++ b/CraftBukkit-Patches/0010-Fix-various-crop-growth-modifier-formula-issues.patch @@ -1,7 +1,7 @@ -From c496c06761b4bda4b215743b3cd33039aef8d5ac Mon Sep 17 00:00:00 2001 +From 31793fc6dc16c7bc26f4c23852d3af93bd62fb56 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 11 Jan 2013 11:08:45 -0500 -Subject: [PATCH 10/13] Fix various crop growth modifier formula issues +Subject: [PATCH 10/15] Fix various crop growth modifier formula issues --- src/main/java/net/minecraft/server/BlockCactus.java | 2 +- @@ -28,7 +28,7 @@ index 1cb89fa..57bedfc 100644 world.setData(i, j, k, 0); } else { diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java -index 4d3b448..815e050 100644 +index 4d3b448..b9d35ff 100644 --- a/src/main/java/net/minecraft/server/BlockCrops.java +++ b/src/main/java/net/minecraft/server/BlockCrops.java @@ -30,7 +30,7 @@ public class BlockCrops extends BlockFlower { diff --git a/CraftBukkit-Patches/0011-Fix-mob-spawn-radius-setting-so-that-its-actually-us.patch b/CraftBukkit-Patches/0011-Fix-mob-spawn-radius-setting-so-that-its-actually-us.patch index 9b3777843..7558c38be 100644 --- a/CraftBukkit-Patches/0011-Fix-mob-spawn-radius-setting-so-that-its-actually-us.patch +++ b/CraftBukkit-Patches/0011-Fix-mob-spawn-radius-setting-so-that-its-actually-us.patch @@ -1,7 +1,7 @@ -From 2600250e5c8ad99a131ef58f3180fc5c288882ed Mon Sep 17 00:00:00 2001 +From 2bb588c4a9d3dbc9f92296114a05327837b9582b Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 11 Jan 2013 14:54:51 -0500 -Subject: [PATCH 11/13] Fix mob-spawn-radius setting so that its actually +Subject: [PATCH 11/15] Fix mob-spawn-radius setting so that its actually used... --- diff --git a/CraftBukkit-Patches/0012-Add-OldChunkLoader-from-mc-dev-for-diff-visibility.patch b/CraftBukkit-Patches/0012-Add-OldChunkLoader-from-mc-dev-for-diff-visibility.patch index 9073357f1..13cee41d0 100644 --- a/CraftBukkit-Patches/0012-Add-OldChunkLoader-from-mc-dev-for-diff-visibility.patch +++ b/CraftBukkit-Patches/0012-Add-OldChunkLoader-from-mc-dev-for-diff-visibility.patch @@ -1,7 +1,7 @@ -From 7fd81ee8ece682794b2cc214b9be16506514a1e6 Mon Sep 17 00:00:00 2001 +From 86541c8411e17c01e499676640272b5d092a4ecd Mon Sep 17 00:00:00 2001 From: Agaricus Date: Sun, 13 Jan 2013 03:41:38 -0800 -Subject: [PATCH 12/13] Add OldChunkLoader from mc-dev for diff visibility +Subject: [PATCH 12/15] Add OldChunkLoader from mc-dev for diff visibility --- .../java/net/minecraft/server/OldChunkLoader.java | 120 +++++++++++++++++++++ diff --git a/CraftBukkit-Patches/0013-Fix-mcRegion-to-Anvil-conversion.patch b/CraftBukkit-Patches/0013-Fix-mcRegion-to-Anvil-conversion.patch index 9a7eb618c..ac0ff135b 100644 --- a/CraftBukkit-Patches/0013-Fix-mcRegion-to-Anvil-conversion.patch +++ b/CraftBukkit-Patches/0013-Fix-mcRegion-to-Anvil-conversion.patch @@ -1,7 +1,7 @@ -From 6d3d278b13d8909db71e87a24af672d0227a0c4c Mon Sep 17 00:00:00 2001 +From 275e28d6d1f9e99a6a11b892e2971a2717c2efea Mon Sep 17 00:00:00 2001 From: Agaricus Date: Sun, 13 Jan 2013 03:49:07 -0800 -Subject: [PATCH 13/13] Fix mcRegion-to-Anvil conversion +Subject: [PATCH 13/15] Fix mcRegion-to-Anvil conversion --- src/main/java/net/minecraft/server/OldChunkLoader.java | 8 +++++--- diff --git a/CraftBukkit-Patches/0014-Update-pom-with-Spigot-specific-info.patch b/CraftBukkit-Patches/0014-Update-pom-with-Spigot-specific-info.patch index 5559aa69f..45c847f77 100644 --- a/CraftBukkit-Patches/0014-Update-pom-with-Spigot-specific-info.patch +++ b/CraftBukkit-Patches/0014-Update-pom-with-Spigot-specific-info.patch @@ -1,7 +1,7 @@ -From 65bee98f2dc2243a21f93902ddc95b371e5f9baa Mon Sep 17 00:00:00 2001 +From 30968c177bc0abd977e69ddf6e11a1716f019609 Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 15 Jan 2013 11:48:54 +1100 -Subject: [PATCH 14/14] Update pom with Spigot specific info. +Subject: [PATCH 14/15] Update pom with Spigot specific info. --- pom.xml | 34 ++++------------------------------ diff --git a/CraftBukkit-Patches/0015-Update-versioning-check-to-correctly-resolve-api-ver.patch b/CraftBukkit-Patches/0015-Update-versioning-check-to-correctly-resolve-api-ver.patch index 864fa95ad..f2d403af6 100644 --- a/CraftBukkit-Patches/0015-Update-versioning-check-to-correctly-resolve-api-ver.patch +++ b/CraftBukkit-Patches/0015-Update-versioning-check-to-correctly-resolve-api-ver.patch @@ -1,4 +1,4 @@ -From 395e8bb758f3f666e65c3fb04e3c8e4c2f79d92c Mon Sep 17 00:00:00 2001 +From 7e1f443bfc611ee5ce828b712e2b2ad4b1c01cc8 Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 15 Jan 2013 15:05:02 +1100 Subject: [PATCH 15/15] Update versioning check to correctly resolve api