From fe18b38aea4c3f18a29b0239ab9b277def0a06cb Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 27 May 2016 21:35:28 -0400 Subject: Remove unneeded mob spawn cap patch - Fixes #235 I misread the code and thought the code kept looping until the mob spawn cap was hit. Upon furthur review, this is not true, so this patch doesn't do anything sane. --- ...pping-number-of-attempts-at-spawning-mobs.patch | 52 -- .../0134-Configurable-RCON-IP-address.patch | 23 + .../0135-Configurable-RCON-IP-address.patch | 23 - .../0135-Prevent-Fire-from-loading-chunks.patch | 49 ++ .../0136-Implement-PlayerLocaleChangeEvent.patch | 53 ++ .../0136-Prevent-Fire-from-loading-chunks.patch | 49 -- ...7-EntityRegainHealthEvent-isFastRegen-API.patch | 45 ++ .../0137-Implement-PlayerLocaleChangeEvent.patch | 53 -- ...ility-to-configure-frosted_ice-properties.patch | 48 ++ ...8-EntityRegainHealthEvent-isFastRegen-API.patch | 45 -- ...ility-to-configure-frosted_ice-properties.patch | 48 -- .../0139-Vehicle-Event-Cancellation-Changes.patch | 94 +++ .../0140-Arrow-pickup-rule-API.patch | 58 ++ .../0140-Vehicle-Event-Cancellation-Changes.patch | 94 --- .../0141-Arrow-pickup-rule-API.patch | 58 -- ...y-count-additions-and-mark-entities-remov.patch | 71 ++ ...y-count-additions-and-mark-entities-remov.patch | 71 -- ...1-Fix-dispenser-dropper-furnace-placement.patch | 55 ++ .../0143-Reimplement-PlayerEditBookEvent.patch | 89 +++ ...1-Fix-dispenser-dropper-furnace-placement.patch | 55 -- ...0144-Improve-Minecraft-Hopper-Performance.patch | 78 +++ .../0144-Reimplement-PlayerEditBookEvent.patch | 89 --- ...0145-Improve-Minecraft-Hopper-Performance.patch | 78 --- ...-null-possibility-for-getServer-singleton.patch | 39 ++ ...s-in-item-frames-performance-and-bug-fixe.patch | 149 +++++ ...-null-possibility-for-getServer-singleton.patch | 39 -- ...s-in-item-frames-performance-and-bug-fixe.patch | 149 ----- ...Table-API-Replenishable-Lootables-Feature.patch | 733 +++++++++++++++++++++ .../0148-Do-not-load-chunks-for-pathfinding.patch | 22 + ...Table-API-Replenishable-Lootables-Feature.patch | 733 --------------------- .../0149-Do-not-load-chunks-for-pathfinding.patch | 22 - .../0149-Entity-Tracking-Improvements.patch | 103 +++ ...-empty-scoreboard-teams-to-scoreboard.dat.patch | 35 + .../0150-Entity-Tracking-Improvements.patch | 103 --- ...ark-chunks-as-active-for-neighbor-updates.patch | 113 ++++ ...-empty-scoreboard-teams-to-scoreboard.dat.patch | 35 - ...ark-chunks-as-active-for-neighbor-updates.patch | 113 ---- ...unk-as-unloading-when-unload-is-cancelled.patch | 34 + ...3-System-property-for-disabling-watchdoge.patch | 22 + ...unk-as-unloading-when-unload-is-cancelled.patch | 34 - Spigot-Server-Patches/0154-Optimize-EAR.patch | 69 ++ ...4-System-property-for-disabling-watchdoge.patch | 22 - Spigot-Server-Patches/0155-Optimize-EAR.patch | 69 -- .../0155-Optimize-UserCache-Thread-Safe.patch | 100 +++ ...sure-EntityItem-loads-before-EntityPotion.patch | 33 + .../0156-Optimize-UserCache-Thread-Safe.patch | 100 --- ...void-blocking-on-Network-Manager-creation.patch | 49 ++ ...sure-EntityItem-loads-before-EntityPotion.patch | 33 - ...void-blocking-on-Network-Manager-creation.patch | 49 -- .../0158-Optional-old-TNT-cannon-behaviors.patch | 395 +++++++++++ ...Faster-redstone-torch-rapid-clock-removal.patch | 43 ++ .../0159-Optional-old-TNT-cannon-behaviors.patch | 395 ----------- ...Faster-redstone-torch-rapid-clock-removal.patch | 43 -- 53 files changed, 2602 insertions(+), 2654 deletions(-) delete mode 100644 Spigot-Server-Patches/0134-Allow-capping-number-of-attempts-at-spawning-mobs.patch create mode 100644 Spigot-Server-Patches/0134-Configurable-RCON-IP-address.patch delete mode 100644 Spigot-Server-Patches/0135-Configurable-RCON-IP-address.patch create mode 100644 Spigot-Server-Patches/0135-Prevent-Fire-from-loading-chunks.patch create mode 100644 Spigot-Server-Patches/0136-Implement-PlayerLocaleChangeEvent.patch delete mode 100644 Spigot-Server-Patches/0136-Prevent-Fire-from-loading-chunks.patch create mode 100644 Spigot-Server-Patches/0137-EntityRegainHealthEvent-isFastRegen-API.patch delete mode 100644 Spigot-Server-Patches/0137-Implement-PlayerLocaleChangeEvent.patch create mode 100644 Spigot-Server-Patches/0138-Add-ability-to-configure-frosted_ice-properties.patch delete mode 100644 Spigot-Server-Patches/0138-EntityRegainHealthEvent-isFastRegen-API.patch delete mode 100644 Spigot-Server-Patches/0139-Add-ability-to-configure-frosted_ice-properties.patch create mode 100644 Spigot-Server-Patches/0139-Vehicle-Event-Cancellation-Changes.patch create mode 100644 Spigot-Server-Patches/0140-Arrow-pickup-rule-API.patch delete mode 100644 Spigot-Server-Patches/0140-Vehicle-Event-Cancellation-Changes.patch delete mode 100644 Spigot-Server-Patches/0141-Arrow-pickup-rule-API.patch create mode 100644 Spigot-Server-Patches/0141-Check-entity-count-additions-and-mark-entities-remov.patch delete mode 100644 Spigot-Server-Patches/0142-Check-entity-count-additions-and-mark-entities-remov.patch create mode 100644 Spigot-Server-Patches/0142-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch create mode 100644 Spigot-Server-Patches/0143-Reimplement-PlayerEditBookEvent.patch delete mode 100644 Spigot-Server-Patches/0143-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch create mode 100644 Spigot-Server-Patches/0144-Improve-Minecraft-Hopper-Performance.patch delete mode 100644 Spigot-Server-Patches/0144-Reimplement-PlayerEditBookEvent.patch delete mode 100644 Spigot-Server-Patches/0145-Improve-Minecraft-Hopper-Performance.patch create mode 100644 Spigot-Server-Patches/0145-remove-null-possibility-for-getServer-singleton.patch create mode 100644 Spigot-Server-Patches/0146-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch delete mode 100644 Spigot-Server-Patches/0146-remove-null-possibility-for-getServer-singleton.patch delete mode 100644 Spigot-Server-Patches/0147-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch create mode 100644 Spigot-Server-Patches/0147-LootTable-API-Replenishable-Lootables-Feature.patch create mode 100644 Spigot-Server-Patches/0148-Do-not-load-chunks-for-pathfinding.patch delete mode 100644 Spigot-Server-Patches/0148-LootTable-API-Replenishable-Lootables-Feature.patch delete mode 100644 Spigot-Server-Patches/0149-Do-not-load-chunks-for-pathfinding.patch create mode 100644 Spigot-Server-Patches/0149-Entity-Tracking-Improvements.patch create mode 100644 Spigot-Server-Patches/0150-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch delete mode 100644 Spigot-Server-Patches/0150-Entity-Tracking-Improvements.patch create mode 100644 Spigot-Server-Patches/0151-Do-not-mark-chunks-as-active-for-neighbor-updates.patch delete mode 100644 Spigot-Server-Patches/0151-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch delete mode 100644 Spigot-Server-Patches/0152-Do-not-mark-chunks-as-active-for-neighbor-updates.patch create mode 100644 Spigot-Server-Patches/0152-Unmark-chunk-as-unloading-when-unload-is-cancelled.patch create mode 100644 Spigot-Server-Patches/0153-System-property-for-disabling-watchdoge.patch delete mode 100644 Spigot-Server-Patches/0153-Unmark-chunk-as-unloading-when-unload-is-cancelled.patch create mode 100644 Spigot-Server-Patches/0154-Optimize-EAR.patch delete mode 100644 Spigot-Server-Patches/0154-System-property-for-disabling-watchdoge.patch delete mode 100644 Spigot-Server-Patches/0155-Optimize-EAR.patch create mode 100644 Spigot-Server-Patches/0155-Optimize-UserCache-Thread-Safe.patch create mode 100644 Spigot-Server-Patches/0156-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch delete mode 100644 Spigot-Server-Patches/0156-Optimize-UserCache-Thread-Safe.patch create mode 100644 Spigot-Server-Patches/0157-Avoid-blocking-on-Network-Manager-creation.patch delete mode 100644 Spigot-Server-Patches/0157-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch delete mode 100644 Spigot-Server-Patches/0158-Avoid-blocking-on-Network-Manager-creation.patch create mode 100644 Spigot-Server-Patches/0158-Optional-old-TNT-cannon-behaviors.patch create mode 100644 Spigot-Server-Patches/0159-Faster-redstone-torch-rapid-clock-removal.patch delete mode 100644 Spigot-Server-Patches/0159-Optional-old-TNT-cannon-behaviors.patch delete mode 100644 Spigot-Server-Patches/0160-Faster-redstone-torch-rapid-clock-removal.patch diff --git a/Spigot-Server-Patches/0134-Allow-capping-number-of-attempts-at-spawning-mobs.patch b/Spigot-Server-Patches/0134-Allow-capping-number-of-attempts-at-spawning-mobs.patch deleted file mode 100644 index a9e56310a4..0000000000 --- a/Spigot-Server-Patches/0134-Allow-capping-number-of-attempts-at-spawning-mobs.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 665309dc76ad50bb5c79f50fcbf48cdcf5bc92f4 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 15 Apr 2016 21:27:14 -0400 -Subject: [PATCH] Allow capping number of attempts at spawning mobs - -By default, this logic would loop endlessly trying to fill the world -with entities until it hits the worlds spawn. - -This patch will cap the # of attempts to so that the tick does not spend -extra long time on mob spawning - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 6a235d1..d470e75 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -320,4 +320,18 @@ public class PaperWorldConfig { - private void useVanillaScoreboardColoring() { - useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false); - } -+ -+ public int maxMobSpawnAttempts; -+ private void maxMobSpawnAttempts() { -+ maxMobSpawnAttempts = getInt("max-mob-spawn-attempts", 250); -+ log( "Max Mob Spawn Attempts: " + maxMobSpawnAttempts); -+ if (maxMobSpawnAttempts < 0) { -+ maxMobSpawnAttempts = Integer.MAX_VALUE; -+ } else { -+ if (maxMobSpawnAttempts < 250 && PaperConfig.version < 10) { -+ set("max-mob-spawn-attempts", 250); -+ maxMobSpawnAttempts = 250; -+ } -+ } -+ } - } -diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java -index a034db2..113a372 100644 ---- a/src/main/java/net/minecraft/server/SpawnerCreature.java -+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java -@@ -140,8 +140,9 @@ public final class SpawnerCreature { - Iterator iterator1 = this.b.iterator(); - - int moblimit = (limit * i / 256) - mobcnt + 1; // Spigot - up to 1 more than limit -+ int maxMobSpawnAttempts = worldserver.paperConfig.maxMobSpawnAttempts; // Paper - max attempts - label120: -- while (iterator1.hasNext() && (moblimit > 0)) { // Spigot - while more allowed -+ while (iterator1.hasNext() && (moblimit > 0) && maxMobSpawnAttempts-- > 0) { // Spigot - while more allowed // Paper - max attempts - // CraftBukkit start = use LongHash and LongObjectHashMap - long key = ((Long) iterator1.next()).longValue(); - BlockPosition blockposition1 = getRandomPosition(worldserver, LongHash.msw(key), LongHash.lsw(key)); --- -2.8.2 - diff --git a/Spigot-Server-Patches/0134-Configurable-RCON-IP-address.patch b/Spigot-Server-Patches/0134-Configurable-RCON-IP-address.patch new file mode 100644 index 0000000000..cb1969572f --- /dev/null +++ b/Spigot-Server-Patches/0134-Configurable-RCON-IP-address.patch @@ -0,0 +1,23 @@ +From b068d063f98eb23fa58eda1e26f9874ba159a304 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 16 Apr 2016 00:39:33 -0400 +Subject: [PATCH] Configurable RCON IP address + +For servers with multiple IP's, ability to bind to a specific interface. + +diff --git a/src/main/java/net/minecraft/server/RemoteControlListener.java b/src/main/java/net/minecraft/server/RemoteControlListener.java +index 8309a99..3a6561a 100644 +--- a/src/main/java/net/minecraft/server/RemoteControlListener.java ++++ b/src/main/java/net/minecraft/server/RemoteControlListener.java +@@ -24,7 +24,7 @@ public class RemoteControlListener extends RemoteConnectionThread { + super(iminecraftserver, "RCON Listener"); + this.h = iminecraftserver.a("rcon.port", 0); + this.l = iminecraftserver.a("rcon.password", ""); +- this.j = iminecraftserver.d_(); ++ this.j = iminecraftserver.a("rcon.ip", iminecraftserver.d_()); // Paper + this.i = iminecraftserver.e_(); + if (0 == this.h) { + this.h = this.i + 10; +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0135-Configurable-RCON-IP-address.patch b/Spigot-Server-Patches/0135-Configurable-RCON-IP-address.patch deleted file mode 100644 index ac162325df..0000000000 --- a/Spigot-Server-Patches/0135-Configurable-RCON-IP-address.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 6af571f68b3d32ada3218e9406e09087329afe9c Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 16 Apr 2016 00:39:33 -0400 -Subject: [PATCH] Configurable RCON IP address - -For servers with multiple IP's, ability to bind to a specific interface. - -diff --git a/src/main/java/net/minecraft/server/RemoteControlListener.java b/src/main/java/net/minecraft/server/RemoteControlListener.java -index 8309a99..3a6561a 100644 ---- a/src/main/java/net/minecraft/server/RemoteControlListener.java -+++ b/src/main/java/net/minecraft/server/RemoteControlListener.java -@@ -24,7 +24,7 @@ public class RemoteControlListener extends RemoteConnectionThread { - super(iminecraftserver, "RCON Listener"); - this.h = iminecraftserver.a("rcon.port", 0); - this.l = iminecraftserver.a("rcon.password", ""); -- this.j = iminecraftserver.d_(); -+ this.j = iminecraftserver.a("rcon.ip", iminecraftserver.d_()); // Paper - this.i = iminecraftserver.e_(); - if (0 == this.h) { - this.h = this.i + 10; --- -2.8.2 - diff --git a/Spigot-Server-Patches/0135-Prevent-Fire-from-loading-chunks.patch b/Spigot-Server-Patches/0135-Prevent-Fire-from-loading-chunks.patch new file mode 100644 index 0000000000..8f742e47a7 --- /dev/null +++ b/Spigot-Server-Patches/0135-Prevent-Fire-from-loading-chunks.patch @@ -0,0 +1,49 @@ +From 6869070acce7a2ed7a821bb157c34db70de22c6c Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 17 Apr 2016 17:27:09 -0400 +Subject: [PATCH] Prevent Fire from loading chunks + +This causes the nether to spam unload/reload chunks, plus overall +bad behavior. + +diff --git a/src/main/java/net/minecraft/server/BlockFire.java b/src/main/java/net/minecraft/server/BlockFire.java +index cb11099..951f0cf 100644 +--- a/src/main/java/net/minecraft/server/BlockFire.java ++++ b/src/main/java/net/minecraft/server/BlockFire.java +@@ -162,6 +162,7 @@ public class BlockFire extends Block { + } + + BlockPosition blockposition1 = blockposition.a(j, l, k); ++ if (!world.isLoaded(blockposition1)) continue; // Paper + int j1 = this.d(world, blockposition1); + + if (j1 > 0) { +@@ -230,10 +231,12 @@ public class BlockFire extends Block { + } + + private void a(World world, BlockPosition blockposition, int i, Random random, int j) { +- int k = this.c(world.getType(blockposition).getBlock()); ++ final IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // Paper ++ if (iblockdata == null) return; // Paper ++ int k = this.c(iblockdata.getBlock()); // Paper + + if (random.nextInt(i) < k) { +- IBlockData iblockdata = world.getType(blockposition); ++ //IBlockData iblockdata = world.getType(blockposition); // Paper + + // CraftBukkit start + org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); +@@ -291,7 +294,9 @@ public class BlockFire extends Block { + for (int k = 0; k < j; ++k) { + EnumDirection enumdirection = aenumdirection[k]; + +- i = Math.max(this.d(world.getType(blockposition.shift(enumdirection)).getBlock()), i); ++ final IBlockData type = world.getTypeIfLoaded(blockposition.shift(enumdirection)); // Paper ++ if (type == null) continue; // Paper ++ i = Math.max(this.d(type.getBlock()), i); // Paper + } + + return i; +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0136-Implement-PlayerLocaleChangeEvent.patch b/Spigot-Server-Patches/0136-Implement-PlayerLocaleChangeEvent.patch new file mode 100644 index 0000000000..14e248056a --- /dev/null +++ b/Spigot-Server-Patches/0136-Implement-PlayerLocaleChangeEvent.patch @@ -0,0 +1,53 @@ +From 94406909cbd42e589bd2380c3de9d308fa53c9df Mon Sep 17 00:00:00 2001 +From: Isaac Moore +Date: Tue, 19 Apr 2016 14:09:31 -0500 +Subject: [PATCH] Implement PlayerLocaleChangeEvent + + +diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java +index 723d40c..44df116 100644 +--- a/src/main/java/net/minecraft/server/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/EntityPlayer.java +@@ -26,7 +26,7 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + public class EntityPlayer extends EntityHuman implements ICrafting { + + private static final Logger bR = LogManager.getLogger(); +- public String locale = "en_US"; // Spigot private -> public ++ public String locale = null; // Spigot private -> public // Paper - default to null + public PlayerConnection playerConnection; + public final MinecraftServer server; + public final PlayerInteractManager playerInteractManager; +@@ -1073,7 +1073,14 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + } + + public void a(PacketPlayInSettings packetplayinsettings) { ++ // Paper start - add PlayerLocaleChangeEvent ++ // Since the field is initialized to null, this event should always fire the first time the packet is received ++ String oldLocale = this.locale; + this.locale = packetplayinsettings.a(); ++ if (!this.locale.equals(oldLocale)) { ++ new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), oldLocale, this.locale).callEvent(); ++ } ++ // Paper end + this.cg = packetplayinsettings.c(); + this.ch = packetplayinsettings.d(); + this.getDataWatcher().set(EntityPlayer.bq, Byte.valueOf((byte) packetplayinsettings.e())); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 7568fc8..d23cade 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1657,7 +1657,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + @Override + public String getLocale() + { +- return getHandle().locale; ++ // Paper start - Locale change event ++ final String locale = getHandle().locale; ++ return locale != null ? locale : "en_US"; ++ // Paper end + } + + @Override +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0136-Prevent-Fire-from-loading-chunks.patch b/Spigot-Server-Patches/0136-Prevent-Fire-from-loading-chunks.patch deleted file mode 100644 index 72b5a939a4..0000000000 --- a/Spigot-Server-Patches/0136-Prevent-Fire-from-loading-chunks.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 24a5d2b07f91ca93ea021402ebbd2c51bc2010b1 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 17 Apr 2016 17:27:09 -0400 -Subject: [PATCH] Prevent Fire from loading chunks - -This causes the nether to spam unload/reload chunks, plus overall -bad behavior. - -diff --git a/src/main/java/net/minecraft/server/BlockFire.java b/src/main/java/net/minecraft/server/BlockFire.java -index cb11099..951f0cf 100644 ---- a/src/main/java/net/minecraft/server/BlockFire.java -+++ b/src/main/java/net/minecraft/server/BlockFire.java -@@ -162,6 +162,7 @@ public class BlockFire extends Block { - } - - BlockPosition blockposition1 = blockposition.a(j, l, k); -+ if (!world.isLoaded(blockposition1)) continue; // Paper - int j1 = this.d(world, blockposition1); - - if (j1 > 0) { -@@ -230,10 +231,12 @@ public class BlockFire extends Block { - } - - private void a(World world, BlockPosition blockposition, int i, Random random, int j) { -- int k = this.c(world.getType(blockposition).getBlock()); -+ final IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // Paper -+ if (iblockdata == null) return; // Paper -+ int k = this.c(iblockdata.getBlock()); // Paper - - if (random.nextInt(i) < k) { -- IBlockData iblockdata = world.getType(blockposition); -+ //IBlockData iblockdata = world.getType(blockposition); // Paper - - // CraftBukkit start - org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); -@@ -291,7 +294,9 @@ public class BlockFire extends Block { - for (int k = 0; k < j; ++k) { - EnumDirection enumdirection = aenumdirection[k]; - -- i = Math.max(this.d(world.getType(blockposition.shift(enumdirection)).getBlock()), i); -+ final IBlockData type = world.getTypeIfLoaded(blockposition.shift(enumdirection)); // Paper -+ if (type == null) continue; // Paper -+ i = Math.max(this.d(type.getBlock()), i); // Paper - } - - return i; --- -2.8.2 - diff --git a/Spigot-Server-Patches/0137-EntityRegainHealthEvent-isFastRegen-API.patch b/Spigot-Server-Patches/0137-EntityRegainHealthEvent-isFastRegen-API.patch new file mode 100644 index 0000000000..db672afcbb --- /dev/null +++ b/Spigot-Server-Patches/0137-EntityRegainHealthEvent-isFastRegen-API.patch @@ -0,0 +1,45 @@ +From 34d571332952449b1187a9afe61f565ac0575944 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Fri, 22 Apr 2016 01:43:11 -0500 +Subject: [PATCH] EntityRegainHealthEvent isFastRegen API + +Don't even get me started + +diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java +index df4d8d8..129bca8 100644 +--- a/src/main/java/net/minecraft/server/EntityLiving.java ++++ b/src/main/java/net/minecraft/server/EntityLiving.java +@@ -734,10 +734,16 @@ public abstract class EntityLiving extends Entity { + } + + public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) { ++ // Paper start - Forward ++ heal(f, regainReason, false); ++ } ++ ++ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) { ++ // Paper end + float f1 = this.getHealth(); + + if (f1 > 0.0F) { +- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason); ++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper - Add isFastRegen + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +diff --git a/src/main/java/net/minecraft/server/FoodMetaData.java b/src/main/java/net/minecraft/server/FoodMetaData.java +index df5fbeb..ebadb37 100644 +--- a/src/main/java/net/minecraft/server/FoodMetaData.java ++++ b/src/main/java/net/minecraft/server/FoodMetaData.java +@@ -65,7 +65,7 @@ public class FoodMetaData { + if (this.foodTickTimer >= 10) { + float f = Math.min(this.saturationLevel, 4.0F); + +- entityhuman.heal(f / 4.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason ++ entityhuman.heal(f / 4.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen + this.a(f); + this.foodTickTimer = 0; + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0137-Implement-PlayerLocaleChangeEvent.patch b/Spigot-Server-Patches/0137-Implement-PlayerLocaleChangeEvent.patch deleted file mode 100644 index 00a0e35abd..0000000000 --- a/Spigot-Server-Patches/0137-Implement-PlayerLocaleChangeEvent.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 36de0ebaee44a6c862e91ce02328130379638d41 Mon Sep 17 00:00:00 2001 -From: Isaac Moore -Date: Tue, 19 Apr 2016 14:09:31 -0500 -Subject: [PATCH] Implement PlayerLocaleChangeEvent - - -diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java -index 723d40c..44df116 100644 ---- a/src/main/java/net/minecraft/server/EntityPlayer.java -+++ b/src/main/java/net/minecraft/server/EntityPlayer.java -@@ -26,7 +26,7 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - public class EntityPlayer extends EntityHuman implements ICrafting { - - private static final Logger bR = LogManager.getLogger(); -- public String locale = "en_US"; // Spigot private -> public -+ public String locale = null; // Spigot private -> public // Paper - default to null - public PlayerConnection playerConnection; - public final MinecraftServer server; - public final PlayerInteractManager playerInteractManager; -@@ -1073,7 +1073,14 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - } - - public void a(PacketPlayInSettings packetplayinsettings) { -+ // Paper start - add PlayerLocaleChangeEvent -+ // Since the field is initialized to null, this event should always fire the first time the packet is received -+ String oldLocale = this.locale; - this.locale = packetplayinsettings.a(); -+ if (!this.locale.equals(oldLocale)) { -+ new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), oldLocale, this.locale).callEvent(); -+ } -+ // Paper end - this.cg = packetplayinsettings.c(); - this.ch = packetplayinsettings.d(); - this.getDataWatcher().set(EntityPlayer.bq, Byte.valueOf((byte) packetplayinsettings.e())); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 7568fc8..d23cade 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1657,7 +1657,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - @Override - public String getLocale() - { -- return getHandle().locale; -+ // Paper start - Locale change event -+ final String locale = getHandle().locale; -+ return locale != null ? locale : "en_US"; -+ // Paper end - } - - @Override --- -2.8.2 - diff --git a/Spigot-Server-Patches/0138-Add-ability-to-configure-frosted_ice-properties.patch b/Spigot-Server-Patches/0138-Add-ability-to-configure-frosted_ice-properties.patch new file mode 100644 index 0000000000..125c6f4b6e --- /dev/null +++ b/Spigot-Server-Patches/0138-Add-ability-to-configure-frosted_ice-properties.patch @@ -0,0 +1,48 @@ +From 928b12e8cc7000f5cd8cb3cb4a2ef5efce65798e Mon Sep 17 00:00:00 2001 +From: kashike +Date: Thu, 21 Apr 2016 23:51:55 -0700 +Subject: [PATCH] Add ability to configure frosted_ice properties + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 6a235d1..cc307c4 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -320,4 +320,14 @@ public class PaperWorldConfig { + private void useVanillaScoreboardColoring() { + useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false); + } ++ ++ public boolean frostedIceEnabled = true; ++ public int frostedIceDelayMin = 20; ++ public int frostedIceDelayMax = 40; ++ private void frostedIce() { ++ this.frostedIceEnabled = this.getBoolean("frosted-ice.enabled", this.frostedIceEnabled); ++ this.frostedIceDelayMin = this.getInt("frosted-ice.delay.min", this.frostedIceDelayMin); ++ this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); ++ this.log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); ++ } + } +diff --git a/src/main/java/net/minecraft/server/BlockIceFrost.java b/src/main/java/net/minecraft/server/BlockIceFrost.java +index 8f502b9..bddfea0 100644 +--- a/src/main/java/net/minecraft/server/BlockIceFrost.java ++++ b/src/main/java/net/minecraft/server/BlockIceFrost.java +@@ -20,10 +20,14 @@ public class BlockIceFrost extends BlockIce { + } + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { ++ if (!world.paperConfig.frostedIceEnabled) return; // Paper - add ability to disable frosted ice + if ((random.nextInt(3) == 0 || this.c(world, blockposition) < 4) && world.getLightLevel(blockposition) > 11 - ((Integer) iblockdata.get(BlockIceFrost.a)).intValue() - iblockdata.c()) { + this.a(world, blockposition, iblockdata, random, true); + } else { +- world.a(blockposition, (Block) this, MathHelper.nextInt(random, 20, 40)); ++ // Paper start - use configurable min/max delay ++ //world.a(blockposition, (Block) this, MathHelper.nextInt(random, 20, 40)); ++ world.a(blockposition, this, MathHelper.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); ++ // Paper end + } + + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0138-EntityRegainHealthEvent-isFastRegen-API.patch b/Spigot-Server-Patches/0138-EntityRegainHealthEvent-isFastRegen-API.patch deleted file mode 100644 index 0196affd87..0000000000 --- a/Spigot-Server-Patches/0138-EntityRegainHealthEvent-isFastRegen-API.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 2ecdfc5475eb3774493dbfc05aee7822b79b2333 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Fri, 22 Apr 2016 01:43:11 -0500 -Subject: [PATCH] EntityRegainHealthEvent isFastRegen API - -Don't even get me started - -diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java -index df4d8d8..129bca8 100644 ---- a/src/main/java/net/minecraft/server/EntityLiving.java -+++ b/src/main/java/net/minecraft/server/EntityLiving.java -@@ -734,10 +734,16 @@ public abstract class EntityLiving extends Entity { - } - - public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) { -+ // Paper start - Forward -+ heal(f, regainReason, false); -+ } -+ -+ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) { -+ // Paper end - float f1 = this.getHealth(); - - if (f1 > 0.0F) { -- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason); -+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper - Add isFastRegen - this.world.getServer().getPluginManager().callEvent(event); - - if (!event.isCancelled()) { -diff --git a/src/main/java/net/minecraft/server/FoodMetaData.java b/src/main/java/net/minecraft/server/FoodMetaData.java -index df5fbeb..ebadb37 100644 ---- a/src/main/java/net/minecraft/server/FoodMetaData.java -+++ b/src/main/java/net/minecraft/server/FoodMetaData.java -@@ -65,7 +65,7 @@ public class FoodMetaData { - if (this.foodTickTimer >= 10) { - float f = Math.min(this.saturationLevel, 4.0F); - -- entityhuman.heal(f / 4.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason -+ entityhuman.heal(f / 4.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen - this.a(f); - this.foodTickTimer = 0; - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0139-Add-ability-to-configure-frosted_ice-properties.patch b/Spigot-Server-Patches/0139-Add-ability-to-configure-frosted_ice-properties.patch deleted file mode 100644 index 919debbcd2..0000000000 --- a/Spigot-Server-Patches/0139-Add-ability-to-configure-frosted_ice-properties.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 40dda2d897571e1d1bbc27d767096ba0ac6c0ffd Mon Sep 17 00:00:00 2001 -From: kashike -Date: Thu, 21 Apr 2016 23:51:55 -0700 -Subject: [PATCH] Add ability to configure frosted_ice properties - - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index d470e75..ccc11a8 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -334,4 +334,14 @@ public class PaperWorldConfig { - } - } - } -+ -+ public boolean frostedIceEnabled = true; -+ public int frostedIceDelayMin = 20; -+ public int frostedIceDelayMax = 40; -+ private void frostedIce() { -+ this.frostedIceEnabled = this.getBoolean("frosted-ice.enabled", this.frostedIceEnabled); -+ this.frostedIceDelayMin = this.getInt("frosted-ice.delay.min", this.frostedIceDelayMin); -+ this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); -+ this.log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); -+ } - } -diff --git a/src/main/java/net/minecraft/server/BlockIceFrost.java b/src/main/java/net/minecraft/server/BlockIceFrost.java -index 8f502b9..bddfea0 100644 ---- a/src/main/java/net/minecraft/server/BlockIceFrost.java -+++ b/src/main/java/net/minecraft/server/BlockIceFrost.java -@@ -20,10 +20,14 @@ public class BlockIceFrost extends BlockIce { - } - - public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { -+ if (!world.paperConfig.frostedIceEnabled) return; // Paper - add ability to disable frosted ice - if ((random.nextInt(3) == 0 || this.c(world, blockposition) < 4) && world.getLightLevel(blockposition) > 11 - ((Integer) iblockdata.get(BlockIceFrost.a)).intValue() - iblockdata.c()) { - this.a(world, blockposition, iblockdata, random, true); - } else { -- world.a(blockposition, (Block) this, MathHelper.nextInt(random, 20, 40)); -+ // Paper start - use configurable min/max delay -+ //world.a(blockposition, (Block) this, MathHelper.nextInt(random, 20, 40)); -+ world.a(blockposition, this, MathHelper.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); -+ // Paper end - } - - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0139-Vehicle-Event-Cancellation-Changes.patch b/Spigot-Server-Patches/0139-Vehicle-Event-Cancellation-Changes.patch new file mode 100644 index 0000000000..a73b6c1723 --- /dev/null +++ b/Spigot-Server-Patches/0139-Vehicle-Event-Cancellation-Changes.patch @@ -0,0 +1,94 @@ +From 7c0576f1a381b34355c782f0cb34303143d7ca98 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Fri, 22 Apr 2016 18:20:05 -0500 +Subject: [PATCH] Vehicle Event Cancellation Changes + + +diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java +index b2dc764..2374a35 100644 +--- a/src/main/java/net/minecraft/server/Entity.java ++++ b/src/main/java/net/minecraft/server/Entity.java +@@ -1658,6 +1658,10 @@ public abstract class Entity implements ICommandListener { + } + + public boolean a(Entity entity, boolean flag) { ++ return this.mountEntity(entity, flag, false); // Paper - forward ++ } ++ ++ public boolean mountEntity(Entity entity, boolean flag, boolean suppressEvents) { // Paper + if (!flag && (!this.n(entity) || !entity.q(this))) { + return false; + } else { +@@ -1666,7 +1670,7 @@ public abstract class Entity implements ICommandListener { + } + + this.at = entity; +- this.at.o(this); ++ this.at.addRider(this, suppressEvents); // Paper + return true; + } + } +@@ -1693,12 +1697,20 @@ public abstract class Entity implements ICommandListener { + } + + protected void o(Entity entity) { ++ // Paper start - Forward ++ this.addRider(entity, false); ++ } ++ ++ private void addRider(Entity entity, boolean suppressEvents) { ++ // Paper end + if (entity.bz() != this) { + throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)"); + } else { + // CraftBukkit start + com.google.common.base.Preconditions.checkState(!entity.passengers.contains(this), "Circular entity riding! %s %s", this, entity); + ++ if (!suppressEvents) { // Paper - Make event calls suppressible ++ // ============================================================= + CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle(); + Entity orig = craft == null ? null : craft.getHandle(); + if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, false)) { // Boolean not used +@@ -1721,6 +1733,8 @@ public abstract class Entity implements ICommandListener { + return; + } + // Spigot end ++ // ============================================================= ++ } // Paper - end suppressible block + if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.bu() instanceof EntityHuman)) { + this.passengers.add(0, entity); + } else { +@@ -1746,16 +1760,29 @@ public abstract class Entity implements ICommandListener { + CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle(); + Entity n = craftn == null ? null : craftn.getHandle(); + if (event.isCancelled() || n != orig) { ++ this.cancelDismount(entity); // Paper + return; + } + } + // CraftBukkit end +- Bukkit.getPluginManager().callEvent( new org.spigotmc.event.entity.EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity())); // Spigot ++ // Paper start - make EntityDismountEvent cancellable ++ if (!new org.spigotmc.event.entity.EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity()).callEvent()) { ++ this.cancelDismount(entity); ++ return; ++ } ++ // Paper end + this.passengers.remove(entity); + entity.j = 60; + } + } + ++ // Paper start ++ private void cancelDismount(Entity dismounter) { ++ this.passengers.remove(dismounter); ++ dismounter.mountEntity(this, false, true); ++ } ++ // Paper end ++ + protected boolean q(Entity entity) { + return this.bv().size() < 1; + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0140-Arrow-pickup-rule-API.patch b/Spigot-Server-Patches/0140-Arrow-pickup-rule-API.patch new file mode 100644 index 0000000000..7ffd355f9a --- /dev/null +++ b/Spigot-Server-Patches/0140-Arrow-pickup-rule-API.patch @@ -0,0 +1,58 @@ +From 7fa53b55160cf63907e2ff84cf3ed9e1783882af Mon Sep 17 00:00:00 2001 +From: Jedediah Smith +Date: Fri, 4 Mar 2016 03:16:11 -0500 +Subject: [PATCH] Arrow pickup rule API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +index 2a3482c..fbf289f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +@@ -72,6 +72,44 @@ public class CraftArrow extends AbstractProjectile implements Arrow { + getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); + } + ++ // Paper start ++ @Override ++ public PickupRule getPickupRule() { ++ return convertPickupRule(this.getHandle().fromPlayer); ++ } ++ ++ @Override ++ public void setPickupRule(PickupRule rule) { ++ this.getHandle().fromPlayer = convertPickupRule(rule); ++ } ++ ++ public static PickupRule convertPickupRule(EntityArrow.PickupStatus nms) { ++ switch (nms) { ++ case DISALLOWED: ++ return PickupRule.DISALLOWED; ++ case ALLOWED: ++ return PickupRule.ALLOWED; ++ case CREATIVE_ONLY: ++ return PickupRule.CREATIVE_ONLY; ++ default: ++ throw new IllegalStateException(); ++ } ++ } ++ ++ public static EntityArrow.PickupStatus convertPickupRule(PickupRule bukkit) { ++ switch (bukkit) { ++ case DISALLOWED: ++ return EntityArrow.PickupStatus.DISALLOWED; ++ case ALLOWED: ++ return EntityArrow.PickupStatus.ALLOWED; ++ case CREATIVE_ONLY: ++ return EntityArrow.PickupStatus.CREATIVE_ONLY; ++ default: ++ throw new IllegalStateException(); ++ } ++ } ++ // Paper end ++ + // Spigot start + private final Arrow.Spigot spigot = new Arrow.Spigot() + { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0140-Vehicle-Event-Cancellation-Changes.patch b/Spigot-Server-Patches/0140-Vehicle-Event-Cancellation-Changes.patch deleted file mode 100644 index 93f035051e..0000000000 --- a/Spigot-Server-Patches/0140-Vehicle-Event-Cancellation-Changes.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 76ee96877676bceaed80df78b73f2a327b8573c6 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Fri, 22 Apr 2016 18:20:05 -0500 -Subject: [PATCH] Vehicle Event Cancellation Changes - - -diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index b2dc764..2374a35 100644 ---- a/src/main/java/net/minecraft/server/Entity.java -+++ b/src/main/java/net/minecraft/server/Entity.java -@@ -1658,6 +1658,10 @@ public abstract class Entity implements ICommandListener { - } - - public boolean a(Entity entity, boolean flag) { -+ return this.mountEntity(entity, flag, false); // Paper - forward -+ } -+ -+ public boolean mountEntity(Entity entity, boolean flag, boolean suppressEvents) { // Paper - if (!flag && (!this.n(entity) || !entity.q(this))) { - return false; - } else { -@@ -1666,7 +1670,7 @@ public abstract class Entity implements ICommandListener { - } - - this.at = entity; -- this.at.o(this); -+ this.at.addRider(this, suppressEvents); // Paper - return true; - } - } -@@ -1693,12 +1697,20 @@ public abstract class Entity implements ICommandListener { - } - - protected void o(Entity entity) { -+ // Paper start - Forward -+ this.addRider(entity, false); -+ } -+ -+ private void addRider(Entity entity, boolean suppressEvents) { -+ // Paper end - if (entity.bz() != this) { - throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)"); - } else { - // CraftBukkit start - com.google.common.base.Preconditions.checkState(!entity.passengers.contains(this), "Circular entity riding! %s %s", this, entity); - -+ if (!suppressEvents) { // Paper - Make event calls suppressible -+ // ============================================================= - CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle(); - Entity orig = craft == null ? null : craft.getHandle(); - if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, false)) { // Boolean not used -@@ -1721,6 +1733,8 @@ public abstract class Entity implements ICommandListener { - return; - } - // Spigot end -+ // ============================================================= -+ } // Paper - end suppressible block - if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.bu() instanceof EntityHuman)) { - this.passengers.add(0, entity); - } else { -@@ -1746,16 +1760,29 @@ public abstract class Entity implements ICommandListener { - CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle(); - Entity n = craftn == null ? null : craftn.getHandle(); - if (event.isCancelled() || n != orig) { -+ this.cancelDismount(entity); // Paper - return; - } - } - // CraftBukkit end -- Bukkit.getPluginManager().callEvent( new org.spigotmc.event.entity.EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity())); // Spigot -+ // Paper start - make EntityDismountEvent cancellable -+ if (!new org.spigotmc.event.entity.EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity()).callEvent()) { -+ this.cancelDismount(entity); -+ return; -+ } -+ // Paper end - this.passengers.remove(entity); - entity.j = 60; - } - } - -+ // Paper start -+ private void cancelDismount(Entity dismounter) { -+ this.passengers.remove(dismounter); -+ dismounter.mountEntity(this, false, true); -+ } -+ // Paper end -+ - protected boolean q(Entity entity) { - return this.bv().size() < 1; - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0141-Arrow-pickup-rule-API.patch b/Spigot-Server-Patches/0141-Arrow-pickup-rule-API.patch deleted file mode 100644 index 34cb2f84c7..0000000000 --- a/Spigot-Server-Patches/0141-Arrow-pickup-rule-API.patch +++ /dev/null @@ -1,58 +0,0 @@ -From bb373b3b0dad597e4f58085441298a085988ec94 Mon Sep 17 00:00:00 2001 -From: Jedediah Smith -Date: Fri, 4 Mar 2016 03:16:11 -0500 -Subject: [PATCH] Arrow pickup rule API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -index 2a3482c..fbf289f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -@@ -72,6 +72,44 @@ public class CraftArrow extends AbstractProjectile implements Arrow { - getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); - } - -+ // Paper start -+ @Override -+ public PickupRule getPickupRule() { -+ return convertPickupRule(this.getHandle().fromPlayer); -+ } -+ -+ @Override -+ public void setPickupRule(PickupRule rule) { -+ this.getHandle().fromPlayer = convertPickupRule(rule); -+ } -+ -+ public static PickupRule convertPickupRule(EntityArrow.PickupStatus nms) { -+ switch (nms) { -+ case DISALLOWED: -+ return PickupRule.DISALLOWED; -+ case ALLOWED: -+ return PickupRule.ALLOWED; -+ case CREATIVE_ONLY: -+ return PickupRule.CREATIVE_ONLY; -+ default: -+ throw new IllegalStateException(); -+ } -+ } -+ -+ public static EntityArrow.PickupStatus convertPickupRule(PickupRule bukkit) { -+ switch (bukkit) { -+ case DISALLOWED: -+ return EntityArrow.PickupStatus.DISALLOWED; -+ case ALLOWED: -+ return EntityArrow.PickupStatus.ALLOWED; -+ case CREATIVE_ONLY: -+ return EntityArrow.PickupStatus.CREATIVE_ONLY; -+ default: -+ throw new IllegalStateException(); -+ } -+ } -+ // Paper end -+ - // Spigot start - private final Arrow.Spigot spigot = new Arrow.Spigot() - { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0141-Check-entity-count-additions-and-mark-entities-remov.patch b/Spigot-Server-Patches/0141-Check-entity-count-additions-and-mark-entities-remov.patch new file mode 100644 index 0000000000..170531fa0a --- /dev/null +++ b/Spigot-Server-Patches/0141-Check-entity-count-additions-and-mark-entities-remov.patch @@ -0,0 +1,71 @@ +From a02b0089dead6bcbc2103c847cc067855b6aef72 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Fri, 22 Apr 2016 20:34:21 -0500 +Subject: [PATCH] Check entity count additions and mark entities removed + + +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index b94cdad..904141a 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -631,12 +631,36 @@ public class Chunk { + k = this.entitySlices.length - 1; + } + ++ // Paper start - Try to catch plugins doing indecent things ++ boolean ignoreAdd = false; ++ if (entity.aa && entity.getChunkX() == this.locX && entity.getChunkY() == k && entity.getChunkZ() == this.locZ) { ++ String chunkName = entity.getWorld().getWorld().getName() + ":" + entity.getChunkX() + "," + entity.getChunkY() + "," + entity.getChunkZ(); ++ if (this.entitySlices[k].contains(entity)) { ++ new Throwable("Double Chunk Add to: " + chunkName).printStackTrace(); ++ ignoreAdd = true; ++ } else { ++ boolean found = false; ++ for (int i1 = 0; i1 < this.entitySlices.length; i1++) { ++ if (this.entitySlices[i1].contains(entity)) { ++ new Throwable("Entity was found in another slice of this chunk, tried: " + k + ", was in: " + chunkName).printStackTrace(); ++ found = true; ++ ignoreAdd = true; ++ } ++ } ++ if (!found) { ++ new Throwable("Improperly detected double chunk add. Was not actually in this chunk.").printStackTrace(); ++ } ++ } ++ } ++ // Paper end ++ + entity.aa = true; + entity.ab = this.locX; + entity.ac = k; + entity.ad = this.locZ; + this.entitySlices[k].add(entity); + // Paper start - update count ++ if (ignoreAdd) return; + if (entity instanceof EntityItem) { + itemCounts[k]++; + } else if (entity instanceof IInventory) { +@@ -681,6 +705,7 @@ public class Chunk { + } else if (entity instanceof IInventory) { + inventoryEntityCounts[i]--; + } ++ entity.aa = false; // You aren't added to chunk anymore + // Paper end + // Spigot start - decrement creature type count + // Keep this synced up with World.a(Class) +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 6e7e9af..23b342b 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -1739,7 +1739,7 @@ public abstract class World implements IBlockAccess { + } + + int k = MathHelper.floor(entity.locX / 16.0D); +- int l = MathHelper.floor(entity.locY / 16.0D); ++ int l = Math.min(15, Math.max(0, MathHelper.floor(entity.locY / 16.0D))); // Paper - stay consistent with chunk add/remove behavior + int i1 = MathHelper.floor(entity.locZ / 16.0D); + + if (!entity.aa || entity.ab != k || entity.ac != l || entity.ad != i1) { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0142-Check-entity-count-additions-and-mark-entities-remov.patch b/Spigot-Server-Patches/0142-Check-entity-count-additions-and-mark-entities-remov.patch deleted file mode 100644 index a080e62317..0000000000 --- a/Spigot-Server-Patches/0142-Check-entity-count-additions-and-mark-entities-remov.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 96f6ebe5e1b8a63789ffffb307ef1cf856c434de Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Fri, 22 Apr 2016 20:34:21 -0500 -Subject: [PATCH] Check entity count additions and mark entities removed - - -diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index b94cdad..904141a 100644 ---- a/src/main/java/net/minecraft/server/Chunk.java -+++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -631,12 +631,36 @@ public class Chunk { - k = this.entitySlices.length - 1; - } - -+ // Paper start - Try to catch plugins doing indecent things -+ boolean ignoreAdd = false; -+ if (entity.aa && entity.getChunkX() == this.locX && entity.getChunkY() == k && entity.getChunkZ() == this.locZ) { -+ String chunkName = entity.getWorld().getWorld().getName() + ":" + entity.getChunkX() + "," + entity.getChunkY() + "," + entity.getChunkZ(); -+ if (this.entitySlices[k].contains(entity)) { -+ new Throwable("Double Chunk Add to: " + chunkName).printStackTrace(); -+ ignoreAdd = true; -+ } else { -+ boolean found = false; -+ for (int i1 = 0; i1 < this.entitySlices.length; i1++) { -+ if (this.entitySlices[i1].contains(entity)) { -+ new Throwable("Entity was found in another slice of this chunk, tried: " + k + ", was in: " + chunkName).printStackTrace(); -+ found = true; -+ ignoreAdd = true; -+ } -+ } -+ if (!found) { -+ new Throwable("Improperly detected double chunk add. Was not actually in this chunk.").printStackTrace(); -+ } -+ } -+ } -+ // Paper end -+ - entity.aa = true; - entity.ab = this.locX; - entity.ac = k; - entity.ad = this.locZ; - this.entitySlices[k].add(entity); - // Paper start - update count -+ if (ignoreAdd) return; - if (entity instanceof EntityItem) { - itemCounts[k]++; - } else if (entity instanceof IInventory) { -@@ -681,6 +705,7 @@ public class Chunk { - } else if (entity instanceof IInventory) { - inventoryEntityCounts[i]--; - } -+ entity.aa = false; // You aren't added to chunk anymore - // Paper end - // Spigot start - decrement creature type count - // Keep this synced up with World.a(Class) -diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index b3dd456..5c3e075 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -1739,7 +1739,7 @@ public abstract class World implements IBlockAccess { - } - - int k = MathHelper.floor(entity.locX / 16.0D); -- int l = MathHelper.floor(entity.locY / 16.0D); -+ int l = Math.min(15, Math.max(0, MathHelper.floor(entity.locY / 16.0D))); // Paper - stay consistent with chunk add/remove behavior - int i1 = MathHelper.floor(entity.locZ / 16.0D); - - if (!entity.aa || entity.ab != k || entity.ac != l || entity.ad != i1) { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0142-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch b/Spigot-Server-Patches/0142-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch new file mode 100644 index 0000000000..00c0c19eb1 --- /dev/null +++ b/Spigot-Server-Patches/0142-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch @@ -0,0 +1,55 @@ +From 7c4048c52e4c36d4646335713eb75e1f2ca4effc Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sun, 24 Apr 2016 19:49:33 -0500 +Subject: [PATCH] SPIGOT-1401: Fix dispenser, dropper, furnace placement + + +diff --git a/src/main/java/net/minecraft/server/BlockDispenser.java b/src/main/java/net/minecraft/server/BlockDispenser.java +index 9e80efe..337a1cb 100644 +--- a/src/main/java/net/minecraft/server/BlockDispenser.java ++++ b/src/main/java/net/minecraft/server/BlockDispenser.java +@@ -21,6 +21,9 @@ public class BlockDispenser extends BlockTileEntity { + return 4; + } + ++ // Paper start - Removed override of onPlace that was reversing placement direction when ++ // adjacent to another block, which was not consistent with single player block placement ++ /* + public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { + super.onPlace(world, blockposition, iblockdata); + this.e(world, blockposition, iblockdata); +@@ -50,6 +53,8 @@ public class BlockDispenser extends BlockTileEntity { + world.setTypeAndData(blockposition, iblockdata.set(BlockDispenser.FACING, enumdirection).set(BlockDispenser.TRIGGERED, Boolean.valueOf(false)), 2); + } + } ++ */ ++ // Paper end + + public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, @Nullable ItemStack itemstack, EnumDirection enumdirection, float f, float f1, float f2) { + if (world.isClientSide) { +diff --git a/src/main/java/net/minecraft/server/BlockFurnace.java b/src/main/java/net/minecraft/server/BlockFurnace.java +index 61a6b8a..25f7b4b 100644 +--- a/src/main/java/net/minecraft/server/BlockFurnace.java ++++ b/src/main/java/net/minecraft/server/BlockFurnace.java +@@ -20,6 +20,9 @@ public class BlockFurnace extends BlockTileEntity { + return Item.getItemOf(Blocks.FURNACE); + } + ++ // Paper start - Removed override of onPlace that was reversing placement direction when ++ // adjacent to another block, which was not consistent with single player block placement ++ /* + public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { + this.e(world, blockposition, iblockdata); + } +@@ -45,6 +48,8 @@ public class BlockFurnace extends BlockTileEntity { + world.setTypeAndData(blockposition, iblockdata.set(BlockFurnace.FACING, enumdirection), 2); + } + } ++ */ ++ // Paper end + + public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, @Nullable ItemStack itemstack, EnumDirection enumdirection, float f, float f1, float f2) { + if (world.isClientSide) { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0143-Reimplement-PlayerEditBookEvent.patch b/Spigot-Server-Patches/0143-Reimplement-PlayerEditBookEvent.patch new file mode 100644 index 0000000000..564b00b75b --- /dev/null +++ b/Spigot-Server-Patches/0143-Reimplement-PlayerEditBookEvent.patch @@ -0,0 +1,89 @@ +From df91c49a8a8472b88e89ad0634954ee2b495b793 Mon Sep 17 00:00:00 2001 +From: willies952002 +Date: Sat, 23 Apr 2016 19:51:19 -0400 +Subject: [PATCH] Reimplement PlayerEditBookEvent + + +diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java +index 4d471ec..cf27086 100644 +--- a/src/main/java/net/minecraft/server/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/PlayerConnection.java +@@ -2207,6 +2207,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + ItemStack itemstack; + ItemStack itemstack1; + ++ try { // Paper - Reimplement BookEditEvent + if ("MC|BEdit".equals(s)) { + packetdataserializer = new PacketDataSerializer(Unpooled.wrappedBuffer(packetplayincustompayload.b())); + +@@ -2224,12 +2225,14 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + if (itemstack1 != null) { + if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) { + itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); ++ CraftEventFactory.handleEditBookEvent(player, itemstack1); // Paper + } + + return; + } + } catch (Exception exception) { + PlayerConnection.LOGGER.error("Couldn\'t handle book info", exception); ++ this.disconnect("Invalid Book Data!"); // Paper + return; + } finally { + packetdataserializer.release(); +@@ -2269,12 +2272,14 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + + itemstack1.a("pages", (NBTBase) nbttaglist); + itemstack1.setItem(Items.WRITTEN_BOOK); ++ CraftEventFactory.handleEditBookEvent(player, itemstack1); // Paper + } + + return; + } + } catch (Exception exception1) { + PlayerConnection.LOGGER.error("Couldn\'t sign book", exception1); ++ this.disconnect("Invalid Book Data!"); // Paper + return; + } finally { + packetdataserializer.release(); +@@ -2340,6 +2345,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + } + } catch (Exception exception3) { + PlayerConnection.LOGGER.error("Couldn\'t set command block", exception3); ++ this.disconnect("Invalid Command Block Data!"); // Paper + } finally { + packetdataserializer.release(); + } +@@ -2409,6 +2415,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + } + } catch (Exception exception4) { + PlayerConnection.LOGGER.error("Couldn\'t set command block", exception4); ++ this.disconnect("Invalid Command Block Data!"); // Paper + } finally { + packetdataserializer.release(); + } +@@ -2434,6 +2441,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + } + } catch (Exception exception5) { + PlayerConnection.LOGGER.error("Couldn\'t set beacon", exception5); ++ this.disconnect("Invalid Beacon Data!"); // Paper + } + } + } else if ("MC|ItemName".equals(s)) { +@@ -2536,6 +2544,13 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { + } + } + } ++ // Paper start ++ } finally { ++ if (packetplayincustompayload.b().refCnt() > 0) { ++ packetplayincustompayload.b().release(); ++ } ++ } ++ // Paper end + + } + +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0143-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch b/Spigot-Server-Patches/0143-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch deleted file mode 100644 index 35ae0f48dc..0000000000 --- a/Spigot-Server-Patches/0143-SPIGOT-1401-Fix-dispenser-dropper-furnace-placement.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 33bc5ffd91ccca0e30489cba02ec2963f670e086 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sun, 24 Apr 2016 19:49:33 -0500 -Subject: [PATCH] SPIGOT-1401: Fix dispenser, dropper, furnace placement - - -diff --git a/src/main/java/net/minecraft/server/BlockDispenser.java b/src/main/java/net/minecraft/server/BlockDispenser.java -index 9e80efe..337a1cb 100644 ---- a/src/main/java/net/minecraft/server/BlockDispenser.java -+++ b/src/main/java/net/minecraft/server/BlockDispenser.java -@@ -21,6 +21,9 @@ public class BlockDispenser extends BlockTileEntity { - return 4; - } - -+ // Paper start - Removed override of onPlace that was reversing placement direction when -+ // adjacent to another block, which was not consistent with single player block placement -+ /* - public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { - super.onPlace(world, blockposition, iblockdata); - this.e(world, blockposition, iblockdata); -@@ -50,6 +53,8 @@ public class BlockDispenser extends BlockTileEntity { - world.setTypeAndData(blockposition, iblockdata.set(BlockDispenser.FACING, enumdirection).set(BlockDispenser.TRIGGERED, Boolean.valueOf(false)), 2); - } - } -+ */ -+ // Paper end - - public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, @Nullable ItemStack itemstack, EnumDirection enumdirection, float f, float f1, float f2) { - if (world.isClientSide) { -diff --git a/src/main/java/net/minecraft/server/BlockFurnace.java b/src/main/java/net/minecraft/server/BlockFurnace.java -index 61a6b8a..25f7b4b 100644 ---- a/src/main/java/net/minecraft/server/BlockFurnace.java -+++ b/src/main/java/net/minecraft/server/BlockFurnace.java -@@ -20,6 +20,9 @@ public class BlockFurnace extends BlockTileEntity { - return Item.getItemOf(Blocks.FURNACE); - } - -+ // Paper start - Removed override of onPlace that was reversing placement direction when -+ // adjacent to another block, which was not consistent with single player block placement -+ /* - public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { - this.e(world, blockposition, iblockdata); - } -@@ -45,6 +48,8 @@ public class BlockFurnace extends BlockTileEntity { - world.setTypeAndData(blockposition, iblockdata.set(BlockFurnace.FACING, enumdirection), 2); - } - } -+ */ -+ // Paper end - - public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, @Nullable ItemStack itemstack, EnumDirection enumdirection, float f, float f1, float f2) { - if (world.isClientSide) { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0144-Improve-Minecraft-Hopper-Performance.patch b/Spigot-Server-Patches/0144-Improve-Minecraft-Hopper-Performance.patch new file mode 100644 index 0000000000..4b0168d7d4 --- /dev/null +++ b/Spigot-Server-Patches/0144-Improve-Minecraft-Hopper-Performance.patch @@ -0,0 +1,78 @@ +From 6a110c2813f8b97f35921b67d31e6e2f3f21df4a Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 27 Apr 2016 22:09:52 -0400 +Subject: [PATCH] Improve Minecraft Hopper Performance + +Removes unnecessary extra calls to .update() that are very expensive +Also reset cooldown each hopper tick that a hopper is full. + +diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java +index f59e6f8..85f97cc 100644 +--- a/src/main/java/net/minecraft/server/TileEntity.java ++++ b/src/main/java/net/minecraft/server/TileEntity.java +@@ -36,6 +36,7 @@ public abstract class TileEntity { + } + } + ++ static boolean IGNORE_TILE_UPDATES = false; // Paper + public World getWorld() { + return this.world; + } +@@ -110,6 +111,7 @@ public abstract class TileEntity { + + public void update() { + if (this.world != null) { ++ if (IGNORE_TILE_UPDATES) return; // Paper + IBlockData iblockdata = this.world.getType(this.position); + + this.h = iblockdata.getBlock().toLegacyData(iblockdata); +diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java +index de458c8..ec0b1ca 100644 +--- a/src/main/java/net/minecraft/server/TileEntityHopper.java ++++ b/src/main/java/net/minecraft/server/TileEntityHopper.java +@@ -190,12 +190,15 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + } + // Paper end + } ++ ++ if (!isCooledDown() && isFull()) { setCooldown(world.spigotConfig.hopperTransfer); } // Paper + return false; + } else { + return false; + } + } + ++ boolean isFull() { return q(); } // Paper // OBFHELPER + private boolean q() { + ItemStack[] aitemstack = this.items; + int i = aitemstack.length; +@@ -490,7 +493,9 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + boolean flag = false; + + if (itemstack1 == null) { ++ IGNORE_TILE_UPDATES = true; // Paper + iinventory.setItem(i, itemstack); ++ IGNORE_TILE_UPDATES = false; // Paper + itemstack = null; + flag = true; + } else if (a(itemstack1, itemstack)) { +@@ -510,7 +515,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + tileentityhopper.setCooldown(tileentityhopper.world.spigotConfig.hopperTransfer); // Spigot + } + +- iinventory.update(); ++ //iinventory.update(); // Paper + } + + iinventory.update(); +@@ -585,6 +590,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + this.g = i; + } + ++ boolean isCooledDown() { return o(); } // Paper // OBFHELPER + public boolean o() { + return this.g > 0; + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0144-Reimplement-PlayerEditBookEvent.patch b/Spigot-Server-Patches/0144-Reimplement-PlayerEditBookEvent.patch deleted file mode 100644 index 3869f1ec0d..0000000000 --- a/Spigot-Server-Patches/0144-Reimplement-PlayerEditBookEvent.patch +++ /dev/null @@ -1,89 +0,0 @@ -From daafbd9ad18ff3fab1e810dbf51ea59ccb3af390 Mon Sep 17 00:00:00 2001 -From: willies952002 -Date: Sat, 23 Apr 2016 19:51:19 -0400 -Subject: [PATCH] Reimplement PlayerEditBookEvent - - -diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java -index 4d471ec..cf27086 100644 ---- a/src/main/java/net/minecraft/server/PlayerConnection.java -+++ b/src/main/java/net/minecraft/server/PlayerConnection.java -@@ -2207,6 +2207,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - ItemStack itemstack; - ItemStack itemstack1; - -+ try { // Paper - Reimplement BookEditEvent - if ("MC|BEdit".equals(s)) { - packetdataserializer = new PacketDataSerializer(Unpooled.wrappedBuffer(packetplayincustompayload.b())); - -@@ -2224,12 +2225,14 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - if (itemstack1 != null) { - if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) { - itemstack1.a("pages", (NBTBase) itemstack.getTag().getList("pages", 8)); -+ CraftEventFactory.handleEditBookEvent(player, itemstack1); // Paper - } - - return; - } - } catch (Exception exception) { - PlayerConnection.LOGGER.error("Couldn\'t handle book info", exception); -+ this.disconnect("Invalid Book Data!"); // Paper - return; - } finally { - packetdataserializer.release(); -@@ -2269,12 +2272,14 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - - itemstack1.a("pages", (NBTBase) nbttaglist); - itemstack1.setItem(Items.WRITTEN_BOOK); -+ CraftEventFactory.handleEditBookEvent(player, itemstack1); // Paper - } - - return; - } - } catch (Exception exception1) { - PlayerConnection.LOGGER.error("Couldn\'t sign book", exception1); -+ this.disconnect("Invalid Book Data!"); // Paper - return; - } finally { - packetdataserializer.release(); -@@ -2340,6 +2345,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - } - } catch (Exception exception3) { - PlayerConnection.LOGGER.error("Couldn\'t set command block", exception3); -+ this.disconnect("Invalid Command Block Data!"); // Paper - } finally { - packetdataserializer.release(); - } -@@ -2409,6 +2415,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - } - } catch (Exception exception4) { - PlayerConnection.LOGGER.error("Couldn\'t set command block", exception4); -+ this.disconnect("Invalid Command Block Data!"); // Paper - } finally { - packetdataserializer.release(); - } -@@ -2434,6 +2441,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - } - } catch (Exception exception5) { - PlayerConnection.LOGGER.error("Couldn\'t set beacon", exception5); -+ this.disconnect("Invalid Beacon Data!"); // Paper - } - } - } else if ("MC|ItemName".equals(s)) { -@@ -2536,6 +2544,13 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { - } - } - } -+ // Paper start -+ } finally { -+ if (packetplayincustompayload.b().refCnt() > 0) { -+ packetplayincustompayload.b().release(); -+ } -+ } -+ // Paper end - - } - --- -2.8.2 - diff --git a/Spigot-Server-Patches/0145-Improve-Minecraft-Hopper-Performance.patch b/Spigot-Server-Patches/0145-Improve-Minecraft-Hopper-Performance.patch deleted file mode 100644 index b222364ced..0000000000 --- a/Spigot-Server-Patches/0145-Improve-Minecraft-Hopper-Performance.patch +++ /dev/null @@ -1,78 +0,0 @@ -From ff070ed082dcd1c44676ba68b3d39daed7b88b90 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 27 Apr 2016 22:09:52 -0400 -Subject: [PATCH] Improve Minecraft Hopper Performance - -Removes unnecessary extra calls to .update() that are very expensive -Also reset cooldown each hopper tick that a hopper is full. - -diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java -index f59e6f8..85f97cc 100644 ---- a/src/main/java/net/minecraft/server/TileEntity.java -+++ b/src/main/java/net/minecraft/server/TileEntity.java -@@ -36,6 +36,7 @@ public abstract class TileEntity { - } - } - -+ static boolean IGNORE_TILE_UPDATES = false; // Paper - public World getWorld() { - return this.world; - } -@@ -110,6 +111,7 @@ public abstract class TileEntity { - - public void update() { - if (this.world != null) { -+ if (IGNORE_TILE_UPDATES) return; // Paper - IBlockData iblockdata = this.world.getType(this.position); - - this.h = iblockdata.getBlock().toLegacyData(iblockdata); -diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java -index de458c8..ec0b1ca 100644 ---- a/src/main/java/net/minecraft/server/TileEntityHopper.java -+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java -@@ -190,12 +190,15 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi - } - // Paper end - } -+ -+ if (!isCooledDown() && isFull()) { setCooldown(world.spigotConfig.hopperTransfer); } // Paper - return false; - } else { - return false; - } - } - -+ boolean isFull() { return q(); } // Paper // OBFHELPER - private boolean q() { - ItemStack[] aitemstack = this.items; - int i = aitemstack.length; -@@ -490,7 +493,9 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi - boolean flag = false; - - if (itemstack1 == null) { -+ IGNORE_TILE_UPDATES = true; // Paper - iinventory.setItem(i, itemstack); -+ IGNORE_TILE_UPDATES = false; // Paper - itemstack = null; - flag = true; - } else if (a(itemstack1, itemstack)) { -@@ -510,7 +515,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi - tileentityhopper.setCooldown(tileentityhopper.world.spigotConfig.hopperTransfer); // Spigot - } - -- iinventory.update(); -+ //iinventory.update(); // Paper - } - - iinventory.update(); -@@ -585,6 +590,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi - this.g = i; - } - -+ boolean isCooledDown() { return o(); } // Paper // OBFHELPER - public boolean o() { - return this.g > 0; - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0145-remove-null-possibility-for-getServer-singleton.patch b/Spigot-Server-Patches/0145-remove-null-possibility-for-getServer-singleton.patch new file mode 100644 index 0000000000..92d2b01369 --- /dev/null +++ b/Spigot-Server-Patches/0145-remove-null-possibility-for-getServer-singleton.patch @@ -0,0 +1,39 @@ +From 059294d9f3416fec8a01bd061149ba6409d3bb66 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 28 Apr 2016 00:57:27 -0400 +Subject: [PATCH] remove null possibility for getServer singleton + +to stop IDE complaining about potential NPE + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index e1c0c0b..ec9f037 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -54,6 +54,7 @@ import co.aikar.timings.MinecraftTimings; // Paper + + public abstract class MinecraftServer implements Runnable, ICommandListener, IAsyncTaskHandler, IMojangStatistics { + ++ private static MinecraftServer SERVER; // Paper + public static final Logger LOGGER = LogManager.getLogger(); + public static final File a = new File("usercache.json"); + public Convertable convertable; +@@ -121,6 +122,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + // CraftBukkit end + + public MinecraftServer(OptionSet options, Proxy proxy, DataConverterManager dataconvertermanager, YggdrasilAuthenticationService yggdrasilauthenticationservice, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, UserCache usercache) { ++ SERVER = this; // Paper - better singleton + io.netty.util.ResourceLeakDetector.setEnabled( false ); // Spigot - disable + this.e = proxy; + this.U = yggdrasilauthenticationservice; +@@ -1591,7 +1593,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + // CraftBukkit start + @Deprecated + public static MinecraftServer getServer() { +- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null; ++ return SERVER; + } + // CraftBukkit end + +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0146-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch b/Spigot-Server-Patches/0146-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch new file mode 100644 index 0000000000..96ec3d56b7 --- /dev/null +++ b/Spigot-Server-Patches/0146-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch @@ -0,0 +1,149 @@ +From 6c301c0cf944d0d47e82f3b9a8b8eaf78e62dcd4 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 29 Apr 2016 20:02:00 -0400 +Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes + +Maps used a modified version of rendering to support plugin controlled +imaging on maps. The Craft Map Renderer is much slower than Vanilla, +causing maps in item frames to cause a noticeable hit on server performance. + +This updates the map system to not use the Craft system if we detect that no +custom renderers are in use, defaulting to the much simpler Vanilla system. + +Additionally, numerous issues to player position tracking on maps has been fixed. + +diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java +index 0f73fcf..696f21f 100644 +--- a/src/main/java/net/minecraft/server/EntityHuman.java ++++ b/src/main/java/net/minecraft/server/EntityHuman.java +@@ -589,6 +589,12 @@ public abstract class EntityHuman extends EntityLiving { + return null; + } + // CraftBukkit end ++ // Paper start - remove player from map on drop ++ if (itemstack.getItem() == Items.FILLED_MAP) { ++ WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.world); ++ worldmap.updateSeenPlayers(this, itemstack); ++ } ++ // Paper stop + + ItemStack itemstack1 = this.a(entityitem); + +diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java +index 6c8da79..38e88d8 100644 +--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java ++++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java +@@ -90,11 +90,11 @@ public class EntityTrackerEntry { + } + + // PAIL : rename +- if (this.tracker instanceof EntityItemFrame /*&& this.a % 10 == 0*/) { // CraftBukkit - Moved below, should always enter this block ++ if (this.tracker instanceof EntityItemFrame && this.a % 20 == 0) { // Paper + EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker; + ItemStack itemstack = entityitemframe.getItem(); + +- if (this.a % 10 == 0 && itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // CraftBukkit - Moved this.m % 10 logic here so item frames do not enter the other blocks ++ if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // Paper - moved back up + WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world); + Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit + +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 23b342b..6c67062 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -1144,6 +1144,7 @@ public abstract class World implements IBlockAccess { + { + if ( iter.next().trackee == entity ) + { ++ map.decorations.remove(entity.getUniqueID()); // Paper + iter.remove(); + } + } +diff --git a/src/main/java/net/minecraft/server/WorldMap.java b/src/main/java/net/minecraft/server/WorldMap.java +index 7f604ca..e3e56f3 100644 +--- a/src/main/java/net/minecraft/server/WorldMap.java ++++ b/src/main/java/net/minecraft/server/WorldMap.java +@@ -27,6 +27,7 @@ public class WorldMap extends PersistentBase { + public List h = Lists.newArrayList(); + public Map j = Maps.newHashMap(); // Spigot + public Map decorations = Maps.newLinkedHashMap(); // Spigot ++ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper + + // CraftBukkit start + public final CraftMapView mapView; +@@ -39,6 +40,7 @@ public class WorldMap extends PersistentBase { + // CraftBukkit start + mapView = new CraftMapView(this); + server = (CraftServer) org.bukkit.Bukkit.getServer(); ++ vanillaRender.buffer = colors; // Paper + // CraftBukkit end + } + +@@ -112,6 +114,7 @@ public class WorldMap extends PersistentBase { + } + } + } ++ vanillaRender.buffer = colors; // Paper + + } + +@@ -146,6 +149,7 @@ public class WorldMap extends PersistentBase { + return nbttagcompound; + } + ++ public void updateSeenPlayers(EntityHuman entityhuman, ItemStack itemstack) { a(entityhuman, itemstack); } // Paper // OBFHELPER + public void a(EntityHuman entityhuman, ItemStack itemstack) { + if (!this.j.containsKey(entityhuman)) { + WorldMap.WorldMapHumanTracker worldmap_worldmaphumantracker = new WorldMap.WorldMapHumanTracker(entityhuman); +@@ -273,6 +277,21 @@ public class WorldMap extends PersistentBase { + + public class WorldMapHumanTracker { + ++ // Paper start ++ private void addSeenPlayers(java.util.Collection icons) { ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) trackee.getBukkitEntity(); ++ WorldMap.this.decorations.forEach((uuid, mapIcon) -> { ++ // If this cursor is for a player check visibility with vanish system ++ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayer(uuid); // Spigot ++ if (other == null || player.canSee(other)) { ++ icons.add(mapIcon); ++ } ++ }); ++ } ++ private boolean shouldUseVanillaMap() { ++ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class; ++ } ++ // Paper stop + public final EntityHuman trackee; + private boolean d = true; + private int e = 0; +@@ -288,9 +307,12 @@ public class WorldMap extends PersistentBase { + + public Packet a(ItemStack itemstack) { + // CraftBukkit start +- org.bukkit.craftbukkit.map.RenderData render = WorldMap.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.trackee.getBukkitEntity()); // CraftBukkit ++ if (!this.d && this.i % 5 != 0) { this.i++; return null; } // Paper - this won't end up sending, so don't render it! ++ boolean vanillaMaps = shouldUseVanillaMap(); // Paper ++ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? WorldMap.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.trackee.getBukkitEntity()) : WorldMap.this.vanillaRender; // CraftBukkit // Paper + + java.util.Collection icons = new java.util.ArrayList(); ++ if (vanillaMaps) addSeenPlayers(icons); // Paper + + for ( org.bukkit.map.MapCursor cursor : render.cursors) { + +diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java +index 256a131..5768cd5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java ++++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java +@@ -5,7 +5,7 @@ import org.bukkit.map.MapCursor; + + public class RenderData { + +- public final byte[] buffer; ++ public byte[] buffer; // Paper + public final ArrayList cursors; + + public RenderData() { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0146-remove-null-possibility-for-getServer-singleton.patch b/Spigot-Server-Patches/0146-remove-null-possibility-for-getServer-singleton.patch deleted file mode 100644 index 7dd1c080c2..0000000000 --- a/Spigot-Server-Patches/0146-remove-null-possibility-for-getServer-singleton.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3b596ccedcfa761caa54a479c5aa43c6a3b5053c Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 28 Apr 2016 00:57:27 -0400 -Subject: [PATCH] remove null possibility for getServer singleton - -to stop IDE complaining about potential NPE - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e1c0c0b..ec9f037 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -54,6 +54,7 @@ import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class MinecraftServer implements Runnable, ICommandListener, IAsyncTaskHandler, IMojangStatistics { - -+ private static MinecraftServer SERVER; // Paper - public static final Logger LOGGER = LogManager.getLogger(); - public static final File a = new File("usercache.json"); - public Convertable convertable; -@@ -121,6 +122,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs - // CraftBukkit end - - public MinecraftServer(OptionSet options, Proxy proxy, DataConverterManager dataconvertermanager, YggdrasilAuthenticationService yggdrasilauthenticationservice, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, UserCache usercache) { -+ SERVER = this; // Paper - better singleton - io.netty.util.ResourceLeakDetector.setEnabled( false ); // Spigot - disable - this.e = proxy; - this.U = yggdrasilauthenticationservice; -@@ -1591,7 +1593,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs - // CraftBukkit start - @Deprecated - public static MinecraftServer getServer() { -- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null; -+ return SERVER; - } - // CraftBukkit end - --- -2.8.2 - diff --git a/Spigot-Server-Patches/0147-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch b/Spigot-Server-Patches/0147-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch deleted file mode 100644 index 1ca96a7314..0000000000 --- a/Spigot-Server-Patches/0147-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch +++ /dev/null @@ -1,149 +0,0 @@ -From d0e77b7d023cdba51d177126f4592d26da939ee1 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 29 Apr 2016 20:02:00 -0400 -Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes - -Maps used a modified version of rendering to support plugin controlled -imaging on maps. The Craft Map Renderer is much slower than Vanilla, -causing maps in item frames to cause a noticeable hit on server performance. - -This updates the map system to not use the Craft system if we detect that no -custom renderers are in use, defaulting to the much simpler Vanilla system. - -Additionally, numerous issues to player position tracking on maps has been fixed. - -diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java -index 0f73fcf..696f21f 100644 ---- a/src/main/java/net/minecraft/server/EntityHuman.java -+++ b/src/main/java/net/minecraft/server/EntityHuman.java -@@ -589,6 +589,12 @@ public abstract class EntityHuman extends EntityLiving { - return null; - } - // CraftBukkit end -+ // Paper start - remove player from map on drop -+ if (itemstack.getItem() == Items.FILLED_MAP) { -+ WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.world); -+ worldmap.updateSeenPlayers(this, itemstack); -+ } -+ // Paper stop - - ItemStack itemstack1 = this.a(entityitem); - -diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -index 6c8da79..38e88d8 100644 ---- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java -+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -@@ -90,11 +90,11 @@ public class EntityTrackerEntry { - } - - // PAIL : rename -- if (this.tracker instanceof EntityItemFrame /*&& this.a % 10 == 0*/) { // CraftBukkit - Moved below, should always enter this block -+ if (this.tracker instanceof EntityItemFrame && this.a % 20 == 0) { // Paper - EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker; - ItemStack itemstack = entityitemframe.getItem(); - -- if (this.a % 10 == 0 && itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // CraftBukkit - Moved this.m % 10 logic here so item frames do not enter the other blocks -+ if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // Paper - moved back up - WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world); - Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit - -diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 5c3e075..0f1ee49 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -1144,6 +1144,7 @@ public abstract class World implements IBlockAccess { - { - if ( iter.next().trackee == entity ) - { -+ map.decorations.remove(entity.getUniqueID()); // Paper - iter.remove(); - } - } -diff --git a/src/main/java/net/minecraft/server/WorldMap.java b/src/main/java/net/minecraft/server/WorldMap.java -index 7f604ca..e3e56f3 100644 ---- a/src/main/java/net/minecraft/server/WorldMap.java -+++ b/src/main/java/net/minecraft/server/WorldMap.java -@@ -27,6 +27,7 @@ public class WorldMap extends PersistentBase { - public List h = Lists.newArrayList(); - public Map j = Maps.newHashMap(); // Spigot - public Map decorations = Maps.newLinkedHashMap(); // Spigot -+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper - - // CraftBukkit start - public final CraftMapView mapView; -@@ -39,6 +40,7 @@ public class WorldMap extends PersistentBase { - // CraftBukkit start - mapView = new CraftMapView(this); - server = (CraftServer) org.bukkit.Bukkit.getServer(); -+ vanillaRender.buffer = colors; // Paper - // CraftBukkit end - } - -@@ -112,6 +114,7 @@ public class WorldMap extends PersistentBase { - } - } - } -+ vanillaRender.buffer = colors; // Paper - - } - -@@ -146,6 +149,7 @@ public class WorldMap extends PersistentBase { - return nbttagcompound; - } - -+ public void updateSeenPlayers(EntityHuman entityhuman, ItemStack itemstack) { a(entityhuman, itemstack); } // Paper // OBFHELPER - public void a(EntityHuman entityhuman, ItemStack itemstack) { - if (!this.j.containsKey(entityhuman)) { - WorldMap.WorldMapHumanTracker worldmap_worldmaphumantracker = new WorldMap.WorldMapHumanTracker(entityhuman); -@@ -273,6 +277,21 @@ public class WorldMap extends PersistentBase { - - public class WorldMapHumanTracker { - -+ // Paper start -+ private void addSeenPlayers(java.util.Collection icons) { -+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) trackee.getBukkitEntity(); -+ WorldMap.this.decorations.forEach((uuid, mapIcon) -> { -+ // If this cursor is for a player check visibility with vanish system -+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayer(uuid); // Spigot -+ if (other == null || player.canSee(other)) { -+ icons.add(mapIcon); -+ } -+ }); -+ } -+ private boolean shouldUseVanillaMap() { -+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class; -+ } -+ // Paper stop - public final EntityHuman trackee; - private boolean d = true; - private int e = 0; -@@ -288,9 +307,12 @@ public class WorldMap extends PersistentBase { - - public Packet a(ItemStack itemstack) { - // CraftBukkit start -- org.bukkit.craftbukkit.map.RenderData render = WorldMap.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.trackee.getBukkitEntity()); // CraftBukkit -+ if (!this.d && this.i % 5 != 0) { this.i++; return null; } // Paper - this won't end up sending, so don't render it! -+ boolean vanillaMaps = shouldUseVanillaMap(); // Paper -+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? WorldMap.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.trackee.getBukkitEntity()) : WorldMap.this.vanillaRender; // CraftBukkit // Paper - - java.util.Collection icons = new java.util.ArrayList(); -+ if (vanillaMaps) addSeenPlayers(icons); // Paper - - for ( org.bukkit.map.MapCursor cursor : render.cursors) { - -diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java -index 256a131..5768cd5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java -+++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java -@@ -5,7 +5,7 @@ import org.bukkit.map.MapCursor; - - public class RenderData { - -- public final byte[] buffer; -+ public byte[] buffer; // Paper - public final ArrayList cursors; - - public RenderData() { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0147-LootTable-API-Replenishable-Lootables-Feature.patch b/Spigot-Server-Patches/0147-LootTable-API-Replenishable-Lootables-Feature.patch new file mode 100644 index 0000000000..2c1a1894e9 --- /dev/null +++ b/Spigot-Server-Patches/0147-LootTable-API-Replenishable-Lootables-Feature.patch @@ -0,0 +1,733 @@ +From 97bbe372fc937d26e9ff4e96ff362a2e4f417586 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 1 May 2016 21:19:14 -0400 +Subject: [PATCH] LootTable API & Replenishable Lootables Feature + +Provides an API to control the loot table for an object. +Also provides a feature that any Lootable Inventory (Chests in Structures) +can automatically replenish after a given time. + +This feature is good for long term worlds so that newer players +do not suffer with "Every chest has been looted" + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index cc307c4..efed4c6 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -330,4 +330,26 @@ public class PaperWorldConfig { + this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); + this.log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); + } ++ ++ public boolean autoReplenishLootables; ++ public boolean restrictPlayerReloot; ++ public boolean changeLootTableSeedOnFill; ++ public int maxLootableRefills; ++ public int lootableRegenMin; ++ public int lootableRegenMax; ++ private void enhancedLootables() { ++ autoReplenishLootables = getBoolean("lootables.auto-replenish", false); ++ restrictPlayerReloot = getBoolean("lootables.restrict-player-reloot", true); ++ changeLootTableSeedOnFill = getBoolean("lootables.reset-seed-on-fill", true); ++ maxLootableRefills = getInt("lootables.max-refills", -1); ++ lootableRegenMin = PaperConfig.getSeconds(getString("lootables.refresh-min", "12h")); ++ lootableRegenMax = PaperConfig.getSeconds(getString("lootables.refresh-max", "2d")); ++ if (autoReplenishLootables) { ++ log("Lootables: Replenishing every " + ++ PaperConfig.timeSummary(lootableRegenMin) + " to " + ++ PaperConfig.timeSummary(lootableRegenMax) + ++ (restrictPlayerReloot ? " (restricting reloot)" : "") ++ ); ++ } ++ } + } +diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java +new file mode 100644 +index 0000000..36c36d1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java +@@ -0,0 +1,12 @@ ++package com.destroystokyo.paper.loottable; ++ ++import net.minecraft.server.World; ++ ++interface CraftLootable extends Lootable { ++ ++ World getNMSWorld(); ++ ++ default org.bukkit.World getBukkitWorld() { ++ return getNMSWorld().getWorld(); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java +new file mode 100644 +index 0000000..20d236c +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java +@@ -0,0 +1,33 @@ ++package com.destroystokyo.paper.loottable; ++ ++import net.minecraft.server.BlockPosition; ++import net.minecraft.server.TileEntityLootable; ++import net.minecraft.server.World; ++import org.bukkit.Chunk; ++import org.bukkit.block.Block; ++ ++public interface CraftLootableBlockInventory extends LootableBlockInventory, CraftLootableInventory { ++ ++ TileEntityLootable getTileEntity(); ++ ++ @Override ++ default LootableInventory getAPILootableInventory() { ++ return this; ++ } ++ ++ @Override ++ default World getNMSWorld() { ++ return getTileEntity().getWorld(); ++ } ++ ++ default Block getBlock() { ++ final BlockPosition position = getTileEntity().getPosition(); ++ final Chunk bukkitChunk = getTileEntity().getWorld().getChunkAtWorldCoords(position).bukkitChunk; ++ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ()); ++ } ++ ++ @Override ++ default CraftLootableInventoryData getLootableData() { ++ return getTileEntity().getLootableData(); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java +new file mode 100644 +index 0000000..1150dee +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java +@@ -0,0 +1,31 @@ ++package com.destroystokyo.paper.loottable; ++ ++import net.minecraft.server.World; ++import org.bukkit.entity.Entity; ++ ++public interface CraftLootableEntityInventory extends LootableEntityInventory, CraftLootableInventory { ++ ++ net.minecraft.server.Entity getHandle(); ++ ++ @Override ++ default LootableInventory getAPILootableInventory() { ++ return this; ++ } ++ ++ default Entity getEntity() { ++ return getHandle().getBukkitEntity(); ++ } ++ ++ @Override ++ default World getNMSWorld() { ++ return getHandle().getWorld(); ++ } ++ ++ @Override ++ default CraftLootableInventoryData getLootableData() { ++ if (getHandle() instanceof CraftLootableInventory) { ++ return ((CraftLootableInventory) getHandle()).getLootableData(); ++ } ++ return null; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java +new file mode 100644 +index 0000000..6680976 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java +@@ -0,0 +1,88 @@ ++package com.destroystokyo.paper.loottable; ++ ++import org.apache.commons.lang.Validate; ++ ++import java.util.UUID; ++ ++public interface CraftLootableInventory extends CraftLootable, LootableInventory { ++ ++ CraftLootableInventoryData getLootableData(); ++ LootableInventory getAPILootableInventory(); ++ ++ @Override ++ default boolean isRefillEnabled() { ++ return getNMSWorld().paperConfig.autoReplenishLootables; ++ } ++ ++ @Override ++ default boolean hasBeenFilled() { ++ return getLastFilled() != -1; ++ } ++ ++ @Override ++ default String getLootTableName() { ++ return getLootableData().getLootable().getLootTableName(); ++ } ++ ++ @Override ++ default String setLootTable(String name, long seed) { ++ Validate.notNull(name); ++ ++ String prevLootTable = getLootTableName(); ++ getLootableData().getLootable().setLootTable(name, seed); ++ return prevLootTable; ++ } ++ ++ @Override ++ default long getLootTableSeed() { ++ return getLootableData().getLootable().getLootTableSeed(); ++ } ++ ++ @Override ++ default void clearLootTable() { ++ getLootableData().getLootable().clearLootTable(); ++ } ++ ++ @Override ++ default boolean hasPlayerLooted(UUID player) { ++ return getLootableData().hasPlayerLooted(player); ++ } ++ ++ @Override ++ default Long getLastLooted(UUID player) { ++ return getLootableData().getLastLooted(player); ++ } ++ ++ @Override ++ default boolean setHasPlayerLooted(UUID player, boolean looted) { ++ final boolean hasLooted = hasPlayerLooted(player); ++ if (hasLooted != looted) { ++ getLootableData().setPlayerLootedState(player, looted); ++ } ++ return hasLooted; ++ } ++ ++ @Override ++ default boolean hasPendingRefill() { ++ long nextRefill = getLootableData().getNextRefill(); ++ return nextRefill != -1 && nextRefill > getLootableData().getLastFill(); ++ } ++ ++ @Override ++ default long getLastFilled() { ++ return getLootableData().getLastFill(); ++ } ++ ++ @Override ++ default long getNextRefill() { ++ return getLootableData().getNextRefill(); ++ } ++ ++ @Override ++ default long setNextRefill(long refillAt) { ++ if (refillAt < -1) { ++ refillAt = -1; ++ } ++ return getLootableData().setNextRefill(refillAt); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java +new file mode 100644 +index 0000000..01c2713 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java +@@ -0,0 +1,182 @@ ++package com.destroystokyo.paper.loottable; ++ ++import com.destroystokyo.paper.PaperWorldConfig; ++import net.minecraft.server.*; ++import org.bukkit.entity.Player; ++ ++import javax.annotation.Nullable; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Random; ++import java.util.UUID; ++ ++public class CraftLootableInventoryData { ++ ++ private static final Random RANDOM = new Random(); ++ ++ private long lastFill = -1; ++ private long nextRefill = -1; ++ private int numRefills = 0; ++ private Map lootedPlayers; ++ private final CraftLootableInventory lootable; ++ ++ public CraftLootableInventoryData(CraftLootableInventory lootable) { ++ this.lootable = lootable; ++ } ++ ++ long getLastFill() { ++ return this.lastFill; ++ } ++ ++ long getNextRefill() { ++ return this.nextRefill; ++ } ++ ++ long setNextRefill(long nextRefill) { ++ long prev = this.nextRefill; ++ this.nextRefill = nextRefill; ++ return prev; ++ } ++ ++ CraftLootableInventory getLootable() { ++ return lootable; ++ } ++ ++ public boolean shouldReplenish(@Nullable EntityHuman player) { ++ String tableName = this.lootable.getLootTableName(); ++ ++ // No Loot Table associated ++ if (tableName == null) { ++ return false; ++ } ++ ++ // ALWAYS process the first fill ++ if (this.lastFill == -1) { ++ return true; ++ } ++ ++ // Only process refills when a player is set ++ if (player == null) { ++ return false; ++ } ++ ++ // Chest is not scheduled for refill ++ if (this.nextRefill == -1) { ++ return false; ++ } ++ ++ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; ++ ++ // Check if max refills has been hit ++ if (paperConfig.maxLootableRefills != -1 && this.numRefills >= paperConfig.maxLootableRefills) { ++ return false; ++ } ++ ++ // Refill has not been reached ++ if (this.nextRefill > System.currentTimeMillis()) { ++ return false; ++ } ++ ++ ++ final Player bukkitPlayer = (Player) player.getBukkitEntity(); ++ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory()); ++ if (paperConfig.restrictPlayerReloot && hasPlayerLooted(player.getUniqueID())) { ++ event.setCancelled(true); ++ } ++ return event.callEvent(); ++ } ++ public void processRefill(@Nullable EntityHuman player) { ++ this.lastFill = System.currentTimeMillis(); ++ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; ++ if (paperConfig.autoReplenishLootables) { ++ int min = paperConfig.lootableRegenMin * 1000; ++ int max = paperConfig.lootableRegenMax * 1000; ++ this.nextRefill = this.lastFill + min + RANDOM.nextInt(max - min + 1); ++ this.numRefills++; ++ if (paperConfig.changeLootTableSeedOnFill) { ++ this.lootable.setLootTableSeed(0); ++ } ++ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific ++ this.setPlayerLootedState(player.getUniqueID(), true); ++ } ++ } else { ++ this.lootable.clearLootTable(); ++ } ++ } ++ ++ ++ public void loadNbt(NBTTagCompound base) { ++ if (!base.hasKeyOfType("Paper.LootableData", 10)) { // 10 = compound ++ return; ++ } ++ NBTTagCompound comp = base.getCompound("Paper.LootableData"); ++ if (comp.hasKey("lastFill")) { ++ this.lastFill = comp.getLong("lastFill"); ++ } ++ if (comp.hasKey("nextRefill")) { ++ this.nextRefill = comp.getLong("nextRefill"); ++ } ++ ++ if (comp.hasKey("numRefills")) { ++ this.numRefills = comp.getInt("numRefills"); ++ } ++ if (comp.hasKeyOfType("lootedPlayers", 9)) { // 9 = list ++ NBTTagList list = comp.getList("lootedPlayers", 10); // 10 = compound ++ final int size = list.size(); ++ if (size > 0) { ++ this.lootedPlayers = new HashMap<>(list.size()); ++ } ++ for (int i = 0; i < size; i++) { ++ final NBTTagCompound cmp = list.get(i); ++ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time")); ++ } ++ } ++ } ++ public void saveNbt(NBTTagCompound base) { ++ NBTTagCompound comp = new NBTTagCompound(); ++ if (this.nextRefill != -1) { ++ comp.setLong("nextRefill", this.nextRefill); ++ } ++ if (this.lastFill != -1) { ++ comp.setLong("lastFill", this.lastFill); ++ } ++ if (this.numRefills != 0) { ++ comp.setInt("numRefills", this.numRefills); ++ } ++ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) { ++ NBTTagList list = new NBTTagList(); ++ for (Map.Entry entry : this.lootedPlayers.entrySet()) { ++ NBTTagCompound cmp = new NBTTagCompound(); ++ cmp.setUUID("UUID", entry.getKey()); ++ cmp.setLong("Time", entry.getValue()); ++ list.add(cmp); ++ } ++ comp.set("lootedPlayers", list); ++ } ++ ++ if (!comp.isEmpty()) { ++ base.set("Paper.LootableData", comp); ++ } ++ } ++ ++ void setPlayerLootedState(UUID player, boolean looted) { ++ if (looted && this.lootedPlayers == null) { ++ this.lootedPlayers = new HashMap<>(); ++ } ++ if (looted) { ++ if (!this.lootedPlayers.containsKey(player)) { ++ this.lootedPlayers.put(player, System.currentTimeMillis()); ++ } ++ } else if (this.lootedPlayers != null) { ++ this.lootedPlayers.remove(player); ++ } ++ } ++ ++ boolean hasPlayerLooted(UUID player) { ++ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player); ++ } ++ ++ Long getLastLooted(UUID player) { ++ return lootedPlayers != null ? lootedPlayers.get(player) : null; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/EntityMinecartContainer.java b/src/main/java/net/minecraft/server/EntityMinecartContainer.java +index 19f9eb6..7216fa5 100644 +--- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java ++++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java +@@ -5,17 +5,21 @@ import javax.annotation.Nullable; + // CraftBukkit start + import java.util.List; + import org.bukkit.Location; ++ ++import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper ++import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper ++import com.destroystokyo.paper.loottable.LootableInventory; // Paper + import org.bukkit.craftbukkit.entity.CraftHumanEntity; + import org.bukkit.entity.HumanEntity; + import org.bukkit.inventory.InventoryHolder; + // CraftBukkit end + +-public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable { ++public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable, CraftLootableInventory { // Paper + + private ItemStack[] items = new ItemStack[27]; // CraftBukkit - 36 -> 27 + private boolean b = true; + private MinecraftKey c; +- private long d; ++ private long d;public long getLootTableSeed() { return d; } // Paper // OBFHELPER + + // CraftBukkit start + public List transaction = new java.util.ArrayList(); +@@ -141,6 +145,7 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp + + protected void b(NBTTagCompound nbttagcompound) { + super.b(nbttagcompound); ++ lootableData.saveNbt(nbttagcompound); // Paper + if (this.c != null) { + nbttagcompound.setString("LootTable", this.c.toString()); + if (this.d != 0L) { +@@ -167,6 +172,7 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp + protected void a(NBTTagCompound nbttagcompound) { + super.a(nbttagcompound); + this.items = new ItemStack[this.getSize()]; ++ lootableData.loadNbt(nbttagcompound); // Paper + if (nbttagcompound.hasKeyOfType("LootTable", 8)) { + this.c = new MinecraftKey(nbttagcompound.getString("LootTable")); + this.d = nbttagcompound.getLong("LootTableSeed"); +@@ -228,10 +234,10 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp + } + + public void f(@Nullable EntityHuman entityhuman) { +- if (this.c != null) { ++ if (lootableData.shouldReplenish(entityhuman)) { // Paper + LootTable loottable = this.world.ak().a(this.c); + +- this.c = null; ++ lootableData.processRefill(entityhuman); // Paper + Random random; + + if (this.d == 0L) { +@@ -260,12 +266,52 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp + + } + ++ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper // OBFHELPER + public void a(MinecraftKey minecraftkey, long i) { + this.c = minecraftkey; + this.d = i; + } + ++ ++ public MinecraftKey getLootTableKey() { return b(); } // Paper // OBFHELPER + public MinecraftKey b() { + return this.c; + } ++ ++ // Paper start ++ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this); ++ ++ @Override ++ public CraftLootableInventoryData getLootableData() { ++ return lootableData; ++ } ++ ++ @Override ++ public LootableInventory getAPILootableInventory() { ++ return (LootableInventory) this.getBukkitEntity(); ++ } ++ ++ @Override ++ public World getNMSWorld() { ++ return this.world; ++ } ++ ++ public String getLootTableName() { ++ final MinecraftKey key = getLootTableKey(); ++ return key != null ? key.toString() : null; ++ } ++ ++ @Override ++ public String setLootTable(String name, long seed) { ++ String prev = getLootTableName(); ++ setLootTable(new MinecraftKey(name), seed); ++ return prev; ++ } ++ ++ @Override ++ public void clearLootTable() { ++ //noinspection RedundantCast ++ this.c = (MinecraftKey) null; ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/server/TileEntityLootable.java b/src/main/java/net/minecraft/server/TileEntityLootable.java +index 3dc58bf..7717316 100644 +--- a/src/main/java/net/minecraft/server/TileEntityLootable.java ++++ b/src/main/java/net/minecraft/server/TileEntityLootable.java +@@ -1,16 +1,21 @@ + package net.minecraft.server; + ++import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper ++import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper ++import com.destroystokyo.paper.loottable.LootableInventory; // Paper ++ + import java.util.Random; + import javax.annotation.Nullable; + +-public abstract class TileEntityLootable extends TileEntityContainer implements ILootable { ++public abstract class TileEntityLootable extends TileEntityContainer implements ILootable, CraftLootableInventory { // Paper + + protected MinecraftKey m; +- protected long n; ++ protected long n; public long getLootTableSeed() { return n; } // Paper // OBFHELPER + + public TileEntityLootable() {} + + protected boolean d(NBTTagCompound nbttagcompound) { ++ lootableData.loadNbt(nbttagcompound); // Paper + if (nbttagcompound.hasKeyOfType("LootTable", 8)) { + this.m = new MinecraftKey(nbttagcompound.getString("LootTable")); + this.n = nbttagcompound.getLong("LootTableSeed"); +@@ -21,6 +26,7 @@ public abstract class TileEntityLootable extends TileEntityContainer implements + } + + protected boolean e(NBTTagCompound nbttagcompound) { ++ lootableData.saveNbt(nbttagcompound); // Paper + if (this.m != null) { + nbttagcompound.setString("LootTable", this.m.toString()); + if (this.n != 0L) { +@@ -34,10 +40,10 @@ public abstract class TileEntityLootable extends TileEntityContainer implements + } + + protected void d(@Nullable EntityHuman entityhuman) { +- if (this.m != null) { ++ if (lootableData.shouldReplenish(entityhuman)) { // Paper + LootTable loottable = this.world.ak().a(this.m); + +- this.m = null; ++ lootableData.processRefill(entityhuman); // Paper + Random random; + + if (this.n == 0L) { +@@ -57,12 +63,51 @@ public abstract class TileEntityLootable extends TileEntityContainer implements + + } + ++ public MinecraftKey getLootTableKey() { return b(); } // Paper // OBFHELPER + public MinecraftKey b() { + return this.m; + } + ++ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper // OBFHELPER + public void a(MinecraftKey minecraftkey, long i) { + this.m = minecraftkey; + this.n = i; + } ++ ++ // Paper start - LootTable API ++ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this); ++ ++ @Override ++ public CraftLootableInventoryData getLootableData() { ++ return lootableData; ++ } ++ ++ @Override ++ public LootableInventory getAPILootableInventory() { ++ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, getPosition())).getState(); ++ } ++ ++ @Override ++ public World getNMSWorld() { ++ return world; ++ } ++ ++ public String getLootTableName() { ++ final MinecraftKey key = getLootTableKey(); ++ return key != null ? key.toString() : null; ++ } ++ ++ @Override ++ public String setLootTable(String name, long seed) { ++ String prev = getLootTableName(); ++ setLootTable(new MinecraftKey(name), seed); ++ return prev; ++ } ++ ++ @Override ++ public void clearLootTable() { ++ //noinspection RedundantCast ++ this.m = (MinecraftKey) null; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +index ce36ee4..99b039b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.block; + ++import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper + import net.minecraft.server.BlockPosition; + import net.minecraft.server.TileEntityChest; + +@@ -11,7 +12,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory; + import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest; + import org.bukkit.inventory.Inventory; + +-public class CraftChest extends CraftBlockState implements Chest { ++public class CraftChest extends CraftBlockState implements Chest, CraftLootableBlockInventory { // Paper + private final CraftWorld world; + private final TileEntityChest chest; + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java +index a3ca3a5..cd7e65d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.block; + ++import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper + import net.minecraft.server.BlockDispenser; + import net.minecraft.server.BlockPosition; + import net.minecraft.server.Blocks; +@@ -14,7 +15,7 @@ import org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource; + import org.bukkit.inventory.Inventory; + import org.bukkit.projectiles.BlockProjectileSource; + +-public class CraftDispenser extends CraftBlockState implements Dispenser { ++public class CraftDispenser extends CraftBlockState implements Dispenser, CraftLootableBlockInventory { // Paper + private final CraftWorld world; + private final TileEntityDispenser dispenser; + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java +index db844a3..1e805a7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.block; + ++import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper + import net.minecraft.server.TileEntityHopper; + import org.bukkit.Material; + import org.bukkit.block.Block; +@@ -8,7 +9,7 @@ import org.bukkit.craftbukkit.CraftWorld; + import org.bukkit.craftbukkit.inventory.CraftInventory; + import org.bukkit.inventory.Inventory; + +-public class CraftHopper extends CraftBlockState implements Hopper { ++public class CraftHopper extends CraftBlockState implements Hopper, CraftLootableBlockInventory { // Paper + private final TileEntityHopper hopper; + + public CraftHopper(final Block block) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java +index f5a1875..b2c5679 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.entity; + ++import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper + import net.minecraft.server.EntityMinecartChest; + + import org.bukkit.craftbukkit.CraftServer; +@@ -9,7 +10,7 @@ import org.bukkit.entity.StorageMinecart; + import org.bukkit.inventory.Inventory; + + @SuppressWarnings("deprecation") +-public class CraftMinecartChest extends CraftMinecart implements StorageMinecart { ++public class CraftMinecartChest extends CraftMinecart implements StorageMinecart, CraftLootableEntityInventory { // Paper + private final CraftInventory inventory; + + public CraftMinecartChest(CraftServer server, EntityMinecartChest entity) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java +index e9963e2..acb4dee 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.entity; + ++import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper + import net.minecraft.server.EntityMinecartHopper; + + import org.bukkit.craftbukkit.CraftServer; +@@ -8,7 +9,7 @@ import org.bukkit.entity.EntityType; + import org.bukkit.entity.minecart.HopperMinecart; + import org.bukkit.inventory.Inventory; + +-final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart { ++final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart, CraftLootableEntityInventory { // Paper + private final CraftInventory inventory; + + CraftMinecartHopper(CraftServer server, EntityMinecartHopper entity) { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0148-Do-not-load-chunks-for-pathfinding.patch b/Spigot-Server-Patches/0148-Do-not-load-chunks-for-pathfinding.patch new file mode 100644 index 0000000000..33434d06c3 --- /dev/null +++ b/Spigot-Server-Patches/0148-Do-not-load-chunks-for-pathfinding.patch @@ -0,0 +1,22 @@ +From c410b547a8bf8a5fcb80ce9e2717d8219d1edc3d Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 19 Jan 2016 00:13:19 -0500 +Subject: [PATCH] Do not load chunks for pathfinding + + +diff --git a/src/main/java/net/minecraft/server/ChunkCache.java b/src/main/java/net/minecraft/server/ChunkCache.java +index a8fd64c..11c11cf 100644 +--- a/src/main/java/net/minecraft/server/ChunkCache.java ++++ b/src/main/java/net/minecraft/server/ChunkCache.java +@@ -25,7 +25,7 @@ public class ChunkCache implements IBlockAccess { + + for (l = this.a; l <= j; ++l) { + for (i1 = this.b; i1 <= k; ++i1) { +- this.c[l - this.a][i1 - this.b] = world.getChunkAt(l, i1); ++ this.c[l - this.a][i1 - this.b] = world.getChunkIfLoaded(l, i1); // Paper + } + } + +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0148-LootTable-API-Replenishable-Lootables-Feature.patch b/Spigot-Server-Patches/0148-LootTable-API-Replenishable-Lootables-Feature.patch deleted file mode 100644 index 4a67eba775..0000000000 --- a/Spigot-Server-Patches/0148-LootTable-API-Replenishable-Lootables-Feature.patch +++ /dev/null @@ -1,733 +0,0 @@ -From ba491f530be8703553a9b5f2f5b24a330519ba4c Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 1 May 2016 21:19:14 -0400 -Subject: [PATCH] LootTable API & Replenishable Lootables Feature - -Provides an API to control the loot table for an object. -Also provides a feature that any Lootable Inventory (Chests in Structures) -can automatically replenish after a given time. - -This feature is good for long term worlds so that newer players -do not suffer with "Every chest has been looted" - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index ccc11a8..9c79f2e 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -344,4 +344,26 @@ public class PaperWorldConfig { - this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); - this.log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); - } -+ -+ public boolean autoReplenishLootables; -+ public boolean restrictPlayerReloot; -+ public boolean changeLootTableSeedOnFill; -+ public int maxLootableRefills; -+ public int lootableRegenMin; -+ public int lootableRegenMax; -+ private void enhancedLootables() { -+ autoReplenishLootables = getBoolean("lootables.auto-replenish", false); -+ restrictPlayerReloot = getBoolean("lootables.restrict-player-reloot", true); -+ changeLootTableSeedOnFill = getBoolean("lootables.reset-seed-on-fill", true); -+ maxLootableRefills = getInt("lootables.max-refills", -1); -+ lootableRegenMin = PaperConfig.getSeconds(getString("lootables.refresh-min", "12h")); -+ lootableRegenMax = PaperConfig.getSeconds(getString("lootables.refresh-max", "2d")); -+ if (autoReplenishLootables) { -+ log("Lootables: Replenishing every " + -+ PaperConfig.timeSummary(lootableRegenMin) + " to " + -+ PaperConfig.timeSummary(lootableRegenMax) + -+ (restrictPlayerReloot ? " (restricting reloot)" : "") -+ ); -+ } -+ } - } -diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java -new file mode 100644 -index 0000000..36c36d1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java -@@ -0,0 +1,12 @@ -+package com.destroystokyo.paper.loottable; -+ -+import net.minecraft.server.World; -+ -+interface CraftLootable extends Lootable { -+ -+ World getNMSWorld(); -+ -+ default org.bukkit.World getBukkitWorld() { -+ return getNMSWorld().getWorld(); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java -new file mode 100644 -index 0000000..20d236c ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java -@@ -0,0 +1,33 @@ -+package com.destroystokyo.paper.loottable; -+ -+import net.minecraft.server.BlockPosition; -+import net.minecraft.server.TileEntityLootable; -+import net.minecraft.server.World; -+import org.bukkit.Chunk; -+import org.bukkit.block.Block; -+ -+public interface CraftLootableBlockInventory extends LootableBlockInventory, CraftLootableInventory { -+ -+ TileEntityLootable getTileEntity(); -+ -+ @Override -+ default LootableInventory getAPILootableInventory() { -+ return this; -+ } -+ -+ @Override -+ default World getNMSWorld() { -+ return getTileEntity().getWorld(); -+ } -+ -+ default Block getBlock() { -+ final BlockPosition position = getTileEntity().getPosition(); -+ final Chunk bukkitChunk = getTileEntity().getWorld().getChunkAtWorldCoords(position).bukkitChunk; -+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ()); -+ } -+ -+ @Override -+ default CraftLootableInventoryData getLootableData() { -+ return getTileEntity().getLootableData(); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java -new file mode 100644 -index 0000000..1150dee ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java -@@ -0,0 +1,31 @@ -+package com.destroystokyo.paper.loottable; -+ -+import net.minecraft.server.World; -+import org.bukkit.entity.Entity; -+ -+public interface CraftLootableEntityInventory extends LootableEntityInventory, CraftLootableInventory { -+ -+ net.minecraft.server.Entity getHandle(); -+ -+ @Override -+ default LootableInventory getAPILootableInventory() { -+ return this; -+ } -+ -+ default Entity getEntity() { -+ return getHandle().getBukkitEntity(); -+ } -+ -+ @Override -+ default World getNMSWorld() { -+ return getHandle().getWorld(); -+ } -+ -+ @Override -+ default CraftLootableInventoryData getLootableData() { -+ if (getHandle() instanceof CraftLootableInventory) { -+ return ((CraftLootableInventory) getHandle()).getLootableData(); -+ } -+ return null; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java -new file mode 100644 -index 0000000..6680976 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java -@@ -0,0 +1,88 @@ -+package com.destroystokyo.paper.loottable; -+ -+import org.apache.commons.lang.Validate; -+ -+import java.util.UUID; -+ -+public interface CraftLootableInventory extends CraftLootable, LootableInventory { -+ -+ CraftLootableInventoryData getLootableData(); -+ LootableInventory getAPILootableInventory(); -+ -+ @Override -+ default boolean isRefillEnabled() { -+ return getNMSWorld().paperConfig.autoReplenishLootables; -+ } -+ -+ @Override -+ default boolean hasBeenFilled() { -+ return getLastFilled() != -1; -+ } -+ -+ @Override -+ default String getLootTableName() { -+ return getLootableData().getLootable().getLootTableName(); -+ } -+ -+ @Override -+ default String setLootTable(String name, long seed) { -+ Validate.notNull(name); -+ -+ String prevLootTable = getLootTableName(); -+ getLootableData().getLootable().setLootTable(name, seed); -+ return prevLootTable; -+ } -+ -+ @Override -+ default long getLootTableSeed() { -+ return getLootableData().getLootable().getLootTableSeed(); -+ } -+ -+ @Override -+ default void clearLootTable() { -+ getLootableData().getLootable().clearLootTable(); -+ } -+ -+ @Override -+ default boolean hasPlayerLooted(UUID player) { -+ return getLootableData().hasPlayerLooted(player); -+ } -+ -+ @Override -+ default Long getLastLooted(UUID player) { -+ return getLootableData().getLastLooted(player); -+ } -+ -+ @Override -+ default boolean setHasPlayerLooted(UUID player, boolean looted) { -+ final boolean hasLooted = hasPlayerLooted(player); -+ if (hasLooted != looted) { -+ getLootableData().setPlayerLootedState(player, looted); -+ } -+ return hasLooted; -+ } -+ -+ @Override -+ default boolean hasPendingRefill() { -+ long nextRefill = getLootableData().getNextRefill(); -+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill(); -+ } -+ -+ @Override -+ default long getLastFilled() { -+ return getLootableData().getLastFill(); -+ } -+ -+ @Override -+ default long getNextRefill() { -+ return getLootableData().getNextRefill(); -+ } -+ -+ @Override -+ default long setNextRefill(long refillAt) { -+ if (refillAt < -1) { -+ refillAt = -1; -+ } -+ return getLootableData().setNextRefill(refillAt); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java -new file mode 100644 -index 0000000..01c2713 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java -@@ -0,0 +1,182 @@ -+package com.destroystokyo.paper.loottable; -+ -+import com.destroystokyo.paper.PaperWorldConfig; -+import net.minecraft.server.*; -+import org.bukkit.entity.Player; -+ -+import javax.annotation.Nullable; -+import java.util.HashMap; -+import java.util.Map; -+import java.util.Random; -+import java.util.UUID; -+ -+public class CraftLootableInventoryData { -+ -+ private static final Random RANDOM = new Random(); -+ -+ private long lastFill = -1; -+ private long nextRefill = -1; -+ private int numRefills = 0; -+ private Map lootedPlayers; -+ private final CraftLootableInventory lootable; -+ -+ public CraftLootableInventoryData(CraftLootableInventory lootable) { -+ this.lootable = lootable; -+ } -+ -+ long getLastFill() { -+ return this.lastFill; -+ } -+ -+ long getNextRefill() { -+ return this.nextRefill; -+ } -+ -+ long setNextRefill(long nextRefill) { -+ long prev = this.nextRefill; -+ this.nextRefill = nextRefill; -+ return prev; -+ } -+ -+ CraftLootableInventory getLootable() { -+ return lootable; -+ } -+ -+ public boolean shouldReplenish(@Nullable EntityHuman player) { -+ String tableName = this.lootable.getLootTableName(); -+ -+ // No Loot Table associated -+ if (tableName == null) { -+ return false; -+ } -+ -+ // ALWAYS process the first fill -+ if (this.lastFill == -1) { -+ return true; -+ } -+ -+ // Only process refills when a player is set -+ if (player == null) { -+ return false; -+ } -+ -+ // Chest is not scheduled for refill -+ if (this.nextRefill == -1) { -+ return false; -+ } -+ -+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; -+ -+ // Check if max refills has been hit -+ if (paperConfig.maxLootableRefills != -1 && this.numRefills >= paperConfig.maxLootableRefills) { -+ return false; -+ } -+ -+ // Refill has not been reached -+ if (this.nextRefill > System.currentTimeMillis()) { -+ return false; -+ } -+ -+ -+ final Player bukkitPlayer = (Player) player.getBukkitEntity(); -+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory()); -+ if (paperConfig.restrictPlayerReloot && hasPlayerLooted(player.getUniqueID())) { -+ event.setCancelled(true); -+ } -+ return event.callEvent(); -+ } -+ public void processRefill(@Nullable EntityHuman player) { -+ this.lastFill = System.currentTimeMillis(); -+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; -+ if (paperConfig.autoReplenishLootables) { -+ int min = paperConfig.lootableRegenMin * 1000; -+ int max = paperConfig.lootableRegenMax * 1000; -+ this.nextRefill = this.lastFill + min + RANDOM.nextInt(max - min + 1); -+ this.numRefills++; -+ if (paperConfig.changeLootTableSeedOnFill) { -+ this.lootable.setLootTableSeed(0); -+ } -+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific -+ this.setPlayerLootedState(player.getUniqueID(), true); -+ } -+ } else { -+ this.lootable.clearLootTable(); -+ } -+ } -+ -+ -+ public void loadNbt(NBTTagCompound base) { -+ if (!base.hasKeyOfType("Paper.LootableData", 10)) { // 10 = compound -+ return; -+ } -+ NBTTagCompound comp = base.getCompound("Paper.LootableData"); -+ if (comp.hasKey("lastFill")) { -+ this.lastFill = comp.getLong("lastFill"); -+ } -+ if (comp.hasKey("nextRefill")) { -+ this.nextRefill = comp.getLong("nextRefill"); -+ } -+ -+ if (comp.hasKey("numRefills")) { -+ this.numRefills = comp.getInt("numRefills"); -+ } -+ if (comp.hasKeyOfType("lootedPlayers", 9)) { // 9 = list -+ NBTTagList list = comp.getList("lootedPlayers", 10); // 10 = compound -+ final int size = list.size(); -+ if (size > 0) { -+ this.lootedPlayers = new HashMap<>(list.size()); -+ } -+ for (int i = 0; i < size; i++) { -+ final NBTTagCompound cmp = list.get(i); -+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time")); -+ } -+ } -+ } -+ public void saveNbt(NBTTagCompound base) { -+ NBTTagCompound comp = new NBTTagCompound(); -+ if (this.nextRefill != -1) { -+ comp.setLong("nextRefill", this.nextRefill); -+ } -+ if (this.lastFill != -1) { -+ comp.setLong("lastFill", this.lastFill); -+ } -+ if (this.numRefills != 0) { -+ comp.setInt("numRefills", this.numRefills); -+ } -+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) { -+ NBTTagList list = new NBTTagList(); -+ for (Map.Entry entry : this.lootedPlayers.entrySet()) { -+ NBTTagCompound cmp = new NBTTagCompound(); -+ cmp.setUUID("UUID", entry.getKey()); -+ cmp.setLong("Time", entry.getValue()); -+ list.add(cmp); -+ } -+ comp.set("lootedPlayers", list); -+ } -+ -+ if (!comp.isEmpty()) { -+ base.set("Paper.LootableData", comp); -+ } -+ } -+ -+ void setPlayerLootedState(UUID player, boolean looted) { -+ if (looted && this.lootedPlayers == null) { -+ this.lootedPlayers = new HashMap<>(); -+ } -+ if (looted) { -+ if (!this.lootedPlayers.containsKey(player)) { -+ this.lootedPlayers.put(player, System.currentTimeMillis()); -+ } -+ } else if (this.lootedPlayers != null) { -+ this.lootedPlayers.remove(player); -+ } -+ } -+ -+ boolean hasPlayerLooted(UUID player) { -+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player); -+ } -+ -+ Long getLastLooted(UUID player) { -+ return lootedPlayers != null ? lootedPlayers.get(player) : null; -+ } -+} -diff --git a/src/main/java/net/minecraft/server/EntityMinecartContainer.java b/src/main/java/net/minecraft/server/EntityMinecartContainer.java -index 19f9eb6..7216fa5 100644 ---- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java -+++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java -@@ -5,17 +5,21 @@ import javax.annotation.Nullable; - // CraftBukkit start - import java.util.List; - import org.bukkit.Location; -+ -+import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper -+import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper -+import com.destroystokyo.paper.loottable.LootableInventory; // Paper - import org.bukkit.craftbukkit.entity.CraftHumanEntity; - import org.bukkit.entity.HumanEntity; - import org.bukkit.inventory.InventoryHolder; - // CraftBukkit end - --public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable { -+public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable, CraftLootableInventory { // Paper - - private ItemStack[] items = new ItemStack[27]; // CraftBukkit - 36 -> 27 - private boolean b = true; - private MinecraftKey c; -- private long d; -+ private long d;public long getLootTableSeed() { return d; } // Paper // OBFHELPER - - // CraftBukkit start - public List transaction = new java.util.ArrayList(); -@@ -141,6 +145,7 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp - - protected void b(NBTTagCompound nbttagcompound) { - super.b(nbttagcompound); -+ lootableData.saveNbt(nbttagcompound); // Paper - if (this.c != null) { - nbttagcompound.setString("LootTable", this.c.toString()); - if (this.d != 0L) { -@@ -167,6 +172,7 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp - protected void a(NBTTagCompound nbttagcompound) { - super.a(nbttagcompound); - this.items = new ItemStack[this.getSize()]; -+ lootableData.loadNbt(nbttagcompound); // Paper - if (nbttagcompound.hasKeyOfType("LootTable", 8)) { - this.c = new MinecraftKey(nbttagcompound.getString("LootTable")); - this.d = nbttagcompound.getLong("LootTableSeed"); -@@ -228,10 +234,10 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp - } - - public void f(@Nullable EntityHuman entityhuman) { -- if (this.c != null) { -+ if (lootableData.shouldReplenish(entityhuman)) { // Paper - LootTable loottable = this.world.ak().a(this.c); - -- this.c = null; -+ lootableData.processRefill(entityhuman); // Paper - Random random; - - if (this.d == 0L) { -@@ -260,12 +266,52 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp - - } - -+ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper // OBFHELPER - public void a(MinecraftKey minecraftkey, long i) { - this.c = minecraftkey; - this.d = i; - } - -+ -+ public MinecraftKey getLootTableKey() { return b(); } // Paper // OBFHELPER - public MinecraftKey b() { - return this.c; - } -+ -+ // Paper start -+ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this); -+ -+ @Override -+ public CraftLootableInventoryData getLootableData() { -+ return lootableData; -+ } -+ -+ @Override -+ public LootableInventory getAPILootableInventory() { -+ return (LootableInventory) this.getBukkitEntity(); -+ } -+ -+ @Override -+ public World getNMSWorld() { -+ return this.world; -+ } -+ -+ public String getLootTableName() { -+ final MinecraftKey key = getLootTableKey(); -+ return key != null ? key.toString() : null; -+ } -+ -+ @Override -+ public String setLootTable(String name, long seed) { -+ String prev = getLootTableName(); -+ setLootTable(new MinecraftKey(name), seed); -+ return prev; -+ } -+ -+ @Override -+ public void clearLootTable() { -+ //noinspection RedundantCast -+ this.c = (MinecraftKey) null; -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/server/TileEntityLootable.java b/src/main/java/net/minecraft/server/TileEntityLootable.java -index 3dc58bf..7717316 100644 ---- a/src/main/java/net/minecraft/server/TileEntityLootable.java -+++ b/src/main/java/net/minecraft/server/TileEntityLootable.java -@@ -1,16 +1,21 @@ - package net.minecraft.server; - -+import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper -+import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper -+import com.destroystokyo.paper.loottable.LootableInventory; // Paper -+ - import java.util.Random; - import javax.annotation.Nullable; - --public abstract class TileEntityLootable extends TileEntityContainer implements ILootable { -+public abstract class TileEntityLootable extends TileEntityContainer implements ILootable, CraftLootableInventory { // Paper - - protected MinecraftKey m; -- protected long n; -+ protected long n; public long getLootTableSeed() { return n; } // Paper // OBFHELPER - - public TileEntityLootable() {} - - protected boolean d(NBTTagCompound nbttagcompound) { -+ lootableData.loadNbt(nbttagcompound); // Paper - if (nbttagcompound.hasKeyOfType("LootTable", 8)) { - this.m = new MinecraftKey(nbttagcompound.getString("LootTable")); - this.n = nbttagcompound.getLong("LootTableSeed"); -@@ -21,6 +26,7 @@ public abstract class TileEntityLootable extends TileEntityContainer implements - } - - protected boolean e(NBTTagCompound nbttagcompound) { -+ lootableData.saveNbt(nbttagcompound); // Paper - if (this.m != null) { - nbttagcompound.setString("LootTable", this.m.toString()); - if (this.n != 0L) { -@@ -34,10 +40,10 @@ public abstract class TileEntityLootable extends TileEntityContainer implements - } - - protected void d(@Nullable EntityHuman entityhuman) { -- if (this.m != null) { -+ if (lootableData.shouldReplenish(entityhuman)) { // Paper - LootTable loottable = this.world.ak().a(this.m); - -- this.m = null; -+ lootableData.processRefill(entityhuman); // Paper - Random random; - - if (this.n == 0L) { -@@ -57,12 +63,51 @@ public abstract class TileEntityLootable extends TileEntityContainer implements - - } - -+ public MinecraftKey getLootTableKey() { return b(); } // Paper // OBFHELPER - public MinecraftKey b() { - return this.m; - } - -+ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper // OBFHELPER - public void a(MinecraftKey minecraftkey, long i) { - this.m = minecraftkey; - this.n = i; - } -+ -+ // Paper start - LootTable API -+ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this); -+ -+ @Override -+ public CraftLootableInventoryData getLootableData() { -+ return lootableData; -+ } -+ -+ @Override -+ public LootableInventory getAPILootableInventory() { -+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, getPosition())).getState(); -+ } -+ -+ @Override -+ public World getNMSWorld() { -+ return world; -+ } -+ -+ public String getLootTableName() { -+ final MinecraftKey key = getLootTableKey(); -+ return key != null ? key.toString() : null; -+ } -+ -+ @Override -+ public String setLootTable(String name, long seed) { -+ String prev = getLootTableName(); -+ setLootTable(new MinecraftKey(name), seed); -+ return prev; -+ } -+ -+ @Override -+ public void clearLootTable() { -+ //noinspection RedundantCast -+ this.m = (MinecraftKey) null; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -index ce36ee4..99b039b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.block; - -+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper - import net.minecraft.server.BlockPosition; - import net.minecraft.server.TileEntityChest; - -@@ -11,7 +12,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory; - import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest; - import org.bukkit.inventory.Inventory; - --public class CraftChest extends CraftBlockState implements Chest { -+public class CraftChest extends CraftBlockState implements Chest, CraftLootableBlockInventory { // Paper - private final CraftWorld world; - private final TileEntityChest chest; - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java -index a3ca3a5..cd7e65d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.block; - -+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper - import net.minecraft.server.BlockDispenser; - import net.minecraft.server.BlockPosition; - import net.minecraft.server.Blocks; -@@ -14,7 +15,7 @@ import org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource; - import org.bukkit.inventory.Inventory; - import org.bukkit.projectiles.BlockProjectileSource; - --public class CraftDispenser extends CraftBlockState implements Dispenser { -+public class CraftDispenser extends CraftBlockState implements Dispenser, CraftLootableBlockInventory { // Paper - private final CraftWorld world; - private final TileEntityDispenser dispenser; - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -index db844a3..1e805a7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.block; - -+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper - import net.minecraft.server.TileEntityHopper; - import org.bukkit.Material; - import org.bukkit.block.Block; -@@ -8,7 +9,7 @@ import org.bukkit.craftbukkit.CraftWorld; - import org.bukkit.craftbukkit.inventory.CraftInventory; - import org.bukkit.inventory.Inventory; - --public class CraftHopper extends CraftBlockState implements Hopper { -+public class CraftHopper extends CraftBlockState implements Hopper, CraftLootableBlockInventory { // Paper - private final TileEntityHopper hopper; - - public CraftHopper(final Block block) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java -index f5a1875..b2c5679 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.entity; - -+import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper - import net.minecraft.server.EntityMinecartChest; - - import org.bukkit.craftbukkit.CraftServer; -@@ -9,7 +10,7 @@ import org.bukkit.entity.StorageMinecart; - import org.bukkit.inventory.Inventory; - - @SuppressWarnings("deprecation") --public class CraftMinecartChest extends CraftMinecart implements StorageMinecart { -+public class CraftMinecartChest extends CraftMinecart implements StorageMinecart, CraftLootableEntityInventory { // Paper - private final CraftInventory inventory; - - public CraftMinecartChest(CraftServer server, EntityMinecartChest entity) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -index e9963e2..acb4dee 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.entity; - -+import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper - import net.minecraft.server.EntityMinecartHopper; - - import org.bukkit.craftbukkit.CraftServer; -@@ -8,7 +9,7 @@ import org.bukkit.entity.EntityType; - import org.bukkit.entity.minecart.HopperMinecart; - import org.bukkit.inventory.Inventory; - --final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart { -+final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart, CraftLootableEntityInventory { // Paper - private final CraftInventory inventory; - - CraftMinecartHopper(CraftServer server, EntityMinecartHopper entity) { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0149-Do-not-load-chunks-for-pathfinding.patch b/Spigot-Server-Patches/0149-Do-not-load-chunks-for-pathfinding.patch deleted file mode 100644 index 1e5b83602c..0000000000 --- a/Spigot-Server-Patches/0149-Do-not-load-chunks-for-pathfinding.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 66f472758c6daa56f3b4a702d0a381fc4a8c5e8c Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 19 Jan 2016 00:13:19 -0500 -Subject: [PATCH] Do not load chunks for pathfinding - - -diff --git a/src/main/java/net/minecraft/server/ChunkCache.java b/src/main/java/net/minecraft/server/ChunkCache.java -index a8fd64c..11c11cf 100644 ---- a/src/main/java/net/minecraft/server/ChunkCache.java -+++ b/src/main/java/net/minecraft/server/ChunkCache.java -@@ -25,7 +25,7 @@ public class ChunkCache implements IBlockAccess { - - for (l = this.a; l <= j; ++l) { - for (i1 = this.b; i1 <= k; ++i1) { -- this.c[l - this.a][i1 - this.b] = world.getChunkAt(l, i1); -+ this.c[l - this.a][i1 - this.b] = world.getChunkIfLoaded(l, i1); // Paper - } - } - --- -2.8.2 - diff --git a/Spigot-Server-Patches/0149-Entity-Tracking-Improvements.patch b/Spigot-Server-Patches/0149-Entity-Tracking-Improvements.patch new file mode 100644 index 0000000000..ecab32f5cd --- /dev/null +++ b/Spigot-Server-Patches/0149-Entity-Tracking-Improvements.patch @@ -0,0 +1,103 @@ +From 918008d4358443f08f3da80724ad524c25c1f4eb Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 17 Jun 2013 01:24:00 -0400 +Subject: [PATCH] Entity Tracking Improvements + +If any part of a Vehicle/Passenger relationship is visible to a player, +send all passenger/vehicles to the player in the chain. + +diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java +index 2374a35..02a1c25 100644 +--- a/src/main/java/net/minecraft/server/Entity.java ++++ b/src/main/java/net/minecraft/server/Entity.java +@@ -51,6 +51,7 @@ public abstract class Entity implements ICommandListener { + + protected CraftEntity bukkitEntity; + ++ EntityTrackerEntry tracker; // Paper + public CraftEntity getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = CraftEntity.getEntity(world.getServer(), this); +diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java +index 38e88d8..a783ecb 100644 +--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java ++++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java +@@ -49,6 +49,7 @@ public class EntityTrackerEntry { + // Paper end + + public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) { ++ entity.tracker = this; // Paper + this.tracker = entity; + this.e = i; + this.f = j; +@@ -440,17 +441,59 @@ public class EntityTrackerEntry { + + this.tracker.b(entityplayer); + entityplayer.d(this.tracker); ++ updatePassengers(entityplayer); // Paper + } + } else if (this.trackedPlayers.contains(entityplayer)) { + this.trackedPlayers.remove(entityplayer); + this.tracker.c(entityplayer); + entityplayer.c(this.tracker); ++ updatePassengers(entityplayer); // Paper + } + + } + } + + public boolean c(EntityPlayer entityplayer) { ++ // Paper start ++ if (tracker.isPassenger()) { ++ return isTrackedBy(tracker.getVehicle(), entityplayer); ++ } else if (hasPassengerInRange(tracker, entityplayer)) { ++ return true; ++ } ++ ++ return isInRangeOfPlayer(entityplayer); ++ } ++ private static boolean hasPassengerInRange(Entity entity, EntityPlayer entityplayer) { ++ if (!entity.isVehicle()) { ++ return false; ++ } ++ for (Entity passenger : entity.passengers) { ++ if (passenger.tracker != null && passenger.tracker.isInRangeOfPlayer(entityplayer)) { ++ return true; ++ } ++ if (passenger.isVehicle()) { ++ if (hasPassengerInRange(passenger, entityplayer)) { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ private static boolean isTrackedBy(Entity entity, EntityPlayer entityplayer) { ++ return entity.tracker != null && entity.tracker.trackedPlayers.contains(entityplayer); ++ } ++ private void updatePassengers(EntityPlayer player) { ++ if (tracker.isVehicle()) { ++ tracker.passengers.forEach((e) -> { ++ if (e.tracker != null) { ++ e.tracker.updatePlayer(player); ++ } ++ }); ++ player.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker)); ++ } ++ } ++ private boolean isInRangeOfPlayer(EntityPlayer entityplayer) { ++ // Paper end + double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D; + double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D; + int i = Math.min(this.e, this.f); +@@ -583,6 +626,7 @@ public class EntityTrackerEntry { + this.trackedPlayers.remove(entityplayer); + this.tracker.c(entityplayer); + entityplayer.c(this.tracker); ++ updatePassengers(entityplayer); // Paper + } + + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0150-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch b/Spigot-Server-Patches/0150-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch new file mode 100644 index 0000000000..93c5366975 --- /dev/null +++ b/Spigot-Server-Patches/0150-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch @@ -0,0 +1,35 @@ +From 96b982b083de4b5304dcc0defbce9d2d5a32d69e Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 7 May 2016 23:33:08 -0400 +Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +index e234c41..c0b6bf1 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java +@@ -223,4 +223,9 @@ public class PaperConfig { + private static void enablePlayerCollisions() { + enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true); + } ++ ++ public static boolean saveEmptyScoreboardTeams = false; ++ private static void saveEmptyScoreboardTeams() { ++ saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false); ++ } + } +diff --git a/src/main/java/net/minecraft/server/PersistentScoreboard.java b/src/main/java/net/minecraft/server/PersistentScoreboard.java +index 230004b..62752f8 100644 +--- a/src/main/java/net/minecraft/server/PersistentScoreboard.java ++++ b/src/main/java/net/minecraft/server/PersistentScoreboard.java +@@ -184,6 +184,7 @@ public class PersistentScoreboard extends PersistentBase { + + while (iterator.hasNext()) { + ScoreboardTeam scoreboardteam = (ScoreboardTeam) iterator.next(); ++ if (!com.destroystokyo.paper.PaperConfig.saveEmptyScoreboardTeams && scoreboardteam.getPlayerNameSet().isEmpty()) continue; // Paper + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + nbttagcompound.setString("Name", scoreboardteam.getName()); +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0150-Entity-Tracking-Improvements.patch b/Spigot-Server-Patches/0150-Entity-Tracking-Improvements.patch deleted file mode 100644 index 888e236441..0000000000 --- a/Spigot-Server-Patches/0150-Entity-Tracking-Improvements.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 62e510d99d8349b4b4b97604ba2a554a83fcf8f0 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 17 Jun 2013 01:24:00 -0400 -Subject: [PATCH] Entity Tracking Improvements - -If any part of a Vehicle/Passenger relationship is visible to a player, -send all passenger/vehicles to the player in the chain. - -diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index 2374a35..02a1c25 100644 ---- a/src/main/java/net/minecraft/server/Entity.java -+++ b/src/main/java/net/minecraft/server/Entity.java -@@ -51,6 +51,7 @@ public abstract class Entity implements ICommandListener { - - protected CraftEntity bukkitEntity; - -+ EntityTrackerEntry tracker; // Paper - public CraftEntity getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = CraftEntity.getEntity(world.getServer(), this); -diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -index 38e88d8..a783ecb 100644 ---- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java -+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java -@@ -49,6 +49,7 @@ public class EntityTrackerEntry { - // Paper end - - public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) { -+ entity.tracker = this; // Paper - this.tracker = entity; - this.e = i; - this.f = j; -@@ -440,17 +441,59 @@ public class EntityTrackerEntry { - - this.tracker.b(entityplayer); - entityplayer.d(this.tracker); -+ updatePassengers(entityplayer); // Paper - } - } else if (this.trackedPlayers.contains(entityplayer)) { - this.trackedPlayers.remove(entityplayer); - this.tracker.c(entityplayer); - entityplayer.c(this.tracker); -+ updatePassengers(entityplayer); // Paper - } - - } - } - - public boolean c(EntityPlayer entityplayer) { -+ // Paper start -+ if (tracker.isPassenger()) { -+ return isTrackedBy(tracker.getVehicle(), entityplayer); -+ } else if (hasPassengerInRange(tracker, entityplayer)) { -+ return true; -+ } -+ -+ return isInRangeOfPlayer(entityplayer); -+ } -+ private static boolean hasPassengerInRange(Entity entity, EntityPlayer entityplayer) { -+ if (!entity.isVehicle()) { -+ return false; -+ } -+ for (Entity passenger : entity.passengers) { -+ if (passenger.tracker != null && passenger.tracker.isInRangeOfPlayer(entityplayer)) { -+ return true; -+ } -+ if (passenger.isVehicle()) { -+ if (hasPassengerInRange(passenger, entityplayer)) { -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ private static boolean isTrackedBy(Entity entity, EntityPlayer entityplayer) { -+ return entity.tracker != null && entity.tracker.trackedPlayers.contains(entityplayer); -+ } -+ private void updatePassengers(EntityPlayer player) { -+ if (tracker.isVehicle()) { -+ tracker.passengers.forEach((e) -> { -+ if (e.tracker != null) { -+ e.tracker.updatePlayer(player); -+ } -+ }); -+ player.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker)); -+ } -+ } -+ private boolean isInRangeOfPlayer(EntityPlayer entityplayer) { -+ // Paper end - double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D; - double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D; - int i = Math.min(this.e, this.f); -@@ -583,6 +626,7 @@ public class EntityTrackerEntry { - this.trackedPlayers.remove(entityplayer); - this.tracker.c(entityplayer); - entityplayer.c(this.tracker); -+ updatePassengers(entityplayer); // Paper - } - - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0151-Do-not-mark-chunks-as-active-for-neighbor-updates.patch b/Spigot-Server-Patches/0151-Do-not-mark-chunks-as-active-for-neighbor-updates.patch new file mode 100644 index 0000000000..c4ddd70085 --- /dev/null +++ b/Spigot-Server-Patches/0151-Do-not-mark-chunks-as-active-for-neighbor-updates.patch @@ -0,0 +1,113 @@ +From a7138126f853f5b09a48a0e348dbaf7dd93c39a8 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 12 May 2016 01:55:17 -0400 +Subject: [PATCH] Do not mark chunks as active for neighbor updates + +Fixes chunk unload issues + +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 904141a..d7b9581 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -991,25 +991,25 @@ public class Chunk { + + public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator) { + world.timings.syncChunkLoadPostTimer.startTiming(); // Spigot +- Chunk chunk = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ - 1); +- Chunk chunk1 = ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ); +- Chunk chunk2 = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ + 1); +- Chunk chunk3 = ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ); ++ Chunk chunk = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX, this.locZ - 1); // Paper ++ Chunk chunk1 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ); // Paper ++ Chunk chunk2 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX, this.locZ + 1); // Paper ++ Chunk chunk3 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ); // Paper + +- if (chunk1 != null && chunk2 != null && ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ + 1) != null) { ++ if (chunk1 != null && chunk2 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ + 1) != null) { // Paper + this.a(chunkgenerator); + } + +- if (chunk3 != null && chunk2 != null && ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ + 1) != null) { ++ if (chunk3 != null && chunk2 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ + 1) != null) { // Paper + chunk3.a(chunkgenerator); + } + +- if (chunk != null && chunk1 != null && ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ - 1) != null) { ++ if (chunk != null && chunk1 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ - 1) != null) { // Paper + chunk.a(chunkgenerator); + } + + if (chunk != null && chunk3 != null) { +- Chunk chunk4 = ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ - 1); ++ Chunk chunk4 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ - 1); // Paper + + if (chunk4 != null) { + chunk4.a(chunkgenerator); +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index f8905b4..6d1b98b 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -203,7 +203,7 @@ public class ChunkProviderServer implements IChunkProvider { + continue; + } + +- Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(this, chunk.locX + x, chunk.locZ + z); // Paper + if (neighbor != null) { + neighbor.setNeighborLoaded(-x, -z); + chunk.setNeighborLoaded(x, z); +@@ -324,7 +324,7 @@ public class ChunkProviderServer implements IChunkProvider { + continue; + } + +- Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(this, chunk.locX + x, chunk.locZ + z); // Paper + if (neighbor != null) { + neighbor.setNeighborUnloaded(-x, -z); + chunk.setNeighborUnloaded(x, z); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 6a3e939..b1a7435 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -241,7 +241,7 @@ public class CraftWorld implements World { + continue; + } + +- net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ net.minecraft.server.Chunk neighbor = net.minecraft.server.MCUtil.getLoadedChunkWithoutMarkingActive(world, chunk.locX + x, chunk.locZ + z); // Paper + if (neighbor != null) { + neighbor.setNeighborUnloaded(-xx, -zz); + chunk.setNeighborUnloaded(xx, zz); +@@ -328,7 +328,7 @@ public class CraftWorld implements World { + continue; + } + +- net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getLoadedChunkAt(chunk.locX + x, chunk.locZ + z); ++ net.minecraft.server.Chunk neighbor = net.minecraft.server.MCUtil.getLoadedChunkWithoutMarkingActive(world, chunk.locX + x, chunk.locZ + z); // Paper + if (neighbor != null) { + neighbor.setNeighborLoaded(-x, -z); + chunk.setNeighborLoaded(x, z); +diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java +index 7b61b14..7752b50 100644 +--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java ++++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java +@@ -5,7 +5,6 @@ import net.minecraft.server.Chunk; + import net.minecraft.server.ChunkCoordIntPair; + import net.minecraft.server.ChunkRegionLoader; + import net.minecraft.server.NBTTagCompound; +- + import org.bukkit.Server; + import org.bukkit.craftbukkit.util.AsynchronousExecutor; + +@@ -62,7 +61,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider -Date: Sat, 7 May 2016 23:33:08 -0400 -Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat - - -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 1199fa2..f5f1e2a 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -223,4 +223,9 @@ public class PaperConfig { - private static void enablePlayerCollisions() { - enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true); - } -+ -+ public static boolean saveEmptyScoreboardTeams = false; -+ private static void saveEmptyScoreboardTeams() { -+ saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false); -+ } - } -diff --git a/src/main/java/net/minecraft/server/PersistentScoreboard.java b/src/main/java/net/minecraft/server/PersistentScoreboard.java -index 230004b..62752f8 100644 ---- a/src/main/java/net/minecraft/server/PersistentScoreboard.java -+++ b/src/main/java/net/minecraft/server/PersistentScoreboard.java -@@ -184,6 +184,7 @@ public class PersistentScoreboard extends PersistentBase { - - while (iterator.hasNext()) { - ScoreboardTeam scoreboardteam = (ScoreboardTeam) iterator.next(); -+ if (!com.destroystokyo.paper.PaperConfig.saveEmptyScoreboardTeams && scoreboardteam.getPlayerNameSet().isEmpty()) continue; // Paper - NBTTagCompound nbttagcompound = new NBTTagCompound(); - - nbttagcompound.setString("Name", scoreboardteam.getName()); --- -2.8.2 - diff --git a/Spigot-Server-Patches/0152-Do-not-mark-chunks-as-active-for-neighbor-updates.patch b/Spigot-Server-Patches/0152-Do-not-mark-chunks-as-active-for-neighbor-updates.patch deleted file mode 100644 index 9a24edb03d..0000000000 --- a/Spigot-Server-Patches/0152-Do-not-mark-chunks-as-active-for-neighbor-updates.patch +++ /dev/null @@ -1,113 +0,0 @@ -From a7b3f62597464c1911ef9e2a8ad16d50dcce9e55 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 12 May 2016 01:55:17 -0400 -Subject: [PATCH] Do not mark chunks as active for neighbor updates - -Fixes chunk unload issues - -diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 904141a..d7b9581 100644 ---- a/src/main/java/net/minecraft/server/Chunk.java -+++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -991,25 +991,25 @@ public class Chunk { - - public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator) { - world.timings.syncChunkLoadPostTimer.startTiming(); // Spigot -- Chunk chunk = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ - 1); -- Chunk chunk1 = ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ); -- Chunk chunk2 = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ + 1); -- Chunk chunk3 = ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ); -+ Chunk chunk = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX, this.locZ - 1); // Paper -+ Chunk chunk1 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ); // Paper -+ Chunk chunk2 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX, this.locZ + 1); // Paper -+ Chunk chunk3 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ); // Paper - -- if (chunk1 != null && chunk2 != null && ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ + 1) != null) { -+ if (chunk1 != null && chunk2 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ + 1) != null) { // Paper - this.a(chunkgenerator); - } - -- if (chunk3 != null && chunk2 != null && ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ + 1) != null) { -+ if (chunk3 != null && chunk2 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ + 1) != null) { // Paper - chunk3.a(chunkgenerator); - } - -- if (chunk != null && chunk1 != null && ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ - 1) != null) { -+ if (chunk != null && chunk1 != null && MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX + 1, this.locZ - 1) != null) { // Paper - chunk.a(chunkgenerator); - } - - if (chunk != null && chunk3 != null) { -- Chunk chunk4 = ichunkprovider.getLoadedChunkAt(this.locX - 1, this.locZ - 1); -+ Chunk chunk4 = MCUtil.getLoadedChunkWithoutMarkingActive(ichunkprovider,this.locX - 1, this.locZ - 1); // Paper - - if (chunk4 != null) { - chunk4.a(chunkgenerator); -diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index f8905b4..6d1b98b 100644 ---- a/src/main/java/net/minecraft/server/ChunkProviderServer.java -+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -203,7 +203,7 @@ public class ChunkProviderServer implements IChunkProvider { - continue; - } - -- Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); -+ Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(this, chunk.locX + x, chunk.locZ + z); // Paper - if (neighbor != null) { - neighbor.setNeighborLoaded(-x, -z); - chunk.setNeighborLoaded(x, z); -@@ -324,7 +324,7 @@ public class ChunkProviderServer implements IChunkProvider { - continue; - } - -- Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); -+ Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(this, chunk.locX + x, chunk.locZ + z); // Paper - if (neighbor != null) { - neighbor.setNeighborUnloaded(-x, -z); - chunk.setNeighborUnloaded(x, z); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 6a3e939..b1a7435 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -241,7 +241,7 @@ public class CraftWorld implements World { - continue; - } - -- net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); -+ net.minecraft.server.Chunk neighbor = net.minecraft.server.MCUtil.getLoadedChunkWithoutMarkingActive(world, chunk.locX + x, chunk.locZ + z); // Paper - if (neighbor != null) { - neighbor.setNeighborUnloaded(-xx, -zz); - chunk.setNeighborUnloaded(xx, zz); -@@ -328,7 +328,7 @@ public class CraftWorld implements World { - continue; - } - -- net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getLoadedChunkAt(chunk.locX + x, chunk.locZ + z); -+ net.minecraft.server.Chunk neighbor = net.minecraft.server.MCUtil.getLoadedChunkWithoutMarkingActive(world, chunk.locX + x, chunk.locZ + z); // Paper - if (neighbor != null) { - neighbor.setNeighborLoaded(-x, -z); - chunk.setNeighborLoaded(x, z); -diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -index 7b61b14..7752b50 100644 ---- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java -@@ -5,7 +5,6 @@ import net.minecraft.server.Chunk; - import net.minecraft.server.ChunkCoordIntPair; - import net.minecraft.server.ChunkRegionLoader; - import net.minecraft.server.NBTTagCompound; -- - import org.bukkit.Server; - import org.bukkit.craftbukkit.util.AsynchronousExecutor; - -@@ -62,7 +61,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider +Date: Thu, 12 May 2016 02:03:56 -0400 +Subject: [PATCH] Unmark chunk as unloading when unload is cancelled + + +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index d7b9581..40d4c9c 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -47,7 +47,7 @@ public class Chunk { + private long w; + private int x; + private ConcurrentLinkedQueue y; +- public boolean d; ++ public boolean d;public void setShouldUnload(boolean unload) { this.d = unload; } // Paper // OBFHELPER + protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // Spigot + + // Paper start +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 6d1b98b..4a2cad6 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -309,6 +309,7 @@ public class ChunkProviderServer implements IChunkProvider { + Chunk chunk = (Chunk) this.chunks.get(olong); + + if (chunk != null && chunk.d) { ++ chunk.setShouldUnload(false); // Paper + // CraftBukkit start + ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); + this.world.getServer().getPluginManager().callEvent(event); +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0153-System-property-for-disabling-watchdoge.patch b/Spigot-Server-Patches/0153-System-property-for-disabling-watchdoge.patch new file mode 100644 index 0000000000..f9c11dca56 --- /dev/null +++ b/Spigot-Server-Patches/0153-System-property-for-disabling-watchdoge.patch @@ -0,0 +1,22 @@ +From 6d579c739f7aa7810454f8abf134194f1cc30baf Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Thu, 12 May 2016 23:02:58 -0500 +Subject: [PATCH] System property for disabling watchdoge + + +diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java +index 3ed983c..fb57e0d 100644 +--- a/src/main/java/org/spigotmc/WatchdogThread.java ++++ b/src/main/java/org/spigotmc/WatchdogThread.java +@@ -52,7 +52,7 @@ public class WatchdogThread extends Thread + while ( !stopping ) + { + // +- if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime ) ++ if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable + { + Logger log = Bukkit.getServer().getLogger(); + log.log( Level.SEVERE, "The server has stopped responding!" ); +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0153-Unmark-chunk-as-unloading-when-unload-is-cancelled.patch b/Spigot-Server-Patches/0153-Unmark-chunk-as-unloading-when-unload-is-cancelled.patch deleted file mode 100644 index 11c94beecb..0000000000 --- a/Spigot-Server-Patches/0153-Unmark-chunk-as-unloading-when-unload-is-cancelled.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 4cbcf0a94fdb7939154591d342fe7b69fe933176 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 12 May 2016 02:03:56 -0400 -Subject: [PATCH] Unmark chunk as unloading when unload is cancelled - - -diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index d7b9581..40d4c9c 100644 ---- a/src/main/java/net/minecraft/server/Chunk.java -+++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -47,7 +47,7 @@ public class Chunk { - private long w; - private int x; - private ConcurrentLinkedQueue y; -- public boolean d; -+ public boolean d;public void setShouldUnload(boolean unload) { this.d = unload; } // Paper // OBFHELPER - protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // Spigot - - // Paper start -diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 6d1b98b..4a2cad6 100644 ---- a/src/main/java/net/minecraft/server/ChunkProviderServer.java -+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -309,6 +309,7 @@ public class ChunkProviderServer implements IChunkProvider { - Chunk chunk = (Chunk) this.chunks.get(olong); - - if (chunk != null && chunk.d) { -+ chunk.setShouldUnload(false); // Paper - // CraftBukkit start - ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); - this.world.getServer().getPluginManager().callEvent(event); --- -2.8.2.windows.1 - diff --git a/Spigot-Server-Patches/0154-Optimize-EAR.patch b/Spigot-Server-Patches/0154-Optimize-EAR.patch new file mode 100644 index 0000000000..050f106f0c --- /dev/null +++ b/Spigot-Server-Patches/0154-Optimize-EAR.patch @@ -0,0 +1,69 @@ +From bd4875040e0063bc788a902ae367ab7bfaed9aec Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 13 May 2016 01:38:06 -0400 +Subject: [PATCH] Optimize EAR + + +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +index ce421eb..a7c4437 100644 +--- a/src/main/java/org/spigotmc/ActivationRange.java ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -2,6 +2,8 @@ package org.spigotmc; + + import java.util.List; + import java.util.Set; ++ ++import co.aikar.timings.MinecraftTimings; + import net.minecraft.server.AxisAlignedBB; + import net.minecraft.server.Chunk; + import net.minecraft.server.Entity; +@@ -13,7 +15,7 @@ import net.minecraft.server.EntityCreature; + import net.minecraft.server.EntityCreeper; + import net.minecraft.server.EntityEnderCrystal; + import net.minecraft.server.EntityEnderDragon; +-import net.minecraft.server.EntityFallingBlock; // Paper ++import net.minecraft.server.EntityFallingBlock; + import net.minecraft.server.EntityFireball; + import net.minecraft.server.EntityFireworks; + import net.minecraft.server.EntityHuman; +@@ -21,16 +23,15 @@ import net.minecraft.server.EntityLiving; + import net.minecraft.server.EntityMonster; + import net.minecraft.server.EntityProjectile; + import net.minecraft.server.EntitySheep; +-import net.minecraft.server.EntitySlice; + import net.minecraft.server.EntitySlime; + import net.minecraft.server.EntityTNTPrimed; + import net.minecraft.server.EntityVillager; + import net.minecraft.server.EntityWeather; + import net.minecraft.server.EntityWither; ++import net.minecraft.server.MCUtil; + import net.minecraft.server.MathHelper; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.World; +-import co.aikar.timings.MinecraftTimings; + + public class ActivationRange + { +@@ -108,6 +109,7 @@ public class ActivationRange + maxRange = Math.max( maxRange, miscActivationRange ); + maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange ); + ++ Chunk chunk; // Paper + for ( EntityHuman player : world.players ) + { + +@@ -126,9 +128,9 @@ public class ActivationRange + { + for ( int j1 = k; j1 <= l; ++j1 ) + { +- if ( world.getWorld().isChunkLoaded( i1, j1 ) ) ++ if ( (chunk = MCUtil.getLoadedChunkWithoutMarkingActive(world, i1, j1 )) != null ) // Paper + { +- activateChunkEntities( world.getChunkAt( i1, j1 ) ); ++ activateChunkEntities( chunk ); // Paper + } + } + } +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0154-System-property-for-disabling-watchdoge.patch b/Spigot-Server-Patches/0154-System-property-for-disabling-watchdoge.patch deleted file mode 100644 index 3f7db25352..0000000000 --- a/Spigot-Server-Patches/0154-System-property-for-disabling-watchdoge.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 00816855c6c0d23f13289a10f4e8329ea47ec3f0 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Thu, 12 May 2016 23:02:58 -0500 -Subject: [PATCH] System property for disabling watchdoge - - -diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index 3ed983c..fb57e0d 100644 ---- a/src/main/java/org/spigotmc/WatchdogThread.java -+++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -52,7 +52,7 @@ public class WatchdogThread extends Thread - while ( !stopping ) - { - // -- if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime ) -+ if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable - { - Logger log = Bukkit.getServer().getLogger(); - log.log( Level.SEVERE, "The server has stopped responding!" ); --- -2.8.2 - diff --git a/Spigot-Server-Patches/0155-Optimize-EAR.patch b/Spigot-Server-Patches/0155-Optimize-EAR.patch deleted file mode 100644 index 66ec55f801..0000000000 --- a/Spigot-Server-Patches/0155-Optimize-EAR.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 07e28d1f91da91eb58b0cc4afa22b92ed477f447 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 13 May 2016 01:38:06 -0400 -Subject: [PATCH] Optimize EAR - - -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index ce421eb..a7c4437 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -2,6 +2,8 @@ package org.spigotmc; - - import java.util.List; - import java.util.Set; -+ -+import co.aikar.timings.MinecraftTimings; - import net.minecraft.server.AxisAlignedBB; - import net.minecraft.server.Chunk; - import net.minecraft.server.Entity; -@@ -13,7 +15,7 @@ import net.minecraft.server.EntityCreature; - import net.minecraft.server.EntityCreeper; - import net.minecraft.server.EntityEnderCrystal; - import net.minecraft.server.EntityEnderDragon; --import net.minecraft.server.EntityFallingBlock; // Paper -+import net.minecraft.server.EntityFallingBlock; - import net.minecraft.server.EntityFireball; - import net.minecraft.server.EntityFireworks; - import net.minecraft.server.EntityHuman; -@@ -21,16 +23,15 @@ import net.minecraft.server.EntityLiving; - import net.minecraft.server.EntityMonster; - import net.minecraft.server.EntityProjectile; - import net.minecraft.server.EntitySheep; --import net.minecraft.server.EntitySlice; - import net.minecraft.server.EntitySlime; - import net.minecraft.server.EntityTNTPrimed; - import net.minecraft.server.EntityVillager; - import net.minecraft.server.EntityWeather; - import net.minecraft.server.EntityWither; -+import net.minecraft.server.MCUtil; - import net.minecraft.server.MathHelper; - import net.minecraft.server.MinecraftServer; - import net.minecraft.server.World; --import co.aikar.timings.MinecraftTimings; - - public class ActivationRange - { -@@ -108,6 +109,7 @@ public class ActivationRange - maxRange = Math.max( maxRange, miscActivationRange ); - maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange ); - -+ Chunk chunk; // Paper - for ( EntityHuman player : world.players ) - { - -@@ -126,9 +128,9 @@ public class ActivationRange - { - for ( int j1 = k; j1 <= l; ++j1 ) - { -- if ( world.getWorld().isChunkLoaded( i1, j1 ) ) -+ if ( (chunk = MCUtil.getLoadedChunkWithoutMarkingActive(world, i1, j1 )) != null ) // Paper - { -- activateChunkEntities( world.getChunkAt( i1, j1 ) ); -+ activateChunkEntities( chunk ); // Paper - } - } - } --- -2.8.2 - diff --git a/Spigot-Server-Patches/0155-Optimize-UserCache-Thread-Safe.patch b/Spigot-Server-Patches/0155-Optimize-UserCache-Thread-Safe.patch new file mode 100644 index 0000000000..e49988631b --- /dev/null +++ b/Spigot-Server-Patches/0155-Optimize-UserCache-Thread-Safe.patch @@ -0,0 +1,100 @@ +From 09a58e2b714a1361da3ed4ac26506e12abc56af9 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 16 May 2016 20:47:41 -0400 +Subject: [PATCH] Optimize UserCache / Thread Safe + +Because Techable keeps complaining about how this isn't thread safe, +easier to do this than replace the entire thing. + +Additionally, move Saving of the User cache to be done async, incase +the user never changed the default setting for Spigot's save on stop only. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index ec9f037..7e7ec23 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -497,7 +497,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + // Spigot start + if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { + LOGGER.info("Saving usercache.json"); +- this.X.c(); ++ this.X.c(false); // Paper + } + // Spigot end + } +diff --git a/src/main/java/net/minecraft/server/UserCache.java b/src/main/java/net/minecraft/server/UserCache.java +index 5cc2731..2420112 100644 +--- a/src/main/java/net/minecraft/server/UserCache.java ++++ b/src/main/java/net/minecraft/server/UserCache.java +@@ -108,7 +108,7 @@ public class UserCache { + this.a(gameprofile, (Date) null); + } + +- private void a(GameProfile gameprofile, Date date) { ++ private synchronized void a(GameProfile gameprofile, Date date) { // Paper - synchronize + UUID uuid = gameprofile.getId(); + + if (date == null) { +@@ -122,8 +122,9 @@ public class UserCache { + String s = gameprofile.getName().toLowerCase(Locale.ROOT); + UserCache.UserCacheEntry usercache_usercacheentry = new UserCache.UserCacheEntry(gameprofile, date, null); + +- if (this.e.containsKey(uuid)) { ++ //if (this.e.containsKey(uuid)) { // Paper + UserCache.UserCacheEntry usercache_usercacheentry1 = (UserCache.UserCacheEntry) this.e.get(uuid); ++ if (usercache_usercacheentry1 != null) { // Paper + + this.d.remove(usercache_usercacheentry1.a().getName().toLowerCase(Locale.ROOT)); + this.f.remove(gameprofile); +@@ -136,7 +137,7 @@ public class UserCache { + } + + @Nullable +- public GameProfile getProfile(String s) { ++ public synchronized GameProfile getProfile(String s) { // Paper - synchronize + String s1 = s.toLowerCase(Locale.ROOT); + UserCache.UserCacheEntry usercache_usercacheentry = (UserCache.UserCacheEntry) this.d.get(s1); + +@@ -165,7 +166,7 @@ public class UserCache { + return usercache_usercacheentry == null ? null : usercache_usercacheentry.a(); + } + +- public String[] a() { ++ public synchronized String[] a() { // Paper - synchronize + ArrayList arraylist = Lists.newArrayList(this.d.keySet()); + + return (String[]) arraylist.toArray(new String[arraylist.size()]); +@@ -227,8 +228,15 @@ public class UserCache { + + } + ++ // Paper start + public void c() { ++ c(true); ++ } ++ public void c(boolean asyncSave) { ++ // Paper end + String s = this.b.toJson(this.a(org.spigotmc.SpigotConfig.userCacheCap)); ++ Runnable save = () -> { ++ + BufferedWriter bufferedwriter = null; + + try { +@@ -242,6 +250,14 @@ public class UserCache { + } finally { + IOUtils.closeQuietly(bufferedwriter); + } ++ // Paper start ++ }; ++ if (asyncSave) { ++ MCUtil.scheduleAsyncTask(save); ++ } else { ++ save.run(); ++ } ++ // Paper end + + } + +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0156-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch b/Spigot-Server-Patches/0156-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch new file mode 100644 index 0000000000..fcd519ea67 --- /dev/null +++ b/Spigot-Server-Patches/0156-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch @@ -0,0 +1,33 @@ +From 6b7b2b272be834ecd1ddb2fd5ae25331c995a240 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 16 May 2016 22:54:36 -0400 +Subject: [PATCH] MC-99914 - ensure EntityItem loads before EntityPotion + + +diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java +index 9618eaf..0b11fd7 100644 +--- a/src/main/java/net/minecraft/server/EntityItem.java ++++ b/src/main/java/net/minecraft/server/EntityItem.java +@@ -41,6 +41,7 @@ public class EntityItem extends Entity { + this.setItemStack(itemstack); + } + ++ static int uglyHack = 1; // Paper - MC-99914 - ensure EntityItem loads before EntityPotion + protected boolean playStepSound() { + return false; + } +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 7e7ec23..8df9f38 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -136,6 +136,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + this.dataConverterManager = dataconvertermanager; + // CraftBukkit start + this.options = options; ++ EntityItem.uglyHack++; // Paper - MC-99914 - ensure EntityItem loads before EntityPotion + // Try to see if we're actually running in a terminal, disable jline if not + if (System.console() == null && System.getProperty("jline.terminal") == null) { + System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0156-Optimize-UserCache-Thread-Safe.patch b/Spigot-Server-Patches/0156-Optimize-UserCache-Thread-Safe.patch deleted file mode 100644 index a37e61f0f2..0000000000 --- a/Spigot-Server-Patches/0156-Optimize-UserCache-Thread-Safe.patch +++ /dev/null @@ -1,100 +0,0 @@ -From a1cf500c7a15721dfa81f4607e6f67f4cc7246a7 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 16 May 2016 20:47:41 -0400 -Subject: [PATCH] Optimize UserCache / Thread Safe - -Because Techable keeps complaining about how this isn't thread safe, -easier to do this than replace the entire thing. - -Additionally, move Saving of the User cache to be done async, incase -the user never changed the default setting for Spigot's save on stop only. - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ec9f037..7e7ec23 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -497,7 +497,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs - // Spigot start - if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { - LOGGER.info("Saving usercache.json"); -- this.X.c(); -+ this.X.c(false); // Paper - } - // Spigot end - } -diff --git a/src/main/java/net/minecraft/server/UserCache.java b/src/main/java/net/minecraft/server/UserCache.java -index 5cc2731..2420112 100644 ---- a/src/main/java/net/minecraft/server/UserCache.java -+++ b/src/main/java/net/minecraft/server/UserCache.java -@@ -108,7 +108,7 @@ public class UserCache { - this.a(gameprofile, (Date) null); - } - -- private void a(GameProfile gameprofile, Date date) { -+ private synchronized void a(GameProfile gameprofile, Date date) { // Paper - synchronize - UUID uuid = gameprofile.getId(); - - if (date == null) { -@@ -122,8 +122,9 @@ public class UserCache { - String s = gameprofile.getName().toLowerCase(Locale.ROOT); - UserCache.UserCacheEntry usercache_usercacheentry = new UserCache.UserCacheEntry(gameprofile, date, null); - -- if (this.e.containsKey(uuid)) { -+ //if (this.e.containsKey(uuid)) { // Paper - UserCache.UserCacheEntry usercache_usercacheentry1 = (UserCache.UserCacheEntry) this.e.get(uuid); -+ if (usercache_usercacheentry1 != null) { // Paper - - this.d.remove(usercache_usercacheentry1.a().getName().toLowerCase(Locale.ROOT)); - this.f.remove(gameprofile); -@@ -136,7 +137,7 @@ public class UserCache { - } - - @Nullable -- public GameProfile getProfile(String s) { -+ public synchronized GameProfile getProfile(String s) { // Paper - synchronize - String s1 = s.toLowerCase(Locale.ROOT); - UserCache.UserCacheEntry usercache_usercacheentry = (UserCache.UserCacheEntry) this.d.get(s1); - -@@ -165,7 +166,7 @@ public class UserCache { - return usercache_usercacheentry == null ? null : usercache_usercacheentry.a(); - } - -- public String[] a() { -+ public synchronized String[] a() { // Paper - synchronize - ArrayList arraylist = Lists.newArrayList(this.d.keySet()); - - return (String[]) arraylist.toArray(new String[arraylist.size()]); -@@ -227,8 +228,15 @@ public class UserCache { - - } - -+ // Paper start - public void c() { -+ c(true); -+ } -+ public void c(boolean asyncSave) { -+ // Paper end - String s = this.b.toJson(this.a(org.spigotmc.SpigotConfig.userCacheCap)); -+ Runnable save = () -> { -+ - BufferedWriter bufferedwriter = null; - - try { -@@ -242,6 +250,14 @@ public class UserCache { - } finally { - IOUtils.closeQuietly(bufferedwriter); - } -+ // Paper start -+ }; -+ if (asyncSave) { -+ MCUtil.scheduleAsyncTask(save); -+ } else { -+ save.run(); -+ } -+ // Paper end - - } - --- -2.8.2 - diff --git a/Spigot-Server-Patches/0157-Avoid-blocking-on-Network-Manager-creation.patch b/Spigot-Server-Patches/0157-Avoid-blocking-on-Network-Manager-creation.patch new file mode 100644 index 0000000000..b37a9f285f --- /dev/null +++ b/Spigot-Server-Patches/0157-Avoid-blocking-on-Network-Manager-creation.patch @@ -0,0 +1,49 @@ +From 3e7863928d22425c7f33221ee729bebf39f50731 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 16 May 2016 23:19:16 -0400 +Subject: [PATCH] Avoid blocking on Network Manager creation + +Per Paper issue 294 + +diff --git a/src/main/java/net/minecraft/server/ServerConnection.java b/src/main/java/net/minecraft/server/ServerConnection.java +index 4ab28e6..08634c3 100644 +--- a/src/main/java/net/minecraft/server/ServerConnection.java ++++ b/src/main/java/net/minecraft/server/ServerConnection.java +@@ -60,6 +60,17 @@ public class ServerConnection { + public volatile boolean d; + private final List g = Collections.synchronizedList(Lists.newArrayList()); + private final List h = Collections.synchronizedList(Lists.newArrayList()); ++ // Paper start - prevent blocking on adding a new network manager while the server is ticking ++ private final List pending = Collections.synchronizedList(Lists.newArrayList()); ++ private void addPending() { ++ synchronized (pending) { ++ synchronized (this.h) { // Paper // OBFHELPER - List of network managers ++ this.h.addAll(pending); ++ pending.clear(); ++ } ++ } ++ } ++ // Paper end + + public ServerConnection(MinecraftServer minecraftserver) { + this.f = minecraftserver; +@@ -94,7 +105,7 @@ public class ServerConnection { + channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("legacy_query", new LegacyPingHandler(ServerConnection.this)).addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND)).addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND)); + NetworkManager networkmanager = new NetworkManager(EnumProtocolDirection.SERVERBOUND); + +- ServerConnection.this.h.add(networkmanager); ++ pending.add(networkmanager); // Paper + channel.pipeline().addLast("packet_handler", networkmanager); + networkmanager.setPacketListener(new HandshakeListener(ServerConnection.this.f, networkmanager)); + } +@@ -123,6 +134,7 @@ public class ServerConnection { + + synchronized (this.h) { + // Spigot Start ++ addPending(); // Paper + // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order + if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 ) + { +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0157-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch b/Spigot-Server-Patches/0157-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch deleted file mode 100644 index ae7d5607fe..0000000000 --- a/Spigot-Server-Patches/0157-MC-99914-ensure-EntityItem-loads-before-EntityPotion.patch +++ /dev/null @@ -1,33 +0,0 @@ -From e7916ce21713f358b99e80754dac20434ec5120d Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 16 May 2016 22:54:36 -0400 -Subject: [PATCH] MC-99914 - ensure EntityItem loads before EntityPotion - - -diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java -index 9618eaf..0b11fd7 100644 ---- a/src/main/java/net/minecraft/server/EntityItem.java -+++ b/src/main/java/net/minecraft/server/EntityItem.java -@@ -41,6 +41,7 @@ public class EntityItem extends Entity { - this.setItemStack(itemstack); - } - -+ static int uglyHack = 1; // Paper - MC-99914 - ensure EntityItem loads before EntityPotion - protected boolean playStepSound() { - return false; - } -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7e7ec23..8df9f38 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -136,6 +136,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs - this.dataConverterManager = dataconvertermanager; - // CraftBukkit start - this.options = options; -+ EntityItem.uglyHack++; // Paper - MC-99914 - ensure EntityItem loads before EntityPotion - // Try to see if we're actually running in a terminal, disable jline if not - if (System.console() == null && System.getProperty("jline.terminal") == null) { - System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); --- -2.8.2 - diff --git a/Spigot-Server-Patches/0158-Avoid-blocking-on-Network-Manager-creation.patch b/Spigot-Server-Patches/0158-Avoid-blocking-on-Network-Manager-creation.patch deleted file mode 100644 index a685b234c6..0000000000 --- a/Spigot-Server-Patches/0158-Avoid-blocking-on-Network-Manager-creation.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 35daee4c95827a178f1f80c336d4e100f64fa91f Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 16 May 2016 23:19:16 -0400 -Subject: [PATCH] Avoid blocking on Network Manager creation - -Per Paper issue 294 - -diff --git a/src/main/java/net/minecraft/server/ServerConnection.java b/src/main/java/net/minecraft/server/ServerConnection.java -index 4ab28e6..08634c3 100644 ---- a/src/main/java/net/minecraft/server/ServerConnection.java -+++ b/src/main/java/net/minecraft/server/ServerConnection.java -@@ -60,6 +60,17 @@ public class ServerConnection { - public volatile boolean d; - private final List g = Collections.synchronizedList(Lists.newArrayList()); - private final List h = Collections.synchronizedList(Lists.newArrayList()); -+ // Paper start - prevent blocking on adding a new network manager while the server is ticking -+ private final List pending = Collections.synchronizedList(Lists.newArrayList()); -+ private void addPending() { -+ synchronized (pending) { -+ synchronized (this.h) { // Paper // OBFHELPER - List of network managers -+ this.h.addAll(pending); -+ pending.clear(); -+ } -+ } -+ } -+ // Paper end - - public ServerConnection(MinecraftServer minecraftserver) { - this.f = minecraftserver; -@@ -94,7 +105,7 @@ public class ServerConnection { - channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("legacy_query", new LegacyPingHandler(ServerConnection.this)).addLast("splitter", new PacketSplitter()).addLast("decoder", new PacketDecoder(EnumProtocolDirection.SERVERBOUND)).addLast("prepender", new PacketPrepender()).addLast("encoder", new PacketEncoder(EnumProtocolDirection.CLIENTBOUND)); - NetworkManager networkmanager = new NetworkManager(EnumProtocolDirection.SERVERBOUND); - -- ServerConnection.this.h.add(networkmanager); -+ pending.add(networkmanager); // Paper - channel.pipeline().addLast("packet_handler", networkmanager); - networkmanager.setPacketListener(new HandshakeListener(ServerConnection.this.f, networkmanager)); - } -@@ -123,6 +134,7 @@ public class ServerConnection { - - synchronized (this.h) { - // Spigot Start -+ addPending(); // Paper - // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order - if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 ) - { --- -2.8.2 - diff --git a/Spigot-Server-Patches/0158-Optional-old-TNT-cannon-behaviors.patch b/Spigot-Server-Patches/0158-Optional-old-TNT-cannon-behaviors.patch new file mode 100644 index 0000000000..a4c2fa026c --- /dev/null +++ b/Spigot-Server-Patches/0158-Optional-old-TNT-cannon-behaviors.patch @@ -0,0 +1,395 @@ +From 201d211ea97e013c64cf7f186a294b5465043bf3 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sun, 22 May 2016 20:20:55 -0500 +Subject: [PATCH] Optional old TNT cannon behaviors + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index efed4c6..1e60a3b 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -352,4 +352,12 @@ public class PaperWorldConfig { + ); + } + } ++ ++ public boolean oldCannonBehaviors; ++ private void oldCannonBehaviors() { ++ oldCannonBehaviors = getBoolean("enable-old-tnt-cannon-behaviors", false); ++ if (oldCannonBehaviors) { ++ log("Old Cannon Behaviors: This feature may not be working entirely properly at the moment"); ++ } ++ } + } +diff --git a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java +index f422843..8abe359 100644 +--- a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java ++++ b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java +@@ -76,6 +76,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal { + } else { + this.b(world, blockposition, iblockdata, 0); + world.setAir(blockposition); ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); ++ return; ++ } ++ // Paper end + EnumDirection[] aenumdirection = EnumDirection.values(); + int i = aenumdirection.length; + +@@ -173,6 +184,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal { + + public void postBreak(World world, BlockPosition blockposition, IBlockData iblockdata) { + if (this.d) { ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); ++ return; ++ } ++ // Paper end + EnumDirection[] aenumdirection = EnumDirection.values(); + int i = aenumdirection.length; + +diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java +index 712b0c0..e2f4f44 100644 +--- a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java ++++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java +@@ -53,6 +53,12 @@ public class BlockRedstoneTorch extends BlockTorch { + + public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { + if (this.isOn) { ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ this.shiftPositions(world, blockposition); ++ return; ++ } ++ // Paper end + EnumDirection[] aenumdirection = EnumDirection.values(); + int i = aenumdirection.length; + +@@ -67,6 +73,12 @@ public class BlockRedstoneTorch extends BlockTorch { + + public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) { + if (this.isOn) { ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ this.shiftPositions(world, blockposition); ++ return; ++ } ++ // Paper end + EnumDirection[] aenumdirection = EnumDirection.values(); + int i = aenumdirection.length; + +@@ -79,6 +91,17 @@ public class BlockRedstoneTorch extends BlockTorch { + + } + ++ // Paper start - Old TNT cannon behaviors ++ private void shiftPositions(World world, BlockPosition blockposition) { ++ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); ++ } ++ // Paper end ++ + public int b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) { + return this.isOn && iblockdata.get(BlockRedstoneTorch.FACING) != enumdirection ? 15 : 0; + } +diff --git a/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/src/main/java/net/minecraft/server/BlockRedstoneWire.java +index 93671ed..661c4f9 100644 +--- a/src/main/java/net/minecraft/server/BlockRedstoneWire.java ++++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java +@@ -20,7 +20,7 @@ public class BlockRedstoneWire extends Block { + public static final BlockStateInteger POWER = BlockStateInteger.of("power", 0, 15); + protected static final AxisAlignedBB[] f = new AxisAlignedBB[] { new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D)}; + private boolean g = true; +- private final Set B = Sets.newHashSet(); ++ private final Set B = Sets.newHashSet(); private final Set blocksToUpdate = B; // Paper - OBFHELPER + + public BlockRedstoneWire() { + super(Material.ORIENTABLE); +@@ -186,6 +186,19 @@ public class BlockRedstoneWire extends Block { + } + + this.B.add(blockposition); ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.WEST)); ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.EAST)); ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.DOWN)); ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.UP)); ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.NORTH)); ++ this.blocksToUpdate.add(blockposition.shift(EnumDirection.SOUTH)); ++ return iblockdata; ++ } ++ // Paper end ++ ++ + EnumDirection[] aenumdirection = EnumDirection.values(); + int i1 = aenumdirection.length; + +@@ -202,6 +215,17 @@ public class BlockRedstoneWire extends Block { + private void b(World world, BlockPosition blockposition) { + if (world.getType(blockposition).getBlock() == this) { + world.applyPhysics(blockposition, this); ++ // Paper start - Old TNT cannon behaviors ++ if (world.paperConfig.oldCannonBehaviors) { ++ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); ++ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); ++ return; ++ } ++ // Paper end + EnumDirection[] aenumdirection = EnumDirection.values(); + int i = aenumdirection.length; + +diff --git a/src/main/java/net/minecraft/server/BlockTNT.java b/src/main/java/net/minecraft/server/BlockTNT.java +index c5022e2..805766d 100644 +--- a/src/main/java/net/minecraft/server/BlockTNT.java ++++ b/src/main/java/net/minecraft/server/BlockTNT.java +@@ -31,7 +31,11 @@ public class BlockTNT extends Block { + + public void wasExploded(World world, BlockPosition blockposition, Explosion explosion) { + if (!world.isClientSide) { +- EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource()); ++ // Paper start - Old TNT cannon behaviors ++ double y = blockposition.getY(); ++ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; ++ EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource()); ++ // Paper end + + entitytntprimed.setFuseTicks((short) (world.random.nextInt(entitytntprimed.getFuseTicks() / 4) + entitytntprimed.getFuseTicks() / 8)); + world.addEntity(entitytntprimed); +@@ -45,7 +49,11 @@ public class BlockTNT extends Block { + public void a(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving) { + if (!world.isClientSide) { + if (((Boolean) iblockdata.get(BlockTNT.EXPLODE)).booleanValue()) { +- EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), entityliving); ++ // Paper start - Old TNT cannon behaviors ++ double y = blockposition.getY(); ++ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; ++ EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), entityliving); ++ // Paper end + + world.addEntity(entitytntprimed); + world.a((EntityHuman) null, entitytntprimed.locX, entitytntprimed.locY, entitytntprimed.locZ, SoundEffects.gk, SoundCategory.BLOCKS, 1.0F, 1.0F); +diff --git a/src/main/java/net/minecraft/server/DispenserRegistry.java b/src/main/java/net/minecraft/server/DispenserRegistry.java +index 4e31ab1..bb58134 100644 +--- a/src/main/java/net/minecraft/server/DispenserRegistry.java ++++ b/src/main/java/net/minecraft/server/DispenserRegistry.java +@@ -497,7 +497,11 @@ public class DispenserRegistry { + org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); + +- BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D)); ++ // Paper start - Old TNT cannon behaviors ++ double y = blockposition.getY(); ++ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; ++ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, y, (double) blockposition.getZ() + 0.5D)); ++ // Paper end + if (!BlockDispenser.eventFired) { + world.getServer().getPluginManager().callEvent(event); + } +diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java +index 02a1c25..d54a30b 100644 +--- a/src/main/java/net/minecraft/server/Entity.java ++++ b/src/main/java/net/minecraft/server/Entity.java +@@ -960,6 +960,12 @@ public abstract class Entity implements ICommandListener { + } + + public boolean aj() { ++ // Paper start - OBFHELPER ++ return this.doWaterMovement(); ++ } ++ ++ public boolean doWaterMovement() { ++ // Paper end + if (this.bz() instanceof EntityBoat) { + this.inWater = false; + } else if (this.world.a(this.getBoundingBox().grow(0.0D, -0.4000000059604645D, 0.0D).shrink(0.001D), Material.WATER, this)) { +@@ -1150,6 +1156,12 @@ public abstract class Entity implements ICommandListener { + } + + public double f(double d0, double d1, double d2) { ++ // Paper start - OBFHELPER ++ return this.getDistance(d0, d1, d2); ++ } ++ ++ public double getDistance(double d0, double d1, double d2) { ++ // Paper end + double d3 = this.locX - d0; + double d4 = this.locY - d1; + double d5 = this.locZ - d2; +@@ -1204,6 +1216,12 @@ public abstract class Entity implements ICommandListener { + } + + public void g(double d0, double d1, double d2) { ++ // Paper start - OBFHELPER ++ this.addVelocity(d0, d1, d2); ++ } ++ ++ public void addVelocity(double d0, double d1, double d2) { ++ // Paper end + this.motX += d0; + this.motY += d1; + this.motZ += d2; +@@ -2311,6 +2329,12 @@ public abstract class Entity implements ICommandListener { + } + + public boolean be() { ++ // Paper start - OBFHELPER ++ return this.pushedByWater(); ++ } ++ ++ public boolean pushedByWater() { ++ // Paper end + return true; + } + +diff --git a/src/main/java/net/minecraft/server/EntityFallingBlock.java b/src/main/java/net/minecraft/server/EntityFallingBlock.java +index 4c14d75..a5d8f02 100644 +--- a/src/main/java/net/minecraft/server/EntityFallingBlock.java ++++ b/src/main/java/net/minecraft/server/EntityFallingBlock.java +@@ -274,4 +274,19 @@ public class EntityFallingBlock extends Entity { + public boolean bs() { + return true; + } ++ ++ // Paper start - Old TNT cannon behaviors ++ @Override ++ public double getDistance(double d0, double d1, double d2) { ++ if (!world.paperConfig.oldCannonBehaviors) return super.getDistance(d0, d1, d2); ++ ++ double newX = this.locX - d0; ++ double newY = this.locY + this.getHeadHeight() - d1; ++ double newZ = this.locZ - d2; ++ ++ return (double) MathHelper.sqrt(newX * newX + newY * newY + newZ * newZ); ++ } ++ ++ ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/server/EntityTNTPrimed.java b/src/main/java/net/minecraft/server/EntityTNTPrimed.java +index 1113b1c..436bbb8 100644 +--- a/src/main/java/net/minecraft/server/EntityTNTPrimed.java ++++ b/src/main/java/net/minecraft/server/EntityTNTPrimed.java +@@ -30,6 +30,7 @@ public class EntityTNTPrimed extends Entity { + this.lastY = d1; + this.lastZ = d2; + this.source = entityliving; ++ if (world.paperConfig.oldCannonBehaviors) this.motX = this.motZ = 0.0F; // Paper - Old TNT cannon behaviors + } + + protected void i() { +@@ -119,7 +120,7 @@ public class EntityTNTPrimed extends Entity { + } + + public float getHeadHeight() { +- return 0.0F; ++ return world.paperConfig.oldCannonBehaviors ? this.length / 2 : 0.0F; // Paper - Old TNT cannon behaviors + } + + public void setFuseTicks(int i) { +@@ -141,4 +142,58 @@ public class EntityTNTPrimed extends Entity { + public int getFuseTicks() { + return this.c; + } ++ ++ // Paper start - Old TNT cannon behaviors ++ @Override ++ public double getDistance(double d0, double d1, double d2) { ++ if (!world.paperConfig.oldCannonBehaviors) return super.getDistance(d0, d1, d2); ++ ++ double newX = this.locX - d0; ++ double newY = this.locY + this.getHeadHeight() - d1; ++ double newZ = this.locZ - d2; ++ ++ return (double) MathHelper.sqrt(newX * newX + newY * newY + newZ * newZ); ++ } ++ ++ @Override ++ public boolean pushedByWater() { ++ return !world.paperConfig.oldCannonBehaviors && super.pushedByWater(); ++ } ++ ++ /** ++ * Author: Jedediah Smith ++ */ ++ @Override ++ public boolean doWaterMovement() { ++ if (!world.paperConfig.oldCannonBehaviors) return super.doWaterMovement(); ++ ++ // Preserve velocity while calling the super method ++ double oldMotX = this.motX; ++ double oldMotY = this.motY; ++ double oldMotZ = this.motZ; ++ ++ super.doWaterMovement(); ++ ++ this.motX = oldMotX; ++ this.motY = oldMotY; ++ this.motZ = oldMotZ; ++ ++ if (this.inWater) { ++ // Send position and velocity updates to nearby players on every tick while the TNT is in water. ++ // This does pretty well at keeping their clients in sync with the server. ++ EntityTrackerEntry ete = ((WorldServer) this.getWorld()).getTracker().trackedEntities.get(this.getId()); ++ if (ete != null) { ++ PacketPlayOutEntityVelocity velocityPacket = new PacketPlayOutEntityVelocity(this); ++ PacketPlayOutEntityTeleport positionPacket = new PacketPlayOutEntityTeleport(this); ++ ++ ete.trackedPlayers.stream().filter(viewer -> (viewer.locX - this.locX) * (viewer.locY - this.locY) * (viewer.locZ - this.locZ) < 16 * 16).forEach(viewer -> { ++ viewer.playerConnection.sendPacket(velocityPacket); ++ viewer.playerConnection.sendPacket(positionPacket); ++ }); ++ } ++ } ++ ++ return this.inWater; ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java +index 28261c5..275e044 100644 +--- a/src/main/java/net/minecraft/server/Explosion.java ++++ b/src/main/java/net/minecraft/server/Explosion.java +@@ -148,9 +148,15 @@ public class Explosion { + d14 = entity instanceof EntityHuman && world.paperConfig.disableExplosionKnockback ? 0 : EnchantmentProtection.a((EntityLiving) entity, d13); // Paper - Disable explosion knockback + } + +- entity.motX += d8 * d14; +- entity.motY += d9 * d14; +- entity.motZ += d10 * d14; ++ // Paper start - Fix cannons ++ /* ++ entity.motX += d8 * d14; ++ entity.motY += d9 * d14; ++ entity.motZ += d10 * d14; ++ */ ++ // This impulse method sets the dirty flag, so clients will get an immediate velocity update ++ entity.addVelocity(d8 * d14, d9 * d14, d10 * d14); ++ // Paper end + if (entity instanceof EntityHuman) { + EntityHuman entityhuman = (EntityHuman) entity; + +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0159-Faster-redstone-torch-rapid-clock-removal.patch b/Spigot-Server-Patches/0159-Faster-redstone-torch-rapid-clock-removal.patch new file mode 100644 index 0000000000..bea4b7e1be --- /dev/null +++ b/Spigot-Server-Patches/0159-Faster-redstone-torch-rapid-clock-removal.patch @@ -0,0 +1,43 @@ +From 335b62827ed9942cf0a7482071634360bb5c4fa1 Mon Sep 17 00:00:00 2001 +From: Martin Panzer +Date: Mon, 23 May 2016 12:12:37 +0200 +Subject: [PATCH] Faster redstone torch rapid clock removal + +Only resize the the redstone torch list once, since resizing arrays / lists is costly + +diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java +index e2f4f44..cf24c45 100644 +--- a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java ++++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java +@@ -118,9 +118,17 @@ public class BlockRedstoneTorch extends BlockTorch { + boolean flag = this.g(world, blockposition, iblockdata); + List list = (List) BlockRedstoneTorch.g.get(world); + +- while (list != null && !list.isEmpty() && world.getTime() - ((BlockRedstoneTorch.RedstoneUpdateInfo) list.get(0)).b > 60L) { +- list.remove(0); ++ // Paper start ++ if (list != null) { ++ int index = 0; ++ while (index < list.size() && world.getTime() - ((BlockRedstoneTorch.RedstoneUpdateInfo) list.get(index)).getTime() > 60L) { ++ index++; ++ } ++ if (index > 0) { ++ list.subList(0, index).clear(); ++ } + } ++ // Paper end + + // CraftBukkit start + org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); +@@ -204,7 +212,7 @@ public class BlockRedstoneTorch extends BlockTorch { + static class RedstoneUpdateInfo { + + BlockPosition a; +- long b; ++ long b; final long getTime() { return this.b; } // Paper - OBFHELPER + + public RedstoneUpdateInfo(BlockPosition blockposition, long i) { + this.a = blockposition; +-- +2.7.4 (Apple Git-66) + diff --git a/Spigot-Server-Patches/0159-Optional-old-TNT-cannon-behaviors.patch b/Spigot-Server-Patches/0159-Optional-old-TNT-cannon-behaviors.patch deleted file mode 100644 index 8bad61dbaf..0000000000 --- a/Spigot-Server-Patches/0159-Optional-old-TNT-cannon-behaviors.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 9b002ecab7ef680b6a1fb31a26978850620bd457 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sun, 22 May 2016 20:20:55 -0500 -Subject: [PATCH] Optional old TNT cannon behaviors - - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 9c79f2e..3b0542a 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -366,4 +366,12 @@ public class PaperWorldConfig { - ); - } - } -+ -+ public boolean oldCannonBehaviors; -+ private void oldCannonBehaviors() { -+ oldCannonBehaviors = getBoolean("enable-old-tnt-cannon-behaviors", false); -+ if (oldCannonBehaviors) { -+ log("Old Cannon Behaviors: This feature may not be working entirely properly at the moment"); -+ } -+ } - } -diff --git a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java -index f422843..8abe359 100644 ---- a/src/main/java/net/minecraft/server/BlockDiodeAbstract.java -+++ b/src/main/java/net/minecraft/server/BlockDiodeAbstract.java -@@ -76,6 +76,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal { - } else { - this.b(world, blockposition, iblockdata, 0); - world.setAir(blockposition); -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); -+ return; -+ } -+ // Paper end - EnumDirection[] aenumdirection = EnumDirection.values(); - int i = aenumdirection.length; - -@@ -173,6 +184,17 @@ public abstract class BlockDiodeAbstract extends BlockFacingHorizontal { - - public void postBreak(World world, BlockPosition blockposition, IBlockData iblockdata) { - if (this.d) { -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); -+ return; -+ } -+ // Paper end - EnumDirection[] aenumdirection = EnumDirection.values(); - int i = aenumdirection.length; - -diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -index 712b0c0..e2f4f44 100644 ---- a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -+++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -@@ -53,6 +53,12 @@ public class BlockRedstoneTorch extends BlockTorch { - - public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { - if (this.isOn) { -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ this.shiftPositions(world, blockposition); -+ return; -+ } -+ // Paper end - EnumDirection[] aenumdirection = EnumDirection.values(); - int i = aenumdirection.length; - -@@ -67,6 +73,12 @@ public class BlockRedstoneTorch extends BlockTorch { - - public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) { - if (this.isOn) { -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ this.shiftPositions(world, blockposition); -+ return; -+ } -+ // Paper end - EnumDirection[] aenumdirection = EnumDirection.values(); - int i = aenumdirection.length; - -@@ -79,6 +91,17 @@ public class BlockRedstoneTorch extends BlockTorch { - - } - -+ // Paper start - Old TNT cannon behaviors -+ private void shiftPositions(World world, BlockPosition blockposition) { -+ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); -+ } -+ // Paper end -+ - public int b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) { - return this.isOn && iblockdata.get(BlockRedstoneTorch.FACING) != enumdirection ? 15 : 0; - } -diff --git a/src/main/java/net/minecraft/server/BlockRedstoneWire.java b/src/main/java/net/minecraft/server/BlockRedstoneWire.java -index 93671ed..661c4f9 100644 ---- a/src/main/java/net/minecraft/server/BlockRedstoneWire.java -+++ b/src/main/java/net/minecraft/server/BlockRedstoneWire.java -@@ -20,7 +20,7 @@ public class BlockRedstoneWire extends Block { - public static final BlockStateInteger POWER = BlockStateInteger.of("power", 0, 15); - protected static final AxisAlignedBB[] f = new AxisAlignedBB[] { new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D)}; - private boolean g = true; -- private final Set B = Sets.newHashSet(); -+ private final Set B = Sets.newHashSet(); private final Set blocksToUpdate = B; // Paper - OBFHELPER - - public BlockRedstoneWire() { - super(Material.ORIENTABLE); -@@ -186,6 +186,19 @@ public class BlockRedstoneWire extends Block { - } - - this.B.add(blockposition); -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.WEST)); -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.EAST)); -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.DOWN)); -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.UP)); -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.NORTH)); -+ this.blocksToUpdate.add(blockposition.shift(EnumDirection.SOUTH)); -+ return iblockdata; -+ } -+ // Paper end -+ -+ - EnumDirection[] aenumdirection = EnumDirection.values(); - int i1 = aenumdirection.length; - -@@ -202,6 +215,17 @@ public class BlockRedstoneWire extends Block { - private void b(World world, BlockPosition blockposition) { - if (world.getType(blockposition).getBlock() == this) { - world.applyPhysics(blockposition, this); -+ // Paper start - Old TNT cannon behaviors -+ if (world.paperConfig.oldCannonBehaviors) { -+ world.applyPhysics(blockposition.shift(EnumDirection.WEST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.EAST), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.NORTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.SOUTH), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.DOWN), this); -+ world.applyPhysics(blockposition.shift(EnumDirection.UP), this); -+ return; -+ } -+ // Paper end - EnumDirection[] aenumdirection = EnumDirection.values(); - int i = aenumdirection.length; - -diff --git a/src/main/java/net/minecraft/server/BlockTNT.java b/src/main/java/net/minecraft/server/BlockTNT.java -index c5022e2..805766d 100644 ---- a/src/main/java/net/minecraft/server/BlockTNT.java -+++ b/src/main/java/net/minecraft/server/BlockTNT.java -@@ -31,7 +31,11 @@ public class BlockTNT extends Block { - - public void wasExploded(World world, BlockPosition blockposition, Explosion explosion) { - if (!world.isClientSide) { -- EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource()); -+ // Paper start - Old TNT cannon behaviors -+ double y = blockposition.getY(); -+ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; -+ EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), explosion.getSource()); -+ // Paper end - - entitytntprimed.setFuseTicks((short) (world.random.nextInt(entitytntprimed.getFuseTicks() / 4) + entitytntprimed.getFuseTicks() / 8)); - world.addEntity(entitytntprimed); -@@ -45,7 +49,11 @@ public class BlockTNT extends Block { - public void a(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving) { - if (!world.isClientSide) { - if (((Boolean) iblockdata.get(BlockTNT.EXPLODE)).booleanValue()) { -- EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), (double) blockposition.getY(), (double) ((float) blockposition.getZ() + 0.5F), entityliving); -+ // Paper start - Old TNT cannon behaviors -+ double y = blockposition.getY(); -+ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; -+ EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(world, (double) ((float) blockposition.getX() + 0.5F), y, (double) ((float) blockposition.getZ() + 0.5F), entityliving); -+ // Paper end - - world.addEntity(entitytntprimed); - world.a((EntityHuman) null, entitytntprimed.locX, entitytntprimed.locY, entitytntprimed.locZ, SoundEffects.gk, SoundCategory.BLOCKS, 1.0F, 1.0F); -diff --git a/src/main/java/net/minecraft/server/DispenserRegistry.java b/src/main/java/net/minecraft/server/DispenserRegistry.java -index 4e31ab1..bb58134 100644 ---- a/src/main/java/net/minecraft/server/DispenserRegistry.java -+++ b/src/main/java/net/minecraft/server/DispenserRegistry.java -@@ -497,7 +497,11 @@ public class DispenserRegistry { - org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockPosition().getX(), isourceblock.getBlockPosition().getY(), isourceblock.getBlockPosition().getZ()); - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - -- BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D)); -+ // Paper start - Old TNT cannon behaviors -+ double y = blockposition.getY(); -+ if (!world.paperConfig.oldCannonBehaviors) y += 0.5; -+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, y, (double) blockposition.getZ() + 0.5D)); -+ // Paper end - if (!BlockDispenser.eventFired) { - world.getServer().getPluginManager().callEvent(event); - } -diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index 02a1c25..d54a30b 100644 ---- a/src/main/java/net/minecraft/server/Entity.java -+++ b/src/main/java/net/minecraft/server/Entity.java -@@ -960,6 +960,12 @@ public abstract class Entity implements ICommandListener { - } - - public boolean aj() { -+ // Paper start - OBFHELPER -+ return this.doWaterMovement(); -+ } -+ -+ public boolean doWaterMovement() { -+ // Paper end - if (this.bz() instanceof EntityBoat) { - this.inWater = false; - } else if (this.world.a(this.getBoundingBox().grow(0.0D, -0.4000000059604645D, 0.0D).shrink(0.001D), Material.WATER, this)) { -@@ -1150,6 +1156,12 @@ public abstract class Entity implements ICommandListener { - } - - public double f(double d0, double d1, double d2) { -+ // Paper start - OBFHELPER -+ return this.getDistance(d0, d1, d2); -+ } -+ -+ public double getDistance(double d0, double d1, double d2) { -+ // Paper end - double d3 = this.locX - d0; - double d4 = this.locY - d1; - double d5 = this.locZ - d2; -@@ -1204,6 +1216,12 @@ public abstract class Entity implements ICommandListener { - } - - public void g(double d0, double d1, double d2) { -+ // Paper start - OBFHELPER -+ this.addVelocity(d0, d1, d2); -+ } -+ -+ public void addVelocity(double d0, double d1, double d2) { -+ // Paper end - this.motX += d0; - this.motY += d1; - this.motZ += d2; -@@ -2311,6 +2329,12 @@ public abstract class Entity implements ICommandListener { - } - - public boolean be() { -+ // Paper start - OBFHELPER -+ return this.pushedByWater(); -+ } -+ -+ public boolean pushedByWater() { -+ // Paper end - return true; - } - -diff --git a/src/main/java/net/minecraft/server/EntityFallingBlock.java b/src/main/java/net/minecraft/server/EntityFallingBlock.java -index 4c14d75..a5d8f02 100644 ---- a/src/main/java/net/minecraft/server/EntityFallingBlock.java -+++ b/src/main/java/net/minecraft/server/EntityFallingBlock.java -@@ -274,4 +274,19 @@ public class EntityFallingBlock extends Entity { - public boolean bs() { - return true; - } -+ -+ // Paper start - Old TNT cannon behaviors -+ @Override -+ public double getDistance(double d0, double d1, double d2) { -+ if (!world.paperConfig.oldCannonBehaviors) return super.getDistance(d0, d1, d2); -+ -+ double newX = this.locX - d0; -+ double newY = this.locY + this.getHeadHeight() - d1; -+ double newZ = this.locZ - d2; -+ -+ return (double) MathHelper.sqrt(newX * newX + newY * newY + newZ * newZ); -+ } -+ -+ -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/server/EntityTNTPrimed.java b/src/main/java/net/minecraft/server/EntityTNTPrimed.java -index 1113b1c..436bbb8 100644 ---- a/src/main/java/net/minecraft/server/EntityTNTPrimed.java -+++ b/src/main/java/net/minecraft/server/EntityTNTPrimed.java -@@ -30,6 +30,7 @@ public class EntityTNTPrimed extends Entity { - this.lastY = d1; - this.lastZ = d2; - this.source = entityliving; -+ if (world.paperConfig.oldCannonBehaviors) this.motX = this.motZ = 0.0F; // Paper - Old TNT cannon behaviors - } - - protected void i() { -@@ -119,7 +120,7 @@ public class EntityTNTPrimed extends Entity { - } - - public float getHeadHeight() { -- return 0.0F; -+ return world.paperConfig.oldCannonBehaviors ? this.length / 2 : 0.0F; // Paper - Old TNT cannon behaviors - } - - public void setFuseTicks(int i) { -@@ -141,4 +142,58 @@ public class EntityTNTPrimed extends Entity { - public int getFuseTicks() { - return this.c; - } -+ -+ // Paper start - Old TNT cannon behaviors -+ @Override -+ public double getDistance(double d0, double d1, double d2) { -+ if (!world.paperConfig.oldCannonBehaviors) return super.getDistance(d0, d1, d2); -+ -+ double newX = this.locX - d0; -+ double newY = this.locY + this.getHeadHeight() - d1; -+ double newZ = this.locZ - d2; -+ -+ return (double) MathHelper.sqrt(newX * newX + newY * newY + newZ * newZ); -+ } -+ -+ @Override -+ public boolean pushedByWater() { -+ return !world.paperConfig.oldCannonBehaviors && super.pushedByWater(); -+ } -+ -+ /** -+ * Author: Jedediah Smith -+ */ -+ @Override -+ public boolean doWaterMovement() { -+ if (!world.paperConfig.oldCannonBehaviors) return super.doWaterMovement(); -+ -+ // Preserve velocity while calling the super method -+ double oldMotX = this.motX; -+ double oldMotY = this.motY; -+ double oldMotZ = this.motZ; -+ -+ super.doWaterMovement(); -+ -+ this.motX = oldMotX; -+ this.motY = oldMotY; -+ this.motZ = oldMotZ; -+ -+ if (this.inWater) { -+ // Send position and velocity updates to nearby players on every tick while the TNT is in water. -+ // This does pretty well at keeping their clients in sync with the server. -+ EntityTrackerEntry ete = ((WorldServer) this.getWorld()).getTracker().trackedEntities.get(this.getId()); -+ if (ete != null) { -+ PacketPlayOutEntityVelocity velocityPacket = new PacketPlayOutEntityVelocity(this); -+ PacketPlayOutEntityTeleport positionPacket = new PacketPlayOutEntityTeleport(this); -+ -+ ete.trackedPlayers.stream().filter(viewer -> (viewer.locX - this.locX) * (viewer.locY - this.locY) * (viewer.locZ - this.locZ) < 16 * 16).forEach(viewer -> { -+ viewer.playerConnection.sendPacket(velocityPacket); -+ viewer.playerConnection.sendPacket(positionPacket); -+ }); -+ } -+ } -+ -+ return this.inWater; -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java -index 28261c5..275e044 100644 ---- a/src/main/java/net/minecraft/server/Explosion.java -+++ b/src/main/java/net/minecraft/server/Explosion.java -@@ -148,9 +148,15 @@ public class Explosion { - d14 = entity instanceof EntityHuman && world.paperConfig.disableExplosionKnockback ? 0 : EnchantmentProtection.a((EntityLiving) entity, d13); // Paper - Disable explosion knockback - } - -- entity.motX += d8 * d14; -- entity.motY += d9 * d14; -- entity.motZ += d10 * d14; -+ // Paper start - Fix cannons -+ /* -+ entity.motX += d8 * d14; -+ entity.motY += d9 * d14; -+ entity.motZ += d10 * d14; -+ */ -+ // This impulse method sets the dirty flag, so clients will get an immediate velocity update -+ entity.addVelocity(d8 * d14, d9 * d14, d10 * d14); -+ // Paper end - if (entity instanceof EntityHuman) { - EntityHuman entityhuman = (EntityHuman) entity; - --- -2.8.2 - diff --git a/Spigot-Server-Patches/0160-Faster-redstone-torch-rapid-clock-removal.patch b/Spigot-Server-Patches/0160-Faster-redstone-torch-rapid-clock-removal.patch deleted file mode 100644 index cd9c4842f6..0000000000 --- a/Spigot-Server-Patches/0160-Faster-redstone-torch-rapid-clock-removal.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 10a2bb42c44b07bf3854f948f887a3e9ee795720 Mon Sep 17 00:00:00 2001 -From: Martin Panzer -Date: Mon, 23 May 2016 12:12:37 +0200 -Subject: [PATCH] Faster redstone torch rapid clock removal - -Only resize the the redstone torch list once, since resizing arrays / lists is costly - -diff --git a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -index e2f4f44..cf24c45 100644 ---- a/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -+++ b/src/main/java/net/minecraft/server/BlockRedstoneTorch.java -@@ -118,9 +118,17 @@ public class BlockRedstoneTorch extends BlockTorch { - boolean flag = this.g(world, blockposition, iblockdata); - List list = (List) BlockRedstoneTorch.g.get(world); - -- while (list != null && !list.isEmpty() && world.getTime() - ((BlockRedstoneTorch.RedstoneUpdateInfo) list.get(0)).b > 60L) { -- list.remove(0); -+ // Paper start -+ if (list != null) { -+ int index = 0; -+ while (index < list.size() && world.getTime() - ((BlockRedstoneTorch.RedstoneUpdateInfo) list.get(index)).getTime() > 60L) { -+ index++; -+ } -+ if (index > 0) { -+ list.subList(0, index).clear(); -+ } - } -+ // Paper end - - // CraftBukkit start - org.bukkit.plugin.PluginManager manager = world.getServer().getPluginManager(); -@@ -204,7 +212,7 @@ public class BlockRedstoneTorch extends BlockTorch { - static class RedstoneUpdateInfo { - - BlockPosition a; -- long b; -+ long b; final long getTime() { return this.b; } // Paper - OBFHELPER - - public RedstoneUpdateInfo(BlockPosition blockposition, long i) { - this.a = blockposition; --- -2.8.2 - -- cgit v1.2.3