From cb3d14c5a7369f94c2037d179666583e0e3945dd Mon Sep 17 00:00:00 2001
From: md_5 <git@md-5.net>
Date: Tue, 28 May 2019 06:30:00 +1000
Subject: [PATCH] Update to Minecraft 1.14.2

---
 nms-patches/AdvancementDataPlayer.patch       |   2 +-
 nms-patches/BehaviorFarm.patch                |   4 +-
 nms-patches/BehaviorMakeLove.patch            |   2 +-
 nms-patches/Block.patch                       |   6 +-
 nms-patches/BlockCauldron.patch               |   4 +-
 nms-patches/BlockCommand.patch                |   4 +-
 nms-patches/Chunk.patch                       |  18 +-
 nms-patches/ChunkProviderServer.patch         |  28 +--
 nms-patches/CommandGamerule.patch             |   4 +-
 nms-patches/CommandSummon.patch               |   2 +-
 nms-patches/CommandTeleport.patch             |   4 +-
 nms-patches/ContainerFurnace.patch            |   4 +-
 nms-patches/ContainerGrindstone.patch         |   2 +-
 nms-patches/ContainerLectern.patch            |  22 +--
 nms-patches/ContainerPlayer.patch             |   4 +-
 nms-patches/ContainerWorkbench.patch          |  13 +-
 nms-patches/Entity.patch                      |   2 +-
 nms-patches/EntityDamageSourceIndirect.patch  |   2 +-
 nms-patches/EntityDolphin.patch               |   4 +-
 nms-patches/EntityEnderCrystal.patch          |  29 ++-
 nms-patches/EntityIllagerIllusioner.patch     |   4 +-
 nms-patches/EntityLiving.patch                |  74 +++----
 nms-patches/EntityLlamaTrader.patch           |   2 +-
 nms-patches/EntityPanda.patch                 |   4 +-
 nms-patches/EntityParrot.patch                |   2 +-
 nms-patches/EntityPillager.patch              |   4 +-
 nms-patches/EntityPlayer.patch                |   2 +-
 nms-patches/EntityRavager.patch               |   4 +-
 nms-patches/EntityThrownExpBottle.patch       |   6 +-
 nms-patches/EntityVex.patch                   |   4 +-
 nms-patches/EntityVillager.patch              |   6 +-
 nms-patches/EntityZombieVillager.patch        |   9 +-
 nms-patches/HandshakeListener.patch           |  78 ++++----
 nms-patches/IMerchant.patch                   |   2 +-
 nms-patches/InventoryCrafting.patch           |   2 +-
 nms-patches/ItemArmor.patch                   |   2 +-
 nms-patches/LegacyPingHandler.patch           |  40 ++--
 nms-patches/PathfinderGoalDefendVillage.patch |   2 +-
 nms-patches/PlayerChunk.patch                 |  44 ++---
 nms-patches/PlayerChunkMap.patch              |  47 +++--
 nms-patches/PlayerConnection.patch            | 180 +++++++++---------
 nms-patches/PlayerInteractManager.patch       |   4 +-
 nms-patches/PlayerList.patch                  |  20 +-
 nms-patches/TickListServer.patch              |  15 +-
 nms-patches/TicketType.patch                  |   8 +-
 nms-patches/TileEntityBeacon.patch            |   8 +-
 nms-patches/TileEntityBrewingStand.patch      |   6 +-
 nms-patches/TileEntityEndGateway.patch        |   2 +-
 nms-patches/TileEntityLectern.patch           |   4 +-
 nms-patches/TileEntitySign.patch              |   6 +-
 nms-patches/World.patch                       |   2 +-
 pom.xml                                       |   4 +-
 .../bukkit/craftbukkit/CraftLootTable.java    |   2 +-
 .../entity/memory/CraftMemoryMapper.java      |   7 +-
 .../inventory/CraftMerchantCustom.java        |   7 +
 .../craftbukkit/util/CraftMagicNumbers.java   |   2 +-
 .../entity/memory/CraftMemoryKeyTest.java     |   4 +-
 57 files changed, 385 insertions(+), 394 deletions(-)

diff --git a/nms-patches/AdvancementDataPlayer.patch b/nms-patches/AdvancementDataPlayer.patch
index 96af9ca550..63e65e4e7d 100644
--- a/nms-patches/AdvancementDataPlayer.patch
+++ b/nms-patches/AdvancementDataPlayer.patch
@@ -20,4 +20,4 @@
 +                this.player.world.getServer().getPluginManager().callEvent(new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.bukkit)); // CraftBukkit
                  advancement.d().a(this.player);
                  if (advancement.c() != null && advancement.c().i() && this.player.world.getGameRules().getBoolean("announceAdvancements")) {
-                     this.d.getPlayerList().sendMessage(new ChatMessage("chat.type.advancement." + advancement.c().e().a(), new Object[] { this.player.getScoreboardDisplayName(), advancement.j()}));
+                     this.d.getPlayerList().sendMessage(new ChatMessage("chat.type.advancement." + advancement.c().e().a(), new Object[]{this.player.getScoreboardDisplayName(), advancement.j()}));
diff --git a/nms-patches/BehaviorFarm.patch b/nms-patches/BehaviorFarm.patch
index 5649fc1f31..1956df7a25 100644
--- a/nms-patches/BehaviorFarm.patch
+++ b/nms-patches/BehaviorFarm.patch
@@ -4,8 +4,8 @@
          } else if (entityvillager.getVillagerData().getProfession() != VillagerProfession.FARMER) {
              return false;
          } else {
--            Set<BlockPosition> set = (Set) ((List) entityvillager.getBehaviorController().getMemory(MemoryModuleType.SECONDARY_JOB_SITE).get()).stream().map(GlobalPos::b).collect(Collectors.toSet());
-+            Set<BlockPosition> set = (Set) (entityvillager.getBehaviorController().getMemory(MemoryModuleType.SECONDARY_JOB_SITE).get()).stream().map(GlobalPos::b).collect(Collectors.toSet()); // CraftBukkit - decompile error
+-            Set<BlockPosition> set = (Set) ((List) entityvillager.getBehaviorController().getMemory(MemoryModuleType.SECONDARY_JOB_SITE).get()).stream().map(GlobalPos::getBlockPosition).collect(Collectors.toSet());
++            Set<BlockPosition> set = (Set) (entityvillager.getBehaviorController().getMemory(MemoryModuleType.SECONDARY_JOB_SITE).get()).stream().map(GlobalPos::getBlockPosition).collect(Collectors.toSet()); // CraftBukkit - decompile error
              BlockPosition blockposition = new BlockPosition(entityvillager);
              Stream stream = ImmutableList.of(blockposition.down(), blockposition.south(), blockposition.north(), blockposition.east(), blockposition.west()).stream();
  
diff --git a/nms-patches/BehaviorMakeLove.patch b/nms-patches/BehaviorMakeLove.patch
index 976bdd5e54..5bf8901151 100644
--- a/nms-patches/BehaviorMakeLove.patch
+++ b/nms-patches/BehaviorMakeLove.patch
@@ -23,7 +23,7 @@
          }
 @@ -110,6 +115,6 @@
      private void a(WorldServer worldserver, EntityVillager entityvillager, BlockPosition blockposition) {
-         GlobalPos globalpos = GlobalPos.a(worldserver.getWorldProvider().getDimensionManager(), blockposition);
+         GlobalPos globalpos = GlobalPos.create(worldserver.getWorldProvider().getDimensionManager(), blockposition);
  
 -        entityvillager.getBehaviorController().setMemory(MemoryModuleType.HOME, (Object) globalpos);
 +        entityvillager.getBehaviorController().setMemory(MemoryModuleType.HOME, globalpos); // CraftBukkit - decompile error
diff --git a/nms-patches/Block.patch b/nms-patches/Block.patch
index af4b5d57e1..663bbad68c 100644
--- a/nms-patches/Block.patch
+++ b/nms-patches/Block.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/Block.java
 +++ b/net/minecraft/server/Block.java
-@@ -435,7 +435,8 @@
+@@ -434,7 +434,8 @@
      }
  
      public static List<ItemStack> getDrops(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, @Nullable TileEntity tileentity, Entity entity, ItemStack itemstack) {
@@ -10,7 +10,7 @@
  
          return iblockdata.a(loottableinfo_builder);
      }
-@@ -489,7 +490,13 @@
+@@ -488,7 +489,13 @@
              EntityItem entityitem = new EntityItem(world, (double) blockposition.getX() + d0, (double) blockposition.getY() + d1, (double) blockposition.getZ() + d2, itemstack);
  
              entityitem.defaultPickupDelay();
@@ -25,7 +25,7 @@
          }
      }
  
-@@ -686,6 +693,12 @@
+@@ -685,6 +692,12 @@
          return block == Blocks.DIRT || block == Blocks.COARSE_DIRT || block == Blocks.PODZOL;
      }
  
diff --git a/nms-patches/BlockCauldron.patch b/nms-patches/BlockCauldron.patch
index 1a47f4c641..d0edc6343e 100644
--- a/nms-patches/BlockCauldron.patch
+++ b/nms-patches/BlockCauldron.patch
@@ -71,7 +71,7 @@
 +                            return true;
 +                        }
                          if (!entityhuman.abilities.canInstantlyBuild) {
-                             itemstack1 = PotionUtil.a(new ItemStack(Items.POTION), Potions.b);
+                             itemstack1 = PotionUtil.a(new ItemStack(Items.POTION), Potions.WATER);
                              entityhuman.a(StatisticList.USE_CAULDRON);
 @@ -96,12 +117,17 @@
                          }
@@ -83,7 +83,7 @@
                      }
  
                      return true;
-                 } else if (item == Items.POTION && PotionUtil.d(itemstack) == Potions.b) {
+                 } else if (item == Items.POTION && PotionUtil.d(itemstack) == Potions.WATER) {
                      if (i < 3 && !world.isClientSide) {
 +                        // CraftBukkit start
 +                        if (!this.changeLevel(world, blockposition, iblockdata, i + 1, entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
diff --git a/nms-patches/BlockCommand.patch b/nms-patches/BlockCommand.patch
index 68f51c0dc6..3827a869b2 100644
--- a/nms-patches/BlockCommand.patch
+++ b/nms-patches/BlockCommand.patch
@@ -12,7 +12,7 @@
 @@ -32,6 +34,15 @@
                  TileEntityCommand tileentitycommand = (TileEntityCommand) tileentity;
                  boolean flag1 = world.isBlockIndirectlyPowered(blockposition);
-                 boolean flag2 = tileentitycommand.d();
+                 boolean flag2 = tileentitycommand.f();
 +                // CraftBukkit start
 +                org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
 +                int old = flag2 ? 15 : 0;
@@ -24,4 +24,4 @@
 +                // CraftBukkit end
  
                  tileentitycommand.a(flag1);
-                 if (!flag2 && !tileentitycommand.f() && tileentitycommand.u() != TileEntityCommand.Type.SEQUENCE) {
+                 if (!flag2 && !tileentitycommand.g() && tileentitycommand.u() != TileEntityCommand.Type.SEQUENCE) {
diff --git a/nms-patches/Chunk.patch b/nms-patches/Chunk.patch
index a617cae68f..0830483ba5 100644
--- a/nms-patches/Chunk.patch
+++ b/nms-patches/Chunk.patch
@@ -70,7 +70,7 @@
          if (tileentity == null) {
              NBTTagCompound nbttagcompound = (NBTTagCompound) this.e.remove(blockposition);
 @@ -429,6 +454,13 @@
-                 tileentity1.m();
+                 tileentity1.W_();
              }
  
 +            // CraftBukkit start
@@ -83,7 +83,7 @@
          }
      }
  
-@@ -457,6 +489,50 @@
+@@ -478,6 +510,50 @@
  
      }
  
@@ -134,7 +134,7 @@
      public void markDirty() {
          this.s = true;
      }
-@@ -531,7 +607,7 @@
+@@ -552,7 +628,7 @@
              Iterator iterator = this.entitySlices[k].a(oclass).iterator();
  
              while (iterator.hasNext()) {
@@ -143,7 +143,7 @@
  
                  if (t0.getBoundingBox().c(axisalignedbb) && (predicate == null || predicate.test(t0))) {
                      list.add(t0);
-@@ -605,7 +681,7 @@
+@@ -626,7 +702,7 @@
  
      @Override
      public boolean isNeedsSaving() {
@@ -152,7 +152,7 @@
      }
  
      public void d(boolean flag) {
-@@ -746,7 +822,7 @@
+@@ -767,7 +843,7 @@
  
      public void B() {
          if (this.o instanceof ProtoChunkTickList) {
@@ -161,7 +161,7 @@
                  return this.getType(blockposition).getBlock();
              });
              this.o = TickListEmpty.a();
-@@ -756,7 +832,7 @@
+@@ -777,7 +853,7 @@
          }
  
          if (this.p instanceof ProtoChunkTickList) {
@@ -170,18 +170,18 @@
                  return this.getFluid(blockposition).getType();
              });
              this.p = TickListEmpty.a();
-@@ -768,12 +844,12 @@
+@@ -789,12 +865,12 @@
      }
  
      public void a(WorldServer worldserver) {
 -        if (this.o == TickListEmpty.a()) {
 +        if (this.o == TickListEmpty.<Block>a()) { // CraftBukkit - decompile error
-             this.o = new TickListChunk<>(IRegistry.BLOCK::getKey, worldserver.getBlockTickList().a(true, this.loc));
+             this.o = new TickListChunk<>(IRegistry.BLOCK::getKey, worldserver.getBlockTickList().a(this.loc, true, false));
              this.setNeedsSaving(true);
          }
  
 -        if (this.p == TickListEmpty.a()) {
 +        if (this.p == TickListEmpty.<FluidType>a()) { // CraftBukkit - decompile error
-             this.p = new TickListChunk<>(IRegistry.FLUID::getKey, worldserver.getFluidTickList().a(true, this.loc));
+             this.p = new TickListChunk<>(IRegistry.FLUID::getKey, worldserver.getFluidTickList().a(this.loc, true, false));
              this.setNeedsSaving(true);
          }
diff --git a/nms-patches/ChunkProviderServer.patch b/nms-patches/ChunkProviderServer.patch
index 0123c9e34b..8aa8f802df 100644
--- a/nms-patches/ChunkProviderServer.patch
+++ b/nms-patches/ChunkProviderServer.patch
@@ -2,8 +2,8 @@
 +++ b/net/minecraft/server/ChunkProviderServer.java
 @@ -81,7 +81,7 @@
              for (int l = 0; l < 4; ++l) {
-                 if (k == this.n[l] && chunkstatus == this.o[l]) {
-                     ichunkaccess = this.p[l];
+                 if (k == this.cachePos[l] && chunkstatus == this.cacheStatus[l]) {
+                     ichunkaccess = this.cacheChunk[l];
 -                    if (ichunkaccess != null || !flag) {
 +                    if (ichunkaccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime
                          return ichunkaccess;
@@ -17,16 +17,16 @@
 +        // CraftBukkit start - don't add new ticket for currently unloading chunk
 +        boolean currentlyUnloading = false;
 +        if (playerchunk != null) {
-+            PlayerChunk.State oldChunkState = PlayerChunk.c(playerchunk.oldTicketLevel); // PAIL getChunkState
-+            PlayerChunk.State currentChunkState = PlayerChunk.c(playerchunk.getTicketLevel()); // PAIL getChunkState
-+            currentlyUnloading = (oldChunkState.a(PlayerChunk.State.BORDER) && !currentChunkState.a(PlayerChunk.State.BORDER)); // PAIL isAtLeast
++            PlayerChunk.State oldChunkState = PlayerChunk.getChunkState(playerchunk.oldTicketLevel);
++            PlayerChunk.State currentChunkState = PlayerChunk.getChunkState(playerchunk.getTicketLevel());
++            currentlyUnloading = (oldChunkState.isAtLeast(PlayerChunk.State.BORDER) && !currentChunkState.isAtLeast(PlayerChunk.State.BORDER));
 +        }
 +        if (flag && !currentlyUnloading) {
 +            // CraftBukkit end
              this.chunkMapDistance.a(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
              if (this.a(playerchunk, l)) {
                  GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler();
-@@ -144,14 +152,14 @@
+@@ -144,7 +152,7 @@
      }
  
      private boolean a(@Nullable PlayerChunk playerchunk, int i) {
@@ -35,15 +35,7 @@
      }
  
      public boolean isLoaded(int i, int j) {
-         PlayerChunk playerchunk = this.getChunk((new ChunkCoordIntPair(i, j)).pair());
-         int k = 33 + ChunkStatus.a(ChunkStatus.FULL);
- 
--        return playerchunk != null && playerchunk.getTicketLevel() <= k ? ((Either) playerchunk.getStatusFuture(ChunkStatus.FULL).getNow(PlayerChunk.UNLOADED_CHUNK_ACCESS)).left().isPresent() : false;
-+        return playerchunk != null && playerchunk.oldTicketLevel <= k ? ((Either) playerchunk.getStatusFuture(ChunkStatus.FULL).getNow(PlayerChunk.UNLOADED_CHUNK_ACCESS)).left().isPresent() : false; // CraftBukkit using oldTicketLevel for isLoaded checks
-     }
- 
-     @Override
-@@ -241,6 +249,18 @@
+@@ -245,6 +253,18 @@
          this.playerChunkMap.close();
      }
  
@@ -55,14 +47,14 @@
 +        this.world.getMethodProfiler().exitEnter("unload");
 +        this.playerChunkMap.unloadChunks(() -> true);
 +        this.world.getMethodProfiler().exit();
-+        this.l(); // PAIL clearCache
++        this.clearCache();
 +    }
 +    // CraftBukkit end
 +
      public void tick(BooleanSupplier booleansupplier) {
          this.world.getMethodProfiler().enter("purge");
          this.chunkMapDistance.purgeTickets();
-@@ -260,13 +280,13 @@
+@@ -264,13 +284,13 @@
          this.lastTickTime = i;
          WorldData worlddata = this.world.getWorldData();
          boolean flag = worlddata.getType() == WorldType.DEBUG_ALL_BLOCK_STATES;
@@ -78,7 +70,7 @@
  
              this.world.getMethodProfiler().enter("naturalSpawnCount");
              int l = this.chunkMapDistance.b();
-@@ -299,8 +319,30 @@
+@@ -303,8 +323,30 @@
                              for (int j1 = 0; j1 < i1; ++j1) {
                                  EnumCreatureType enumcreaturetype = aenumcreaturetype1[j1];
  
diff --git a/nms-patches/CommandGamerule.patch b/nms-patches/CommandGamerule.patch
index 19639cb53f..aa36467973 100644
--- a/nms-patches/CommandGamerule.patch
+++ b/nms-patches/CommandGamerule.patch
@@ -8,7 +8,7 @@
 +        GameRules.GameRuleValue gamerules_gamerulevalue = commandlistenerwrapper.getWorld().getGameRules().get(s); // CraftBukkit
  
          gamerules_gamerulevalue.getType().a(commandcontext, "value", gamerules_gamerulevalue);
-         commandlistenerwrapper.sendMessage(new ChatMessage("commands.gamerule.set", new Object[] { s, gamerules_gamerulevalue.getValue()}), true);
+         commandlistenerwrapper.sendMessage(new ChatMessage("commands.gamerule.set", new Object[]{s, gamerules_gamerulevalue.getValue()}), true);
 @@ -35,7 +35,7 @@
      }
  
@@ -16,5 +16,5 @@
 -        GameRules.GameRuleValue gamerules_gamerulevalue = commandlistenerwrapper.getServer().getGameRules().get(s);
 +        GameRules.GameRuleValue gamerules_gamerulevalue = commandlistenerwrapper.getWorld().getGameRules().get(s); // CraftBukkit
  
-         commandlistenerwrapper.sendMessage(new ChatMessage("commands.gamerule.query", new Object[] { s, gamerules_gamerulevalue.getValue()}), false);
+         commandlistenerwrapper.sendMessage(new ChatMessage("commands.gamerule.query", new Object[]{s, gamerules_gamerulevalue.getValue()}), false);
          return gamerules_gamerulevalue.getIntValue();
diff --git a/nms-patches/CommandSummon.patch b/nms-patches/CommandSummon.patch
index 4c2499ba91..8ebf13f2f8 100644
--- a/nms-patches/CommandSummon.patch
+++ b/nms-patches/CommandSummon.patch
@@ -6,6 +6,6 @@
  
 -            commandlistenerwrapper.getWorld().strikeLightning(entitylightning);
 +            commandlistenerwrapper.getWorld().strikeLightning(entitylightning, org.bukkit.event.weather.LightningStrikeEvent.Cause.COMMAND); // CraftBukkit
-             commandlistenerwrapper.sendMessage(new ChatMessage("commands.summon.success", new Object[] { entitylightning.getScoreboardDisplayName()}), true);
+             commandlistenerwrapper.sendMessage(new ChatMessage("commands.summon.success", new Object[]{entitylightning.getScoreboardDisplayName()}), true);
              return 1;
          } else {
diff --git a/nms-patches/CommandTeleport.patch b/nms-patches/CommandTeleport.patch
index 3bc8874c9b..43b66a562e 100644
--- a/nms-patches/CommandTeleport.patch
+++ b/nms-patches/CommandTeleport.patch
@@ -12,7 +12,7 @@
  
  public class CommandTeleport {
  
-@@ -118,9 +123,9 @@
+@@ -121,9 +126,9 @@
              }
  
              if (worldserver == entity.world) {
@@ -24,7 +24,7 @@
              }
  
              entity.setHeadRotation(f);
-@@ -129,6 +134,21 @@
+@@ -132,6 +137,21 @@
              float f3 = MathHelper.g(f1);
  
              f3 = MathHelper.a(f3, -90.0F, 90.0F);
diff --git a/nms-patches/ContainerFurnace.patch b/nms-patches/ContainerFurnace.patch
index 5df55973a6..6e3fb76306 100644
--- a/nms-patches/ContainerFurnace.patch
+++ b/nms-patches/ContainerFurnace.patch
@@ -63,8 +63,8 @@
      }
  
      protected boolean a(ItemStack itemstack) {
--        return this.c.getCraftingManager().craft(this.f, new InventorySubcontainer(new ItemStack[] { itemstack}), this.c).isPresent();
-+        return this.c.getCraftingManager().craft((Recipes<RecipeCooking>) this.f, new InventorySubcontainer(new ItemStack[] { itemstack}), this.c).isPresent(); // Eclipse fail
+-        return this.c.getCraftingManager().craft(this.f, new InventorySubcontainer(new ItemStack[]{itemstack}), this.c).isPresent();
++        return this.c.getCraftingManager().craft((Recipes<RecipeCooking>) this.f, new InventorySubcontainer(new ItemStack[]{itemstack}), this.c).isPresent(); // Eclipse fail
      }
  
      protected boolean b(ItemStack itemstack) {
diff --git a/nms-patches/ContainerGrindstone.patch b/nms-patches/ContainerGrindstone.patch
index 92e8b7e32f..5bb9d0d462 100644
--- a/nms-patches/ContainerGrindstone.patch
+++ b/nms-patches/ContainerGrindstone.patch
@@ -53,7 +53,7 @@
      }
  
      @Override
-@@ -233,6 +262,7 @@
+@@ -235,6 +264,7 @@
  
      @Override
      public boolean canUse(EntityHuman entityhuman) {
diff --git a/nms-patches/ContainerLectern.patch b/nms-patches/ContainerLectern.patch
index 19aab42ccc..c0468cf79a 100644
--- a/nms-patches/ContainerLectern.patch
+++ b/nms-patches/ContainerLectern.patch
@@ -53,19 +53,19 @@
  
      @Override
 @@ -48,6 +74,13 @@
-                     return false;
-                 }
+                         return false;
+                     }
  
-+                // CraftBukkit start - Event for taking the book
-+                PlayerTakeLecternBookEvent event = new PlayerTakeLecternBookEvent(player, ((CraftInventoryLectern) getBukkitView().getTopInventory()).getHolder());
-+                Bukkit.getServer().getPluginManager().callEvent(event);
-+                if (event.isCancelled()) {
-+                    return false;
-+                }
-+                // CraftBukkit end
-                 ItemStack itemstack = this.inventory.splitWithoutUpdate(0);
++                    // CraftBukkit start - Event for taking the book
++                    PlayerTakeLecternBookEvent event = new PlayerTakeLecternBookEvent(player, ((CraftInventoryLectern) getBukkitView().getTopInventory()).getHolder());
++                    Bukkit.getServer().getPluginManager().callEvent(event);
++                    if (event.isCancelled()) {
++                        return false;
++                    }
++                    // CraftBukkit end
+                     ItemStack itemstack = this.inventory.splitWithoutUpdate(0);
  
-                 this.inventory.update();
+                     this.inventory.update();
 @@ -70,6 +103,7 @@
  
      @Override
diff --git a/nms-patches/ContainerPlayer.patch b/nms-patches/ContainerPlayer.patch
index 2562fa658e..253de36883 100644
--- a/nms-patches/ContainerPlayer.patch
+++ b/nms-patches/ContainerPlayer.patch
@@ -10,8 +10,8 @@
 +
  public class ContainerPlayer extends ContainerRecipeBook<InventoryCrafting> {
  
-     private static final String[] d = new String[] { "item/empty_armor_slot_boots", "item/empty_armor_slot_leggings", "item/empty_armor_slot_chestplate", "item/empty_armor_slot_helmet"};
-     private static final EnumItemSlot[] e = new EnumItemSlot[] { EnumItemSlot.HEAD, EnumItemSlot.CHEST, EnumItemSlot.LEGS, EnumItemSlot.FEET};
+     private static final String[] d = new String[]{"item/empty_armor_slot_boots", "item/empty_armor_slot_leggings", "item/empty_armor_slot_chestplate", "item/empty_armor_slot_helmet"};
+     private static final EnumItemSlot[] e = new EnumItemSlot[]{EnumItemSlot.HEAD, EnumItemSlot.CHEST, EnumItemSlot.LEGS, EnumItemSlot.FEET};
 -    private final InventoryCrafting craftInventory = new InventoryCrafting(this, 2, 2);
 -    private final InventoryCraftResult resultInventory = new InventoryCraftResult();
 +    // CraftBukkit start
diff --git a/nms-patches/ContainerWorkbench.patch b/nms-patches/ContainerWorkbench.patch
index 2653e2ddd7..d78f84ead5 100644
--- a/nms-patches/ContainerWorkbench.patch
+++ b/nms-patches/ContainerWorkbench.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/ContainerWorkbench.java
 +++ b/net/minecraft/server/ContainerWorkbench.java
-@@ -1,13 +1,21 @@
+@@ -1,6 +1,10 @@
  package net.minecraft.server;
  
  import java.util.Optional;
@@ -11,10 +11,9 @@
  
  public class ContainerWorkbench extends ContainerRecipeBook<InventoryCrafting> {
  
-     private final InventoryCrafting craftInventory;
+@@ -8,6 +12,10 @@
      private final InventoryCraftResult resultInventory;
--    private final ContainerAccess e;
-+    public final ContainerAccess e;
+     public final ContainerAccess containerAccess;
      private final EntityHuman f;
 +    // CraftBukkit start
 +    private CraftInventoryView bukkitEntity = null;
@@ -34,7 +33,7 @@
 +        this.craftInventory.resultInventory = this.resultInventory;
 +        this.player = playerinventory;
 +        // CraftBukkit end
-         this.e = containeraccess;
+         this.containerAccess = containeraccess;
          this.f = playerinventory.player;
          this.a((Slot) (new SlotResult(playerinventory.player, this.craftInventory, this.resultInventory, 0, 124, 35)));
 @@ -42,7 +54,7 @@
@@ -57,7 +56,7 @@
 @@ -64,7 +77,7 @@
      @Override
      public void a(IInventory iinventory) {
-         this.e.a((world, blockposition) -> {
+         this.containerAccess.a((world, blockposition) -> {
 -            a(this.windowId, world, this.f, this.craftInventory, this.resultInventory);
 +            a(this.windowId, world, this.f, this.craftInventory, this.resultInventory, this); // CraftBukkit
          });
@@ -68,7 +67,7 @@
      @Override
      public boolean canUse(EntityHuman entityhuman) {
 +        if (!this.checkReachable) return true; // CraftBukkit
-         return a(this.e, entityhuman, Blocks.CRAFTING_TABLE);
+         return a(this.containerAccess, entityhuman, Blocks.CRAFTING_TABLE);
      }
  
 @@ -166,4 +180,17 @@
diff --git a/nms-patches/Entity.patch b/nms-patches/Entity.patch
index 9448f729cb..57f8cf16f3 100644
--- a/nms-patches/Entity.patch
+++ b/nms-patches/Entity.patch
@@ -685,7 +685,7 @@
              }
  
              this.dead = true;
-@@ -2239,7 +2620,26 @@
+@@ -2249,7 +2630,26 @@
      }
  
      public void a(AxisAlignedBB axisalignedbb) {
diff --git a/nms-patches/EntityDamageSourceIndirect.patch b/nms-patches/EntityDamageSourceIndirect.patch
index fd14861a2e..c6ef0607ef 100644
--- a/nms-patches/EntityDamageSourceIndirect.patch
+++ b/nms-patches/EntityDamageSourceIndirect.patch
@@ -2,7 +2,7 @@
 +++ b/net/minecraft/server/EntityDamageSourceIndirect.java
 @@ -32,4 +32,10 @@
  
-         return !itemstack.isEmpty() && itemstack.hasName() ? new ChatMessage(s1, new Object[] { entityliving.getScoreboardDisplayName(), ichatbasecomponent, itemstack.B()}) : new ChatMessage(s, new Object[] { entityliving.getScoreboardDisplayName(), ichatbasecomponent});
+         return !itemstack.isEmpty() && itemstack.hasName() ? new ChatMessage(s1, new Object[]{entityliving.getScoreboardDisplayName(), ichatbasecomponent, itemstack.B()}) : new ChatMessage(s, new Object[]{entityliving.getScoreboardDisplayName(), ichatbasecomponent});
      }
 +
 +    // CraftBukkit start
diff --git a/nms-patches/EntityDolphin.patch b/nms-patches/EntityDolphin.patch
index ec59f70fbe..9f824ccb0e 100644
--- a/nms-patches/EntityDolphin.patch
+++ b/nms-patches/EntityDolphin.patch
@@ -4,8 +4,8 @@
          this.goalSelector.a(8, new EntityDolphin.d());
          this.goalSelector.a(8, new PathfinderGoalFollowBoat(this));
          this.goalSelector.a(9, new PathfinderGoalAvoidTarget<>(this, EntityGuardian.class, 8.0F, 1.0D, 1.0D));
--        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityGuardian.class})).a());
-+        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityGuardian.class})).a(new Class[0])); // CraftBukkit - decompile error
+-        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityGuardian.class})).a());
++        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityGuardian.class})).a(new Class[0])); // CraftBukkit - decompile error
      }
  
      @Override
diff --git a/nms-patches/EntityEnderCrystal.patch b/nms-patches/EntityEnderCrystal.patch
index f0c66cd81a..c2418e14d5 100644
--- a/nms-patches/EntityEnderCrystal.patch
+++ b/nms-patches/EntityEnderCrystal.patch
@@ -25,7 +25,7 @@
              }
          }
  
-@@ -81,10 +90,23 @@
+@@ -81,9 +90,22 @@
              return false;
          } else {
              if (!this.dead && !this.world.isClientSide) {
@@ -35,18 +35,17 @@
 +                }
 +                // CraftBukkit end
                  this.die();
-                 if (!this.world.isClientSide) {
-                     if (!damagesource.isExplosion()) {
--                        this.world.explode((Entity) null, this.locX, this.locY, this.locZ, 6.0F, Explosion.Effect.DESTROY);
-+                        // CraftBukkit start
-+                        ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 6.0F, false);
-+                        this.world.getServer().getPluginManager().callEvent(event);
-+                        if (event.isCancelled()) {
-+                            this.dead = false;
-+                            return false;
-+                        }
-+                        this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), Explosion.Effect.DESTROY);
-+                        // CraftBukkit end
-                     }
+                 if (!damagesource.isExplosion()) {
+-                    this.world.explode((Entity) null, this.locX, this.locY, this.locZ, 6.0F, Explosion.Effect.DESTROY);
++                    // CraftBukkit start
++                    ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 6.0F, false);
++                    this.world.getServer().getPluginManager().callEvent(event);
++                    if (event.isCancelled()) {
++                        this.dead = false;
++                        return false;
++                    }
++                    this.world.createExplosion(this, this.locX, this.locY, this.locZ, event.getRadius(), event.getFire(), Explosion.Effect.DESTROY);
++                    // CraftBukkit end
+                 }
  
-                     this.a(damagesource);
+                 this.a(damagesource);
diff --git a/nms-patches/EntityIllagerIllusioner.patch b/nms-patches/EntityIllagerIllusioner.patch
index d279307da5..d4ec47b58b 100644
--- a/nms-patches/EntityIllagerIllusioner.patch
+++ b/nms-patches/EntityIllagerIllusioner.patch
@@ -4,8 +4,8 @@
          this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
          this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
          this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
--        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a());
-+        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
+-        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a());
++        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
          this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
          this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
          this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
diff --git a/nms-patches/EntityLiving.patch b/nms-patches/EntityLiving.patch
index 9492a98a97..ec9630a098 100644
--- a/nms-patches/EntityLiving.patch
+++ b/nms-patches/EntityLiving.patch
@@ -72,7 +72,7 @@
              }
          }
  
-@@ -286,6 +326,18 @@
+@@ -290,6 +330,18 @@
          this.world.getMethodProfiler().exit();
      }
  
@@ -91,7 +91,7 @@
      protected void b(BlockPosition blockposition) {
          int i = EnchantmentManager.a(Enchantments.FROST_WALKER, this);
  
-@@ -310,19 +362,19 @@
+@@ -314,19 +366,19 @@
  
      protected void cn() {
          ++this.deathTicks;
@@ -120,7 +120,7 @@
  
              this.die();
  
-@@ -495,6 +547,17 @@
+@@ -499,6 +551,17 @@
              }
          }
  
@@ -138,7 +138,7 @@
          if (nbttagcompound.hasKeyOfType("Health", 99)) {
              this.setHealth(nbttagcompound.getFloat("Health"));
          }
-@@ -530,9 +593,32 @@
+@@ -536,9 +599,32 @@
  
      }
  
@@ -171,7 +171,7 @@
          try {
              while (iterator.hasNext()) {
                  MobEffectList mobeffectlist = (MobEffectList) iterator.next();
-@@ -540,6 +626,12 @@
+@@ -546,6 +632,12 @@
  
                  if (!mobeffect.tick(this)) {
                      if (!this.world.isClientSide) {
@@ -184,7 +184,7 @@
                          iterator.remove();
                          this.b(mobeffect);
                      }
-@@ -550,6 +642,17 @@
+@@ -556,6 +648,17 @@
          } catch (ConcurrentModificationException concurrentmodificationexception) {
              ;
          }
@@ -202,7 +202,7 @@
  
          if (this.updateEffects) {
              if (!this.world.isClientSide) {
-@@ -659,7 +762,13 @@
+@@ -665,7 +768,13 @@
          this.datawatcher.set(EntityLiving.e, 0);
      }
  
@@ -216,7 +216,7 @@
          if (this.world.isClientSide) {
              return false;
          } else {
-@@ -668,7 +777,14 @@
+@@ -674,7 +783,14 @@
              boolean flag;
  
              for (flag = false; iterator.hasNext(); flag = true) {
@@ -232,7 +232,7 @@
                  iterator.remove();
              }
  
-@@ -693,18 +809,44 @@
+@@ -699,18 +815,44 @@
          return (MobEffect) this.effects.get(mobeffectlist);
      }
  
@@ -278,7 +278,7 @@
                  return true;
              } else {
                  return false;
-@@ -728,13 +870,39 @@
+@@ -734,13 +876,39 @@
          return this.getMonsterType() == EnumMonsterType.UNDEAD;
      }
  
@@ -319,7 +319,7 @@
  
          if (mobeffect != null) {
              this.b(mobeffect);
-@@ -771,20 +939,55 @@
+@@ -777,20 +945,55 @@
  
      }
  
@@ -376,7 +376,7 @@
          this.datawatcher.set(EntityLiving.HEALTH, MathHelper.a(f, 0.0F, this.getMaxHealth()));
      }
  
-@@ -794,7 +997,7 @@
+@@ -800,7 +1003,7 @@
              return false;
          } else if (this.world.isClientSide) {
              return false;
@@ -385,7 +385,7 @@
              return false;
          } else if (damagesource.p() && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
              return false;
-@@ -806,17 +1009,19 @@
+@@ -812,17 +1015,19 @@
              this.ticksFarFromPlayer = 0;
              float f1 = f;
  
@@ -408,7 +408,7 @@
                  this.damageShield(f);
                  f2 = f;
                  f = 0.0F;
-@@ -836,20 +1041,39 @@
+@@ -842,20 +1047,39 @@
  
              if ((float) this.noDamageTicks > 10.0F) {
                  if (f <= this.lastDamage) {
@@ -450,7 +450,7 @@
              this.az = 0.0F;
              Entity entity1 = damagesource.getEntity();
  
-@@ -970,19 +1194,29 @@
+@@ -976,19 +1200,29 @@
              EnumHand[] aenumhand = EnumHand.values();
              int i = aenumhand.length;
  
@@ -484,7 +484,7 @@
                      EntityPlayer entityplayer = (EntityPlayer) this;
  
                      entityplayer.b(StatisticList.ITEM_USED.b(Items.TOTEM_OF_UNDYING));
-@@ -990,13 +1224,15 @@
+@@ -996,13 +1230,15 @@
                  }
  
                  this.setHealth(1.0F);
@@ -504,7 +504,7 @@
          }
      }
  
-@@ -1109,6 +1345,12 @@
+@@ -1115,6 +1351,12 @@
          if (this.isDropExperience() && this.world.getGameRules().getBoolean("doMobLoot")) {
              this.a(damagesource, flag);
              this.dropDeathLoot(damagesource, i, flag);
@@ -517,7 +517,7 @@
          }
  
          this.cE();
-@@ -1212,8 +1454,13 @@
+@@ -1218,8 +1460,13 @@
          int i = MathHelper.f((f - 3.0F - f2) * f1);
  
          if (i > 0) {
@@ -532,7 +532,7 @@
              int j = MathHelper.floor(this.locX);
              int k = MathHelper.floor(this.locY - 0.20000000298023224D);
              int l = MathHelper.floor(this.locZ);
-@@ -1240,7 +1487,7 @@
+@@ -1246,7 +1493,7 @@
  
      protected float applyArmorModifier(DamageSource damagesource, float f) {
          if (!damagesource.ignoresArmor()) {
@@ -541,7 +541,7 @@
              f = CombatMath.a(f, (float) this.getArmorStrength(), (float) this.getAttributeInstance(GenericAttributes.ARMOR_TOUGHNESS).getValue());
          }
  
-@@ -1253,7 +1500,8 @@
+@@ -1259,7 +1506,8 @@
          } else {
              int i;
  
@@ -551,7 +551,7 @@
                  i = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5;
                  int j = 25 - i;
                  float f1 = f * (float) j;
-@@ -1284,28 +1532,170 @@
+@@ -1290,28 +1538,170 @@
          }
      }
  
@@ -570,7 +570,10 @@
 +                public Double apply(Double f) {
 +                    if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && !EntityLiving.this.getEquipment(EnumItemSlot.HEAD).isEmpty()) {
 +                        return -(f - (f * 0.75F));
-+
+ 
+-            f = Math.max(f - this.getAbsorptionHearts(), 0.0F);
+-            this.setAbsorptionHearts(this.getAbsorptionHearts() - (f1 - f));
+-            float f2 = f1 - f;
 +                    }
 +                    return -0.0;
 +                }
@@ -627,7 +630,7 @@
 +                }
 +            };
 +            float absorptionModifier = absorption.apply((double) f).floatValue();
-+
+ 
 +            EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption);
 +            if (event.isCancelled()) {
 +                return false;
@@ -659,10 +662,7 @@
 +                float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT));
 +                this.damageArmor(armorDamage);
 +            }
- 
--            f = Math.max(f - this.getAbsorptionHearts(), 0.0F);
--            this.setAbsorptionHearts(this.getAbsorptionHearts() - (f1 - f));
--            float f2 = f1 - f;
++
 +            // Apply blocking code // PAIL: steal from above
 +            if (event.getDamage(DamageModifier.BLOCKING) < 0) {
 +                this.world.broadcastEntityEffect(this, (byte) 29); // SPIGOT-4635 - shield damage sound
@@ -670,10 +670,10 @@
 +                Entity entity = damagesource.j();
 +
 +                if (entity instanceof EntityLiving) {
-+                    this.d((EntityLiving) entity);
++                    this.shieldBlock((EntityLiving) entity);
 +                }
 +            }
- 
++
 +            absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION);
 +            this.setAbsorptionHearts(Math.max(this.getAbsorptionHearts() - absorptionModifier, 0.0F));
 +            float f2 = absorptionModifier;
@@ -732,7 +732,7 @@
      }
  
      public CombatTracker getCombatTracker() {
-@@ -1373,6 +1763,7 @@
+@@ -1379,6 +1769,7 @@
      public AttributeMapBase getAttributeMap() {
          if (this.attributeMap == null) {
              this.attributeMap = new AttributeMapServer();
@@ -740,7 +740,7 @@
          }
  
          return this.attributeMap;
-@@ -1719,6 +2110,7 @@
+@@ -1725,6 +2116,7 @@
                  }
  
                  if (this.onGround && !this.world.isClientSide) {
@@ -748,7 +748,7 @@
                      this.setFlag(7, false);
                  }
              } else {
-@@ -2100,6 +2492,7 @@
+@@ -2106,6 +2498,7 @@
          }
  
          if (!this.world.isClientSide) {
@@ -756,7 +756,7 @@
              this.setFlag(7, flag);
          }
  
-@@ -2228,12 +2621,12 @@
+@@ -2234,12 +2627,12 @@
  
      @Override
      public boolean isInteractable() {
@@ -771,7 +771,7 @@
      }
  
      @Override
-@@ -2404,7 +2797,27 @@
+@@ -2410,7 +2803,27 @@
      protected void q() {
          if (!this.activeItem.isEmpty() && this.isHandRaised()) {
              this.b(this.activeItem, 16);
@@ -800,7 +800,7 @@
              this.dp();
          }
  
-@@ -2489,10 +2902,18 @@
+@@ -2495,10 +2908,18 @@
              }
  
              if (flag2) {
@@ -822,7 +822,7 @@
              }
          }
  
-@@ -2579,7 +3000,7 @@
+@@ -2585,7 +3006,7 @@
      }
  
      public void dy() {
@@ -831,7 +831,7 @@
          World world = this.world;
  
          this.world.getClass();
-@@ -2641,7 +3062,7 @@
+@@ -2647,7 +3068,7 @@
                  Pair<MobEffect, Float> pair = (Pair) iterator.next();
  
                  if (!world.isClientSide && pair.getLeft() != null && world.random.nextFloat() < (Float) pair.getRight()) {
diff --git a/nms-patches/EntityLlamaTrader.patch b/nms-patches/EntityLlamaTrader.patch
index 5894e6b926..898e4b89a9 100644
--- a/nms-patches/EntityLlamaTrader.patch
+++ b/nms-patches/EntityLlamaTrader.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/EntityLlamaTrader.java
 +++ b/net/minecraft/server/EntityLlamaTrader.java
-@@ -129,7 +129,7 @@
+@@ -126,7 +126,7 @@
  
          @Override
          public void c() {
diff --git a/nms-patches/EntityPanda.patch b/nms-patches/EntityPanda.patch
index d18849b871..59cd39aae1 100644
--- a/nms-patches/EntityPanda.patch
+++ b/nms-patches/EntityPanda.patch
@@ -13,8 +13,8 @@
  
      @Override
      protected void a(EntityItem entityitem) {
--        if (this.getEquipment(EnumItemSlot.MAINHAND).isEmpty() && EntityPanda.bQ.test(entityitem)) {
-+        if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entityitem, 0, !(this.getEquipment(EnumItemSlot.MAINHAND).isEmpty() && EntityPanda.bQ.test(entityitem))).isCancelled()) { // CraftBukkit
+-        if (this.getEquipment(EnumItemSlot.MAINHAND).isEmpty() && EntityPanda.PICKUP_PREDICATE.test(entityitem)) {
++        if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entityitem, 0, !(this.getEquipment(EnumItemSlot.MAINHAND).isEmpty() && EntityPanda.PICKUP_PREDICATE.test(entityitem))).isCancelled()) { // CraftBukkit
              ItemStack itemstack = entityitem.getItemStack();
  
              this.setSlot(EnumItemSlot.MAINHAND, itemstack);
diff --git a/nms-patches/EntityParrot.patch b/nms-patches/EntityParrot.patch
index 7a9c02c078..5ec3cbdd5f 100644
--- a/nms-patches/EntityParrot.patch
+++ b/nms-patches/EntityParrot.patch
@@ -3,7 +3,7 @@
 @@ -21,7 +21,7 @@
      };
      private static final Item bK = Items.COOKIE;
-     private static final Set<Item> bL = Sets.newHashSet(new Item[] { Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS});
+     private static final Set<Item> bL = Sets.newHashSet(new Item[]{Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS});
 -    private static final Map<EntityTypes<?>, SoundEffect> bM = (Map) SystemUtils.a((Object) Maps.newHashMap(), (hashmap) -> {
 +    private static final Map<EntityTypes<?>, SoundEffect> bM = (Map) SystemUtils.a(Maps.newHashMap(), (hashmap) -> { // CraftBukkit - decompile error
          hashmap.put(EntityTypes.BLAZE, SoundEffects.ENTITY_PARROT_IMITATE_BLAZE);
diff --git a/nms-patches/EntityPillager.patch b/nms-patches/EntityPillager.patch
index cd82166783..42b900ec92 100644
--- a/nms-patches/EntityPillager.patch
+++ b/nms-patches/EntityPillager.patch
@@ -4,8 +4,8 @@
          this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
          this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 15.0F, 1.0F));
          this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 15.0F));
--        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a());
-+        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
+-        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a());
++        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
          this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true));
          this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false));
          this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true));
diff --git a/nms-patches/EntityPlayer.patch b/nms-patches/EntityPlayer.patch
index 7f65c99380..823e78689f 100644
--- a/nms-patches/EntityPlayer.patch
+++ b/nms-patches/EntityPlayer.patch
@@ -689,7 +689,7 @@
          this.cl = packetplayinsettings.e();
 @@ -1149,13 +1479,13 @@
          if (entity instanceof EntityHuman) {
-             this.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(new int[] { entity.getId()}));
+             this.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(new int[]{entity.getId()}));
          } else {
 -            this.removeQueue.add(entity.getId());
 +            this.removeQueue.add((Integer) entity.getId()); // CraftBukkit - decompile error
diff --git a/nms-patches/EntityRavager.patch b/nms-patches/EntityRavager.patch
index 2430bfb2e0..6cdbcf52a4 100644
--- a/nms-patches/EntityRavager.patch
+++ b/nms-patches/EntityRavager.patch
@@ -4,8 +4,8 @@
          this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 0.4D));
          this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F));
          this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
--        this.targetSelector.a(2, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a());
-+        this.targetSelector.a(2, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
+-        this.targetSelector.a(2, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a());
++        this.targetSelector.a(2, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
          this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true));
          this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, true));
          this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true));
diff --git a/nms-patches/EntityThrownExpBottle.patch b/nms-patches/EntityThrownExpBottle.patch
index 761ec125ac..3cef308b55 100644
--- a/nms-patches/EntityThrownExpBottle.patch
+++ b/nms-patches/EntityThrownExpBottle.patch
@@ -4,16 +4,16 @@
      @Override
      protected void a(MovingObjectPosition movingobjectposition) {
          if (!this.world.isClientSide) {
--            this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.b));
+-            this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.WATER));
 +            // CraftBukkit - moved to after event
-+            // this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.b));
++            // this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.WATER));
              int i = 3 + this.world.random.nextInt(5) + this.world.random.nextInt(5);
  
 +            // CraftBukkit start
 +            org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, i);
 +            i = event.getExperience();
 +            if (event.getShowEffect()) {
-+                this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.b));
++                this.world.triggerEffect(2002, new BlockPosition(this), PotionUtil.a(Potions.WATER));
 +            }
 +            // CraftBukkit end
 +
diff --git a/nms-patches/EntityVex.patch b/nms-patches/EntityVex.patch
index 861e7329bb..ba140cd0eb 100644
--- a/nms-patches/EntityVex.patch
+++ b/nms-patches/EntityVex.patch
@@ -12,8 +12,8 @@
          this.goalSelector.a(8, new EntityVex.d());
          this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
          this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
--        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a());
-+        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[] { EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
+-        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a());
++        this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error
          this.targetSelector.a(2, new EntityVex.b(this));
          this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true));
      }
diff --git a/nms-patches/EntityVillager.patch b/nms-patches/EntityVillager.patch
index 8f800f0628..c563072b33 100644
--- a/nms-patches/EntityVillager.patch
+++ b/nms-patches/EntityVillager.patch
@@ -60,7 +60,7 @@
              }
          }
  
-@@ -558,7 +575,12 @@
+@@ -564,7 +581,12 @@
              entitywitch.setCustomNameVisible(this.getCustomNameVisible());
          }
  
@@ -74,7 +74,7 @@
          this.die();
      }
  
-@@ -730,7 +752,7 @@
+@@ -737,7 +759,7 @@
  
              if (entityirongolem != null) {
                  if (entityirongolem.a((GeneratorAccess) this.world, EnumMobSpawn.MOB_SUMMONED) && entityirongolem.a((IWorldReader) this.world)) {
@@ -83,7 +83,7 @@
                      return entityirongolem;
                  }
  
-@@ -780,7 +802,7 @@
+@@ -787,7 +809,7 @@
          EntityVillager.a entityvillager_a = (EntityVillager.a) this.getBehaviorController().getMemory(MemoryModuleType.GOLEM_SPAWN_CONDITIONS).orElseGet(EntityVillager.a::new);
  
          entityvillager_a.b(this.world.getTime());
diff --git a/nms-patches/EntityZombieVillager.patch b/nms-patches/EntityZombieVillager.patch
index cb1e11c951..45ac546031 100644
--- a/nms-patches/EntityZombieVillager.patch
+++ b/nms-patches/EntityZombieVillager.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/EntityZombieVillager.java
 +++ b/net/minecraft/server/EntityZombieVillager.java
-@@ -3,15 +3,20 @@
+@@ -3,6 +3,10 @@
  import com.mojang.datafixers.Dynamic;
  import java.util.UUID;
  import javax.annotation.Nullable;
@@ -11,11 +11,8 @@
  
  public class EntityZombieVillager extends EntityZombie implements VillagerDataHolder {
  
-     public static final DataWatcherObject<Boolean> CONVERTING = DataWatcher.a(EntityZombieVillager.class, DataWatcherRegistry.i);
-     private static final DataWatcherObject<VillagerData> c = DataWatcher.a(EntityZombieVillager.class, DataWatcherRegistry.q);
-     public int conversionTime;
--    private UUID conversionPlayer;
-+    public UUID conversionPlayer; // CraftBukkit - public
+@@ -12,6 +16,7 @@
+     public UUID conversionPlayer;
      private NBTTagCompound bB;
      private int bC;
 +    private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field
diff --git a/nms-patches/HandshakeListener.patch b/nms-patches/HandshakeListener.patch
index c9446a0cc0..d74cd5ed13 100644
--- a/nms-patches/HandshakeListener.patch
+++ b/nms-patches/HandshakeListener.patch
@@ -19,52 +19,52 @@
      private final NetworkManager b;
  
 @@ -17,6 +27,41 @@
-             this.b.setProtocol(EnumProtocol.LOGIN);
-             ChatMessage chatmessage;
+                 this.b.setProtocol(EnumProtocol.LOGIN);
+                 ChatMessage chatmessage;
  
-+            // CraftBukkit start - Connection throttle
-+            try {
-+                long currentTime = System.currentTimeMillis();
-+                long connectionThrottle = MinecraftServer.getServer().server.getConnectionThrottle();
-+                InetAddress address = ((java.net.InetSocketAddress) this.b.getSocketAddress()).getAddress();
++                // CraftBukkit start - Connection throttle
++                try {
++                    long currentTime = System.currentTimeMillis();
++                    long connectionThrottle = MinecraftServer.getServer().server.getConnectionThrottle();
++                    InetAddress address = ((java.net.InetSocketAddress) this.b.getSocketAddress()).getAddress();
++
++                    synchronized (throttleTracker) {
++                        if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
++                            throttleTracker.put(address, currentTime);
++                            chatmessage = new ChatMessage("Connection throttled! Please wait before reconnecting.");
++                            this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
++                            this.b.close(chatmessage);
++                            return;
++                        }
 +
-+                synchronized (throttleTracker) {
-+                    if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
 +                        throttleTracker.put(address, currentTime);
-+                        chatmessage = new ChatMessage("Connection throttled! Please wait before reconnecting.");
-+                        this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
-+                        this.b.close(chatmessage);
-+                        return;
-+                    }
++                        throttleCounter++;
++                        if (throttleCounter > 200) {
++                            throttleCounter = 0;
 +
-+                    throttleTracker.put(address, currentTime);
-+                    throttleCounter++;
-+                    if (throttleCounter > 200) {
-+                        throttleCounter = 0;
-+
-+                        // Cleanup stale entries
-+                        java.util.Iterator iter = throttleTracker.entrySet().iterator();
-+                        while (iter.hasNext()) {
-+                            java.util.Map.Entry<InetAddress, Long> entry = (java.util.Map.Entry) iter.next();
-+                            if (entry.getValue() > connectionThrottle) {
-+                                iter.remove();
++                            // Cleanup stale entries
++                            java.util.Iterator iter = throttleTracker.entrySet().iterator();
++                            while (iter.hasNext()) {
++                                java.util.Map.Entry<InetAddress, Long> entry = (java.util.Map.Entry) iter.next();
++                                if (entry.getValue() > connectionThrottle) {
++                                    iter.remove();
++                                }
 +                            }
 +                        }
 +                    }
++                } catch (Throwable t) {
++                    org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
 +                }
-+            } catch (Throwable t) {
-+                org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
-+            }
-+            // CraftBukkit end
++                // CraftBukkit end
 +
-             if (packethandshakinginsetprotocol.c() > SharedConstants.a().getProtocolVersion()) {
-                 chatmessage = new ChatMessage("multiplayer.disconnect.outdated_server", new Object[] { SharedConstants.a().getName()});
-                 this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
+                 if (packethandshakinginsetprotocol.c() > SharedConstants.a().getProtocolVersion()) {
+                     chatmessage = new ChatMessage("multiplayer.disconnect.outdated_server", new Object[]{SharedConstants.a().getName()});
+                     this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
 @@ -27,6 +72,7 @@
-                 this.b.close(chatmessage);
-             } else {
-                 this.b.setPacketListener(new LoginListener(this.a, this.b));
-+                ((LoginListener) this.b.i()).hostname = packethandshakinginsetprotocol.hostname + ":" + packethandshakinginsetprotocol.port; // CraftBukkit - set hostname
-             }
-             break;
-         case STATUS:
+                     this.b.close(chatmessage);
+                 } else {
+                     this.b.setPacketListener(new LoginListener(this.a, this.b));
++                    ((LoginListener) this.b.i()).hostname = packethandshakinginsetprotocol.hostname + ":" + packethandshakinginsetprotocol.port; // CraftBukkit - set hostname
+                 }
+                 break;
+             case STATUS:
diff --git a/nms-patches/IMerchant.patch b/nms-patches/IMerchant.patch
index 6103a93d3d..a7eac44dd2 100644
--- a/nms-patches/IMerchant.patch
+++ b/nms-patches/IMerchant.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/IMerchant.java
 +++ b/net/minecraft/server/IMerchant.java
-@@ -38,4 +38,6 @@
+@@ -40,4 +40,6 @@
          }
  
      }
diff --git a/nms-patches/InventoryCrafting.patch b/nms-patches/InventoryCrafting.patch
index 8557c6e662..1738e42dbe 100644
--- a/nms-patches/InventoryCrafting.patch
+++ b/nms-patches/InventoryCrafting.patch
@@ -62,7 +62,7 @@
 +
 +    @Override
 +    public Location getLocation() {
-+        return container instanceof ContainerWorkbench ? ((ContainerWorkbench) container).e.getLocation() : owner.getBukkitEntity().getLocation();
++        return container instanceof ContainerWorkbench ? ((ContainerWorkbench) container).containerAccess.getLocation() : owner.getBukkitEntity().getLocation();
 +    }
 +
 +    @Override
diff --git a/nms-patches/ItemArmor.patch b/nms-patches/ItemArmor.patch
index 29cae8763b..181467b7d8 100644
--- a/nms-patches/ItemArmor.patch
+++ b/nms-patches/ItemArmor.patch
@@ -11,7 +11,7 @@
 +
  public class ItemArmor extends Item {
  
-     private static final UUID[] k = new UUID[] { UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
+     private static final UUID[] k = new UUID[]{UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
 @@ -30,6 +35,32 @@
              EntityLiving entityliving = (EntityLiving) list.get(0);
              EnumItemSlot enumitemslot = EntityInsentient.h(itemstack);
diff --git a/nms-patches/LegacyPingHandler.patch b/nms-patches/LegacyPingHandler.patch
index b368ae2d03..b56969813b 100644
--- a/nms-patches/LegacyPingHandler.patch
+++ b/nms-patches/LegacyPingHandler.patch
@@ -7,28 +7,28 @@
 +            org.bukkit.event.server.ServerListPingEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callServerListPingEvent(minecraftserver.server, inetsocketaddress.getAddress(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers()); // CraftBukkit
  
              switch (i) {
-             case 0:
-                 LegacyPingHandler.LOGGER.debug("Ping: (<1.3.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
--                s = String.format("%s\u00a7%d\u00a7%d", minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
-+                s = String.format("%s\u00a7%d\u00a7%d", event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
-                 this.a(channelhandlercontext, this.a(s));
-                 break;
-             case 1:
+                 case 0:
+                     LegacyPingHandler.LOGGER.debug("Ping: (<1.3.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
+-                    s = String.format("%s\u00a7%d\u00a7%d", minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
++                    s = String.format("%s\u00a7%d\u00a7%d", event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
+                     this.a(channelhandlercontext, this.a(s));
+                     break;
+                 case 1:
 @@ -47,7 +48,7 @@
-                 }
+                     }
  
-                 LegacyPingHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
--                s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
-+                s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
-                 this.a(channelhandlercontext, this.a(s));
-                 break;
-             default:
+                     LegacyPingHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
+-                    s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
++                    s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
+                     this.a(channelhandlercontext, this.a(s));
+                     break;
+                 default:
 @@ -66,7 +67,7 @@
-                 }
+                     }
  
-                 LegacyPingHandler.LOGGER.debug("Ping: (1.6) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
--                String s1 = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
-+                String s1 = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
-                 ByteBuf bytebuf1 = this.a(s1);
+                     LegacyPingHandler.LOGGER.debug("Ping: (1.6) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
+-                    String s1 = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers());
++                    String s1 = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
+                     ByteBuf bytebuf1 = this.a(s1);
  
-                 try {
+                     try {
diff --git a/nms-patches/PathfinderGoalDefendVillage.patch b/nms-patches/PathfinderGoalDefendVillage.patch
index 19cab7c2a6..f12edb2999 100644
--- a/nms-patches/PathfinderGoalDefendVillage.patch
+++ b/nms-patches/PathfinderGoalDefendVillage.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/PathfinderGoalDefendVillage.java
 +++ b/net/minecraft/server/PathfinderGoalDefendVillage.java
-@@ -20,7 +20,7 @@
+@@ -43,7 +43,7 @@
  
      @Override
      public void c() {
diff --git a/nms-patches/PlayerChunk.patch b/nms-patches/PlayerChunk.patch
index e34a359bb2..e344cb0090 100644
--- a/nms-patches/PlayerChunk.patch
+++ b/nms-patches/PlayerChunk.patch
@@ -1,14 +1,5 @@
 --- a/net/minecraft/server/PlayerChunk.java
 +++ b/net/minecraft/server/PlayerChunk.java
-@@ -23,7 +23,7 @@
-     private volatile CompletableFuture<Either<Chunk, PlayerChunk.Failure>> tickingFuture;
-     private volatile CompletableFuture<Either<Chunk, PlayerChunk.Failure>> entityTickingFuture;
-     private CompletableFuture<IChunkAccess> chunkSave;
--    private int oldTicketLevel;
-+    public int oldTicketLevel; // CraftBukkit - public
-     private int ticketLevel;
-     private int n;
-     private final ChunkCoordIntPair location;
 @@ -43,7 +43,7 @@
          this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
          this.tickingFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
@@ -24,7 +15,7 @@
  
 +    // CraftBukkit start
 +    public Chunk getFullChunk() {
-+        CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> statusFuture = this.getStatusFuture(ChunkStatus.FULL);
++        CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> statusFuture = this.getStatusFutureUnchecked(ChunkStatus.FULL);
 +        Either<IChunkAccess, PlayerChunk.Failure> either = (Either<IChunkAccess, PlayerChunk.Failure>) statusFuture.getNow(null);
 +        return either == null ? null : (Chunk) either.left().orElse(null);
 +    }
@@ -33,16 +24,7 @@
      public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFutureUnchecked(ChunkStatus chunkstatus) {
          CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = (CompletableFuture) this.statusFutures.get(chunkstatus.c());
  
-@@ -62,7 +70,7 @@
-     }
- 
-     public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getStatusFuture(ChunkStatus chunkstatus) {
--        return b(this.ticketLevel).b(chunkstatus) ? this.getStatusFutureUnchecked(chunkstatus) : PlayerChunk.UNLOADED_CHUNK_ACCESS_FUTURE;
-+        return b(this.oldTicketLevel).b(chunkstatus) ? this.getStatusFutureUnchecked(chunkstatus) : PlayerChunk.UNLOADED_CHUNK_ACCESS_FUTURE; // CraftBukkit using oldTicketLevel for isLoaded checks
-     }
- 
-     public CompletableFuture<Either<Chunk, PlayerChunk.Failure>> a() {
-@@ -76,9 +84,9 @@
+@@ -72,9 +80,9 @@
      @Nullable
      public Chunk getChunk() {
          CompletableFuture<Either<Chunk, PlayerChunk.Failure>> completablefuture = this.a();
@@ -54,7 +36,7 @@
      }
  
      public CompletableFuture<IChunkAccess> getChunkSave() {
-@@ -201,7 +209,7 @@
+@@ -197,7 +205,7 @@
          CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = (CompletableFuture) this.statusFutures.get(i);
  
          if (completablefuture != null) {
@@ -63,13 +45,13 @@
  
              if (either == null || either.left().isPresent()) {
                  return completablefuture;
-@@ -256,6 +264,21 @@
+@@ -252,6 +260,21 @@
          boolean flag1 = this.ticketLevel <= PlayerChunkMap.GOLDEN_TICKET;
-         PlayerChunk.State playerchunk_state = c(this.oldTicketLevel);
-         PlayerChunk.State playerchunk_state1 = c(this.ticketLevel);
+         PlayerChunk.State playerchunk_state = getChunkState(this.oldTicketLevel);
+         PlayerChunk.State playerchunk_state1 = getChunkState(this.ticketLevel);
 +        // CraftBukkit start
 +        // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins.
-+        if (playerchunk_state.a(PlayerChunk.State.BORDER) && !playerchunk_state1.a(PlayerChunk.State.BORDER)) { // PAIL oldChunkState, newChunkState, isAtLeast
++        if (playerchunk_state.isAtLeast(PlayerChunk.State.BORDER) && !playerchunk_state1.isAtLeast(PlayerChunk.State.BORDER)) {
 +            this.getStatusFutureUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
 +                either.ifLeft((chunkAccess) -> {
 +                    Chunk chunk = (Chunk) chunkAccess;
@@ -82,10 +64,10 @@
 +            });
 +        }
 +        // CraftBukkit end
+         CompletableFuture completablefuture;
  
-         if (flag1) {
-             for (int i = flag ? chunkstatus.c() + 1 : 0; i <= chunkstatus1.c(); ++i) {
-@@ -294,7 +317,7 @@
+         if (flag) {
+@@ -283,7 +306,7 @@
          if (flag2 && !flag3) {
              completablefuture = this.fullChunkFuture;
              this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
@@ -94,13 +76,13 @@
                  playerchunkmap.getClass();
                  return either1.ifLeft(playerchunkmap::a);
              }));
-@@ -332,6 +355,17 @@
+@@ -321,6 +344,17 @@
  
          this.w.a(this.location, this::j, this.ticketLevel, this::d);
          this.oldTicketLevel = this.ticketLevel;
 +        // CraftBukkit start
 +        // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins.
-+        if (!playerchunk_state.a(PlayerChunk.State.BORDER) && playerchunk_state1.a(PlayerChunk.State.BORDER)) { // PAIL oldChunkState, newChunkState, isAtLeast
++        if (!playerchunk_state.isAtLeast(PlayerChunk.State.BORDER) && playerchunk_state1.isAtLeast(PlayerChunk.State.BORDER)) {
 +            this.getStatusFutureUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
 +                either.ifLeft((chunkAccess) -> {
 +                    Chunk chunk = (Chunk) chunkAccess;
@@ -111,4 +93,4 @@
 +        // CraftBukkit end
      }
  
-     public static ChunkStatus b(int i) {
+     public static ChunkStatus getChunkStatus(int i) {
diff --git a/nms-patches/PlayerChunkMap.patch b/nms-patches/PlayerChunkMap.patch
index 0700775c92..c4bb4ac9c6 100644
--- a/nms-patches/PlayerChunkMap.patch
+++ b/nms-patches/PlayerChunkMap.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/PlayerChunkMap.java
 +++ b/net/minecraft/server/PlayerChunkMap.java
-@@ -35,6 +35,7 @@
+@@ -38,6 +38,7 @@
  import org.apache.commons.lang3.mutable.MutableBoolean;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
@@ -8,7 +8,7 @@
  
  public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
  
-@@ -181,9 +182,12 @@
+@@ -186,9 +187,12 @@
  
          return completablefuture1.thenApply((list1) -> {
              List<IChunkAccess> list2 = Lists.newArrayList();
@@ -23,7 +23,7 @@
                  final Either<IChunkAccess, PlayerChunk.Failure> either = (Either) iterator.next();
                  Optional<IChunkAccess> optional = either.left();
  
-@@ -279,7 +283,7 @@
+@@ -286,7 +290,7 @@
              PlayerChunkMap.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.x.getName());
          } else {
              this.visibleChunks.values().stream().filter(PlayerChunk::hasBeenLoaded).forEach((playerchunk) -> {
@@ -32,7 +32,7 @@
  
                  if (ichunkaccess instanceof ProtoChunkExtension || ichunkaccess instanceof Chunk) {
                      this.saveChunk(ichunkaccess);
-@@ -290,7 +294,6 @@
+@@ -297,7 +301,6 @@
          }
  
      }
@@ -40,16 +40,25 @@
      protected void unloadChunks(BooleanSupplier booleansupplier) {
          GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler();
  
-@@ -416,7 +419,7 @@
-                     return CompletableFuture.completedFuture(Either.right(playerchunk_failure));
-                 });
-             }, (runnable) -> {
--                this.mailboxWorldGen.a((Object) ChunkTaskQueueSorter.a(playerchunk, runnable));
-+                this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable)); // CraftBukkit - decompile error
+@@ -336,7 +339,7 @@
+ 
+     private void a(long i, PlayerChunk playerchunk) {
+         CompletableFuture<IChunkAccess> completablefuture = playerchunk.getChunkSave();
+-        Consumer consumer = (ichunkaccess) -> {
++        Consumer<IChunkAccess> consumer = (ichunkaccess) -> { // CraftBukkit - decompile error
+             CompletableFuture<IChunkAccess> completablefuture1 = playerchunk.getChunkSave();
+ 
+             if (completablefuture1 != completablefuture) {
+@@ -485,7 +488,7 @@
+                 return CompletableFuture.completedFuture(Either.right(playerchunk_failure));
              });
-         }
+         }, (runnable) -> {
+-            this.mailboxWorldGen.a((Object) ChunkTaskQueueSorter.a(playerchunk, runnable));
++            this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable)); // CraftBukkit - decompile error
+         });
      }
-@@ -498,7 +501,7 @@
+ 
+@@ -566,7 +569,7 @@
              long i = playerchunk.h().pair();
  
              playerchunk.getClass();
@@ -58,7 +67,7 @@
          });
      }
  
-@@ -515,7 +518,7 @@
+@@ -583,7 +586,7 @@
                  return Either.left(chunk);
              });
          }, (runnable) -> {
@@ -67,7 +76,7 @@
          });
  
          completablefuture1.thenAcceptAsync((either) -> {
-@@ -529,7 +532,7 @@
+@@ -597,7 +600,7 @@
                  return Either.left(chunk);
              });
          }, (runnable) -> {
@@ -76,7 +85,7 @@
          });
          return completablefuture1;
      }
-@@ -543,7 +546,7 @@
+@@ -611,7 +614,7 @@
                  return chunk;
              });
          }, (runnable) -> {
@@ -85,7 +94,7 @@
          });
      }
  
-@@ -607,9 +610,10 @@
+@@ -675,9 +678,10 @@
                  ChunkCoordIntPair chunkcoordintpair = playerchunk.h();
                  Packet<?>[] apacket = new Packet[2];
  
@@ -97,7 +106,7 @@
                      boolean flag1 = i1 <= this.viewDistance;
  
                      this.sendChunk(entityplayer, chunkcoordintpair, apacket, flag, flag1);
-@@ -664,7 +668,7 @@
+@@ -732,7 +736,7 @@
      private NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException {
          NBTTagCompound nbttagcompound = this.read(chunkcoordintpair);
  
@@ -106,7 +115,7 @@
      }
  
      boolean d(ChunkCoordIntPair chunkcoordintpair) {
-@@ -984,7 +988,7 @@
+@@ -1052,7 +1056,7 @@
          public final Set<EntityPlayer> trackedPlayers = Sets.newHashSet();
  
          public EntityTracker(Entity entity, int i, int j, boolean flag) {
@@ -115,7 +124,7 @@
              this.tracker = entity;
              this.trackingDistance = i;
              this.e = SectionPosition.a(entity);
-@@ -1053,6 +1057,17 @@
+@@ -1121,6 +1125,17 @@
                          }
                      }
  
diff --git a/nms-patches/PlayerConnection.patch b/nms-patches/PlayerConnection.patch
index 0fc52e5db9..25918bc158 100644
--- a/nms-patches/PlayerConnection.patch
+++ b/nms-patches/PlayerConnection.patch
@@ -507,7 +507,7 @@
                              this.B = d12 >= -0.03125D && this.player.playerInteractManager.getGameMode() != EnumGamemode.SPECTATOR && !this.minecraftServer.getAllowFlight() && !this.player.abilities.canFly && !this.player.hasEffect(MobEffects.LEVITATION) && !this.player.isGliding() && !worldserver.a(this.player.getBoundingBox().g(0.0625D).b(0.0D, -0.55D, 0.0D));
                              this.player.onGround = packetplayinflying.b();
                              this.player.getWorldServer().getChunkProvider().movePlayer(this.player);
-@@ -708,10 +1009,60 @@
+@@ -712,10 +1013,60 @@
      }
  
      public void a(double d0, double d1, double d2, float f, float f1) {
@@ -569,7 +569,7 @@
          double d3 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.X) ? this.player.locX : 0.0D;
          double d4 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.Y) ? this.player.locY : 0.0D;
          double d5 = set.contains(PacketPlayOutPosition.EnumPlayerTeleportFlags.Z) ? this.player.locZ : 0.0D;
-@@ -723,6 +1074,14 @@
+@@ -727,6 +1078,14 @@
              this.teleportAwait = 0;
          }
  
@@ -584,7 +584,7 @@
          this.A = this.e;
          this.player.setLocation(d0, d1, d2, f, f1);
          this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.teleportAwait));
-@@ -731,6 +1090,7 @@
+@@ -735,6 +1094,7 @@
      @Override
      public void a(PacketPlayInBlockDig packetplayinblockdig) {
          PlayerConnectionUtils.ensureMainThread(packetplayinblockdig, this, this.player.getWorldServer());
@@ -592,73 +592,73 @@
          WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
          BlockPosition blockposition = packetplayinblockdig.b();
  
-@@ -740,13 +1100,45 @@
-             if (!this.player.isSpectator()) {
-                 ItemStack itemstack = this.player.b(EnumHand.OFF_HAND);
+@@ -744,13 +1104,45 @@
+                 if (!this.player.isSpectator()) {
+                     ItemStack itemstack = this.player.b(EnumHand.OFF_HAND);
  
--                this.player.a(EnumHand.OFF_HAND, this.player.b(EnumHand.MAIN_HAND));
--                this.player.a(EnumHand.MAIN_HAND, itemstack);
-+                // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394)
-+                CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemstack);
-+                CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.b(EnumHand.MAIN_HAND));
-+                PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(getPlayer(), mainHand.clone(), offHand.clone());
-+                this.server.getPluginManager().callEvent(swapItemsEvent);
-+                if (swapItemsEvent.isCancelled()) {
-+                    return;
-+                }
-+                if (swapItemsEvent.getOffHandItem().equals(offHand)) {
-+                    this.player.a(EnumHand.OFF_HAND, this.player.b(EnumHand.MAIN_HAND));
-+                } else {
-+                    this.player.a(EnumHand.OFF_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getOffHandItem()));
-+                }
-+                if (swapItemsEvent.getMainHandItem().equals(mainHand)) {
-+                    this.player.a(EnumHand.MAIN_HAND, itemstack);
-+                } else {
-+                    this.player.a(EnumHand.MAIN_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getMainHandItem()));
-+                }
-+                // CraftBukkit end
-             }
- 
-             return;
-         case DROP_ITEM:
-             if (!this.player.isSpectator()) {
-+                // limit how quickly items can be dropped
-+                // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick.
-+                if (this.lastDropTick != MinecraftServer.currentTick) {
-+                    this.dropCount = 0;
-+                    this.lastDropTick = MinecraftServer.currentTick;
-+                } else {
-+                    // Else we increment the drop count and check the amount.
-+                    this.dropCount++;
-+                    if (this.dropCount >= 20) {
-+                        LOGGER.warn(this.player.getName() + " dropped their items too quickly!");
-+                        this.disconnect("You dropped your items too quickly (Hacking?)");
+-                    this.player.a(EnumHand.OFF_HAND, this.player.b(EnumHand.MAIN_HAND));
+-                    this.player.a(EnumHand.MAIN_HAND, itemstack);
++                    // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394)
++                    CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemstack);
++                    CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.b(EnumHand.MAIN_HAND));
++                    PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(getPlayer(), mainHand.clone(), offHand.clone());
++                    this.server.getPluginManager().callEvent(swapItemsEvent);
++                    if (swapItemsEvent.isCancelled()) {
 +                        return;
 +                    }
-+                }
-+                // CraftBukkit end
-                 this.player.n(false);
-             }
++                    if (swapItemsEvent.getOffHandItem().equals(offHand)) {
++                        this.player.a(EnumHand.OFF_HAND, this.player.b(EnumHand.MAIN_HAND));
++                    } else {
++                        this.player.a(EnumHand.OFF_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getOffHandItem()));
++                    }
++                    if (swapItemsEvent.getMainHandItem().equals(mainHand)) {
++                        this.player.a(EnumHand.MAIN_HAND, itemstack);
++                    } else {
++                        this.player.a(EnumHand.MAIN_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getMainHandItem()));
++                    }
++                    // CraftBukkit end
+                 }
  
-@@ -777,7 +1169,15 @@
-                     if (!this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.getWorldBorder().a(blockposition)) {
-                         this.player.playerInteractManager.a(blockposition, packetplayinblockdig.c());
-                     } else {
-+                        // CraftBukkit start - fire PlayerInteractEvent
-+                        CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, packetplayinblockdig.c(), this.player.inventory.getItemInHand(), EnumHand.MAIN_HAND);
-                         this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition));
-+                        // Update any tile entity data for this block
-+                        TileEntity tileentity = worldserver.getTileEntity(blockposition);
-+                        if (tileentity != null) {
-+                            this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
+                 return;
+             case DROP_ITEM:
+                 if (!this.player.isSpectator()) {
++                    // limit how quickly items can be dropped
++                    // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick.
++                    if (this.lastDropTick != MinecraftServer.currentTick) {
++                        this.dropCount = 0;
++                        this.lastDropTick = MinecraftServer.currentTick;
++                    } else {
++                        // Else we increment the drop count and check the amount.
++                        this.dropCount++;
++                        if (this.dropCount >= 20) {
++                            LOGGER.warn(this.player.getName() + " dropped their items too quickly!");
++                            this.disconnect("You dropped your items too quickly (Hacking?)");
++                            return;
 +                        }
-+                        // CraftBukkit end
-                     }
-                 } else {
-                     if (packetplayinblockdig.d() == PacketPlayInBlockDig.EnumPlayerDigType.STOP_DESTROY_BLOCK) {
-@@ -796,11 +1196,13 @@
-         default:
-             throw new IllegalArgumentException("Invalid player action");
++                    }
++                    // CraftBukkit end
+                     this.player.n(false);
+                 }
+ 
+@@ -781,7 +1173,15 @@
+                         if (!this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.getWorldBorder().a(blockposition)) {
+                             this.player.playerInteractManager.a(blockposition, packetplayinblockdig.c());
+                         } else {
++                            // CraftBukkit start - fire PlayerInteractEvent
++                            CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, packetplayinblockdig.c(), this.player.inventory.getItemInHand(), EnumHand.MAIN_HAND);
+                             this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition));
++                            // Update any tile entity data for this block
++                            TileEntity tileentity = worldserver.getTileEntity(blockposition);
++                            if (tileentity != null) {
++                                this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
++                            }
++                            // CraftBukkit end
+                         }
+                     } else {
+                         if (packetplayinblockdig.d() == PacketPlayInBlockDig.EnumPlayerDigType.STOP_DESTROY_BLOCK) {
+@@ -800,11 +1200,13 @@
+             default:
+                 throw new IllegalArgumentException("Invalid player action");
          }
 +        // CraftBukkit end
      }
@@ -670,7 +670,7 @@
          WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
          EnumHand enumhand = packetplayinuseitem.b();
          ItemStack itemstack = this.player.b(enumhand);
-@@ -814,6 +1216,14 @@
+@@ -818,6 +1220,14 @@
  
              this.player.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent, ChatMessageType.GAME_INFO));
          } else if (this.teleportPos == null && this.player.e((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && !this.minecraftServer.a(worldserver, blockposition, this.player) && worldserver.getWorldBorder().a(blockposition)) {
@@ -685,7 +685,7 @@
              this.player.playerInteractManager.a(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock);
          }
  
-@@ -824,13 +1234,53 @@
+@@ -828,13 +1238,53 @@
      @Override
      public void a(PacketPlayInBlockPlace packetplayinblockplace) {
          PlayerConnectionUtils.ensureMainThread(packetplayinblockplace, this, this.player.getWorldServer());
@@ -740,7 +740,7 @@
          }
      }
  
-@@ -845,7 +1295,7 @@
+@@ -849,7 +1299,7 @@
                  Entity entity = packetplayinspectate.a(worldserver);
  
                  if (entity != null) {
@@ -749,7 +749,7 @@
                      return;
                  }
              }
-@@ -854,7 +1304,12 @@
+@@ -858,7 +1308,12 @@
      }
  
      @Override
@@ -763,7 +763,7 @@
  
      @Override
      public void a(PacketPlayInBoatMove packetplayinboatmove) {
-@@ -869,11 +1324,26 @@
+@@ -873,11 +1328,26 @@
  
      @Override
      public void a(IChatBaseComponent ichatbasecomponent) {
@@ -778,7 +778,7 @@
 +        // CraftBukkit start - Replace vanilla quit message handling with our own.
 +        /*
          this.minecraftServer.invalidatePingSample();
-         this.minecraftServer.getPlayerList().sendMessage((new ChatMessage("multiplayer.player.left", new Object[] { this.player.getScoreboardDisplayName()})).a(EnumChatFormat.YELLOW));
+         this.minecraftServer.getPlayerList().sendMessage((new ChatMessage("multiplayer.player.left", new Object[]{this.player.getScoreboardDisplayName()})).a(EnumChatFormat.YELLOW));
 +        */
 +
          this.player.n();
@@ -791,7 +791,7 @@
          if (this.isExemptPlayer()) {
              PlayerConnection.LOGGER.info("Stopping singleplayer server as player logged out");
              this.minecraftServer.safeShutdown(false);
-@@ -899,6 +1369,15 @@
+@@ -903,6 +1373,15 @@
              }
          }
  
@@ -807,7 +807,7 @@
          try {
              this.networkManager.sendPacket(packet, genericfuturelistener);
          } catch (Throwable throwable) {
-@@ -915,18 +1394,38 @@
+@@ -919,18 +1398,38 @@
      @Override
      public void a(PacketPlayInHeldItemSlot packetplayinhelditemslot) {
          PlayerConnectionUtils.ensureMainThread(packetplayinhelditemslot, this, this.player.getWorldServer());
@@ -848,7 +848,7 @@
              this.sendPacket(new PacketPlayOutChat((new ChatMessage("chat.cannotSend", new Object[0])).a(EnumChatFormat.RED)));
          } else {
              this.player.resetIdleTimer();
-@@ -936,41 +1435,257 @@
+@@ -940,41 +1439,257 @@
  
              for (int i = 0; i < s.length(); ++i) {
                  if (!SharedConstants.isAllowedChatCharacter(s.charAt(i))) {
@@ -909,7 +909,7 @@
 +                this.chat(s, true);
 +                // CraftBukkit end - the below is for reference. :)
              } else {
-                 ChatMessage chatmessage = new ChatMessage("chat.type.text", new Object[] { this.player.getScoreboardDisplayName(), s});
+                 ChatMessage chatmessage = new ChatMessage("chat.type.text", new Object[]{this.player.getScoreboardDisplayName(), s});
  
                  this.minecraftServer.getPlayerList().sendMessage(chatmessage, false);
              }
@@ -1113,7 +1113,7 @@
          this.player.resetIdleTimer();
          IJumpable ijumpable;
  
-@@ -1034,6 +1749,7 @@
+@@ -1038,6 +1753,7 @@
      @Override
      public void a(PacketPlayInUseEntity packetplayinuseentity) {
          PlayerConnectionUtils.ensureMainThread(packetplayinuseentity, this, this.player.getWorldServer());
@@ -1121,7 +1121,7 @@
          WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
          Entity entity = packetplayinuseentity.a((World) worldserver);
  
-@@ -1049,20 +1765,74 @@
+@@ -1053,20 +1769,74 @@
              if (this.player.h(entity) < d0) {
                  EnumHand enumhand;
  
@@ -1197,7 +1197,7 @@
                  }
              }
          }
-@@ -1102,15 +1872,21 @@
+@@ -1106,15 +1876,21 @@
      @Override
      public void a(PacketPlayInCloseWindow packetplayinclosewindow) {
          PlayerConnectionUtils.ensureMainThread(packetplayinclosewindow, this, this.player.getWorldServer());
@@ -1221,7 +1221,7 @@
                  NonNullList<ItemStack> nonnulllist = NonNullList.a();
  
                  for (int i = 0; i < this.player.activeContainer.slots.size(); ++i) {
-@@ -1119,8 +1895,274 @@
+@@ -1123,8 +1899,274 @@
  
                  this.player.a(this.player.activeContainer, nonnulllist);
              } else {
@@ -1230,10 +1230,10 @@
 +                if (packetplayinwindowclick.c() < -1 && packetplayinwindowclick.c() != -999) {
 +                    return;
 +                }
- 
++
 +                InventoryView inventory = this.player.activeContainer.getBukkitView();
 +                SlotType type = inventory.getSlotType(packetplayinwindowclick.c());
-+
+ 
 +                InventoryClickEvent event;
 +                ClickType click = ClickType.UNKNOWN;
 +                InventoryAction action = InventoryAction.UNKNOWN;
@@ -1497,7 +1497,7 @@
                  if (ItemStack.matches(packetplayinwindowclick.f(), itemstack)) {
                      this.player.playerConnection.sendPacket(new PacketPlayOutTransaction(packetplayinwindowclick.b(), packetplayinwindowclick.e(), true));
                      this.player.e = true;
-@@ -1160,6 +2202,7 @@
+@@ -1164,6 +2206,7 @@
      @Override
      public void a(PacketPlayInEnchantItem packetplayinenchantitem) {
          PlayerConnectionUtils.ensureMainThread(packetplayinenchantitem, this, this.player.getWorldServer());
@@ -1505,7 +1505,7 @@
          this.player.resetIdleTimer();
          if (this.player.activeContainer.windowId == packetplayinenchantitem.b() && this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
              this.player.activeContainer.a((EntityHuman) this.player, packetplayinenchantitem.c());
-@@ -1192,6 +2235,43 @@
+@@ -1196,6 +2239,43 @@
  
              boolean flag1 = packetplayinsetcreativeslot.b() >= 1 && packetplayinsetcreativeslot.b() <= 45;
              boolean flag2 = itemstack.isEmpty() || itemstack.getDamage() >= 0 && itemstack.getCount() <= 64 && !itemstack.isEmpty();
@@ -1549,7 +1549,7 @@
  
              if (flag1 && flag2) {
                  if (itemstack.isEmpty()) {
-@@ -1217,6 +2297,7 @@
+@@ -1221,6 +2301,7 @@
      @Override
      public void a(PacketPlayInTransaction packetplayintransaction) {
          PlayerConnectionUtils.ensureMainThread(packetplayintransaction, this, this.player.getWorldServer());
@@ -1557,7 +1557,7 @@
          int i = this.player.activeContainer.windowId;
  
          if (i == packetplayintransaction.b() && this.k.getOrDefault(i, (short) (packetplayintransaction.c() + 1)) == packetplayintransaction.c() && !this.player.activeContainer.c(this.player) && !this.player.isSpectator()) {
-@@ -1228,6 +2309,7 @@
+@@ -1232,6 +2313,7 @@
      @Override
      public void a(PacketPlayInUpdateSign packetplayinupdatesign) {
          PlayerConnectionUtils.ensureMainThread(packetplayinupdatesign, this, this.player.getWorldServer());
@@ -1565,9 +1565,9 @@
          this.player.resetIdleTimer();
          WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
          BlockPosition blockposition = packetplayinupdatesign.b();
-@@ -1244,14 +2326,30 @@
+@@ -1248,14 +2330,30 @@
  
-             if (!tileentitysign.c() || tileentitysign.d() != this.player) {
+             if (!tileentitysign.d() || tileentitysign.f() != this.player) {
                  this.minecraftServer.warning("Player " + this.player.getDisplayName().getString() + " just tried to change non-editable sign");
 +                this.sendPacket(tileentity.getUpdatePacket()); // CraftBukkit
                  return;
@@ -1597,7 +1597,7 @@
  
              tileentitysign.update();
              worldserver.notify(blockposition, iblockdata, iblockdata, 3);
-@@ -1261,6 +2359,7 @@
+@@ -1265,6 +2363,7 @@
  
      @Override
      public void a(PacketPlayInKeepAlive packetplayinkeepalive) {
@@ -1605,7 +1605,7 @@
          if (this.awaitingKeepAlive && packetplayinkeepalive.b() == this.h) {
              int i = (int) (SystemUtils.getMonotonicMillis() - this.lastKeepAlive);
  
-@@ -1275,7 +2374,17 @@
+@@ -1279,7 +2378,17 @@
      @Override
      public void a(PacketPlayInAbilities packetplayinabilities) {
          PlayerConnectionUtils.ensureMainThread(packetplayinabilities, this, this.player.getWorldServer());
@@ -1624,7 +1624,7 @@
      }
  
      @Override
-@@ -1284,8 +2393,50 @@
+@@ -1288,8 +2397,50 @@
          this.player.a(packetplayinsettings);
      }
  
diff --git a/nms-patches/PlayerInteractManager.patch b/nms-patches/PlayerInteractManager.patch
index bd75f83fe1..321f074add 100644
--- a/nms-patches/PlayerInteractManager.patch
+++ b/nms-patches/PlayerInteractManager.patch
@@ -20,8 +20,8 @@
          this.gamemode = enumgamemode;
          enumgamemode.a(this.player.abilities);
          this.player.updateAbilities();
--        this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[] { this.player}));
-+        this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[] { this.player}), this.player); // CraftBukkit
+-        this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[]{this.player}));
++        this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[]{this.player}), this.player); // CraftBukkit
          this.world.everyoneSleeping();
      }
  
diff --git a/nms-patches/PlayerList.patch b/nms-patches/PlayerList.patch
index a460223475..45e9683684 100644
--- a/nms-patches/PlayerList.patch
+++ b/nms-patches/PlayerList.patch
@@ -108,7 +108,7 @@
          playerconnection.sendPacket(new PacketPlayOutAbilities(entityplayer.abilities));
 @@ -100,19 +142,61 @@
          } else {
-             chatmessage = new ChatMessage("multiplayer.player.joined.renamed", new Object[] { entityplayer.getScoreboardDisplayName(), s});
+             chatmessage = new ChatMessage("multiplayer.player.joined.renamed", new Object[]{entityplayer.getScoreboardDisplayName(), s});
          }
 +        // CraftBukkit start
 +        chatmessage.a(EnumChatFormat.YELLOW);
@@ -118,8 +118,8 @@
          playerconnection.a(entityplayer.locX, entityplayer.locY, entityplayer.locZ, entityplayer.yaw, entityplayer.pitch);
          this.players.add(entityplayer);
          this.j.put(entityplayer.getUniqueID(), entityplayer);
--        this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { entityplayer}));
-+        // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { entityplayer})); // CraftBukkit - replaced with loop below
+-        this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer}));
++        // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
 +
 +        // CraftBukkit start
 +        PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(cserver.getPlayer(entityplayer), joinMessage);
@@ -142,7 +142,7 @@
 +        PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, entityplayer);
  
          for (int i = 0; i < this.players.size(); ++i) {
--            entityplayer.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[] { (EntityPlayer) this.players.get(i)}));
+-            entityplayer.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{(EntityPlayer) this.players.get(i)}));
 +            EntityPlayer entityplayer1 = (EntityPlayer) this.players.get(i);
 +
 +            if (entityplayer1.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) {
@@ -287,9 +287,9 @@
 +            // CraftBukkit end
          }
  
--        this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[] { entityplayer}));
+-        this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
 +        // CraftBukkit start
-+        //  this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[] { entityplayer}));
++        //  this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
 +        PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entityplayer);
 +        for (int i = 0; i < players.size(); i++) {
 +            EntityPlayer entityplayer2 = (EntityPlayer) this.players.get(i);
@@ -347,9 +347,9 @@
 +        if (getProfileBans().isBanned(gameprofile) && !getProfileBans().get(gameprofile).hasExpired()) {
              GameProfileBanEntry gameprofilebanentry = (GameProfileBanEntry) this.k.get(gameprofile);
  
-             chatmessage = new ChatMessage("multiplayer.disconnect.banned.reason", new Object[] { gameprofilebanentry.getReason()});
+             chatmessage = new ChatMessage("multiplayer.disconnect.banned.reason", new Object[]{gameprofilebanentry.getReason()});
 @@ -317,10 +467,12 @@
-                 chatmessage.addSibling(new ChatMessage("multiplayer.disconnect.banned.expiration", new Object[] { PlayerList.g.format(gameprofilebanentry.getExpires())}));
+                 chatmessage.addSibling(new ChatMessage("multiplayer.disconnect.banned.expiration", new Object[]{PlayerList.g.format(gameprofilebanentry.getExpires())}));
              }
  
 -            return chatmessage;
@@ -363,9 +363,9 @@
 +        } else if (getIPBans().isBanned(socketaddress) && !getIPBans().get(socketaddress).hasExpired()) {
              IpBanEntry ipbanentry = this.l.get(socketaddress);
  
-             chatmessage = new ChatMessage("multiplayer.disconnect.banned_ip.reason", new Object[] { ipbanentry.getReason()});
+             chatmessage = new ChatMessage("multiplayer.disconnect.banned_ip.reason", new Object[]{ipbanentry.getReason()});
 @@ -328,13 +480,25 @@
-                 chatmessage.addSibling(new ChatMessage("multiplayer.disconnect.banned_ip.expiration", new Object[] { PlayerList.g.format(ipbanentry.getExpires())}));
+                 chatmessage.addSibling(new ChatMessage("multiplayer.disconnect.banned_ip.expiration", new Object[]{PlayerList.g.format(ipbanentry.getExpires())}));
              }
  
 -            return chatmessage;
diff --git a/nms-patches/TickListServer.patch b/nms-patches/TickListServer.patch
index 7658dc2449..5571924416 100644
--- a/nms-patches/TickListServer.patch
+++ b/nms-patches/TickListServer.patch
@@ -1,7 +1,7 @@
 --- a/net/minecraft/server/TickListServer.java
 +++ b/net/minecraft/server/TickListServer.java
-@@ -37,11 +37,17 @@
-         this.b();
+@@ -39,11 +39,17 @@
+     public void a() {
          int i = this.nextTickList.size();
  
 -        if (i != this.nextTickListHash.size()) {
@@ -19,4 +19,13 @@
 +                // CraftBukkit end
              }
  
-             this.h.getMethodProfiler().enter("selecting");
+             ChunkProviderServer chunkproviderserver = this.f.getChunkProvider();
+@@ -82,7 +88,7 @@
+                         throw new ReportedException(crashreport);
+                     }
+                 } else {
+-                    this.a(nextticklistentry.a, nextticklistentry.b(), 0);
++                    this.a(nextticklistentry.a, (T) nextticklistentry.b(), 0); // CraftBukkit - decompile error
+                 }
+             }
+ 
diff --git a/nms-patches/TicketType.patch b/nms-patches/TicketType.patch
index af9e80dca7..e1d53f13a3 100644
--- a/nms-patches/TicketType.patch
+++ b/nms-patches/TicketType.patch
@@ -1,10 +1,10 @@
 --- a/net/minecraft/server/TicketType.java
 +++ b/net/minecraft/server/TicketType.java
-@@ -17,6 +17,7 @@
-     public static final TicketType<ChunkCoordIntPair> LIGHT = a("light", Comparator.comparingLong(ChunkCoordIntPair::pair));
+@@ -19,6 +19,7 @@
      public static final TicketType<BlockPosition2D> PORTAL = a("portal", Comparator.comparingLong(BlockPosition2D::b));
-     public static final TicketType<ChunkCoordIntPair> UNKNOWN = a("unknown", Comparator.comparingLong(ChunkCoordIntPair::pair));
+     public static final TicketType<Integer> POST_TELEPORT = a("post_teleport", Integer::compareTo, 5);
+     public static final TicketType<ChunkCoordIntPair> UNKNOWN = a("unknown", Comparator.comparingLong(ChunkCoordIntPair::pair), 1);
 +    public static final TicketType<Unit> PLUGIN = a("plugin", (a, b) -> 0); // CraftBukkit
  
      public static <T> TicketType<T> a(String s, Comparator<T> comparator) {
-         return new TicketType<>(s, comparator);
+         return new TicketType<>(s, comparator, 0L);
diff --git a/nms-patches/TileEntityBeacon.patch b/nms-patches/TileEntityBeacon.patch
index 3e15884fe9..e8a3a10aa9 100644
--- a/nms-patches/TileEntityBeacon.patch
+++ b/nms-patches/TileEntityBeacon.patch
@@ -13,7 +13,7 @@
 +
  public class TileEntityBeacon extends TileEntity implements ITileInventory, ITickable {
  
-     public static final MobEffectList[][] a = new MobEffectList[][] { { MobEffects.FASTER_MOVEMENT, MobEffects.FASTER_DIG}, { MobEffects.RESISTANCE, MobEffects.JUMP}, { MobEffects.INCREASE_DAMAGE}, { MobEffects.REGENERATION}};
+     public static final MobEffectList[][] a = new MobEffectList[][]{{MobEffects.FASTER_MOVEMENT, MobEffects.FASTER_DIG}, {MobEffects.RESISTANCE, MobEffects.JUMP}, {MobEffects.INCREASE_DAMAGE}, {MobEffects.REGENERATION}};
 @@ -24,6 +31,15 @@
      public IChatBaseComponent customName;
      public ChestLock chestLock;
@@ -30,8 +30,8 @@
  
      public TileEntityBeacon() {
          super(TileEntityTypes.BEACON);
-@@ -187,39 +203,78 @@
- 
+@@ -192,39 +208,78 @@
+         super.W_();
      }
  
 -    private void applyEffects() {
@@ -119,7 +119,7 @@
      public void a(SoundEffect soundeffect) {
          this.world.a((EntityHuman) null, this.position, soundeffect, SoundCategory.BLOCKS, 1.0F, 1.0F);
      }
-@@ -249,8 +304,10 @@
+@@ -254,8 +309,10 @@
      @Override
      public void load(NBTTagCompound nbttagcompound) {
          super.load(nbttagcompound);
diff --git a/nms-patches/TileEntityBrewingStand.patch b/nms-patches/TileEntityBrewingStand.patch
index 6057a17131..953bb5f12a 100644
--- a/nms-patches/TileEntityBrewingStand.patch
+++ b/nms-patches/TileEntityBrewingStand.patch
@@ -16,7 +16,7 @@
 +
  public class TileEntityBrewingStand extends TileEntityContainer implements IWorldInventory, ITickable {
  
-     private static final int[] b = new int[] { 3};
+     private static final int[] b = new int[]{3};
 @@ -15,6 +25,36 @@
      private Item k;
      public int fuelLevel;
@@ -92,10 +92,10 @@
 +            // CraftBukkit end
  
              if (flag2 && flag) {
-                 this.t();
+                 this.s();
 @@ -168,6 +224,16 @@
  
-     private void t() {
+     private void s() {
          ItemStack itemstack = (ItemStack) this.items.get(3);
 +        // CraftBukkit start
 +        InventoryHolder owner = this.getOwner();
diff --git a/nms-patches/TileEntityEndGateway.patch b/nms-patches/TileEntityEndGateway.patch
index 0e5b35f5ad..0a00321ab0 100644
--- a/nms-patches/TileEntityEndGateway.patch
+++ b/nms-patches/TileEntityEndGateway.patch
@@ -37,6 +37,6 @@
 +                }
 +                // CraftBukkit end
 +
-                 entity.enderTeleportTo((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D);
+                 entity.enderTeleportAndLoad((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D);
              }
  
diff --git a/nms-patches/TileEntityLectern.patch b/nms-patches/TileEntityLectern.patch
index f101cf4848..598285846c 100644
--- a/nms-patches/TileEntityLectern.patch
+++ b/nms-patches/TileEntityLectern.patch
@@ -74,8 +74,8 @@
 +        // CraftBukkit start
 +        public void setItem(int i, ItemStack itemstack) {
 +            if (i == 0) {
-+                TileEntityLectern.this.a(itemstack); // PAIL rename setBook
-+                BlockLectern.a(TileEntityLectern.this.getWorld(), TileEntityLectern.this.getPosition(), TileEntityLectern.this.getBlock(), TileEntityLectern.this.f()); // PAIL rename a -> setHasBook, f -> hasBook
++                TileEntityLectern.this.setBook(itemstack);
++                BlockLectern.setHasBook(TileEntityLectern.this.getWorld(), TileEntityLectern.this.getPosition(), TileEntityLectern.this.getBlock(), TileEntityLectern.this.hasBook());
 +            }
 +        }
 +        // CraftBukkit end
diff --git a/nms-patches/TileEntitySign.patch b/nms-patches/TileEntitySign.patch
index 25789f53d2..49ebfd13e9 100644
--- a/nms-patches/TileEntitySign.patch
+++ b/nms-patches/TileEntitySign.patch
@@ -7,7 +7,7 @@
 -public class TileEntitySign extends TileEntity {
 +public class TileEntitySign extends TileEntity implements ICommandListener { // CraftBukkit - implements
  
-     public final IChatBaseComponent[] lines = new IChatBaseComponent[] { new ChatComponentText(""), new ChatComponentText(""), new ChatComponentText(""), new ChatComponentText("")};
+     public final IChatBaseComponent[] lines = new IChatBaseComponent[]{new ChatComponentText(""), new ChatComponentText(""), new ChatComponentText(""), new ChatComponentText("")};
      private int c = -1;
 @@ -29,6 +29,12 @@
              nbttagcompound.setString("Text" + (i + 1), s);
@@ -44,7 +44,7 @@
  
 -            if (this.world instanceof WorldServer) {
 -                try {
--                    this.lines[i] = ChatComponentUtils.filterForDisplay(this.a((EntityPlayer) null), ichatbasecomponent, (Entity) null);
+-                    this.lines[i] = ChatComponentUtils.filterForDisplay(this.a((EntityPlayer) null), ichatbasecomponent, (Entity) null, 0);
 -                } catch (CommandSyntaxException commandsyntaxexception) {
 +                if (oldSign) {
 +                    lines[i] = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(s)[0];
@@ -54,7 +54,7 @@
 +
 +                if (this.world instanceof WorldServer) {
 +                    try {
-+                        this.lines[i] = ChatComponentUtils.filterForDisplay(this.a((EntityPlayer) null), ichatbasecomponent, (Entity) null);
++                        this.lines[i] = ChatComponentUtils.filterForDisplay(this.a((EntityPlayer) null), ichatbasecomponent, (Entity) null, 0);
 +                    } catch (CommandSyntaxException commandsyntaxexception) {
 +                        this.lines[i] = ichatbasecomponent;
 +                    }
diff --git a/nms-patches/World.patch b/nms-patches/World.patch
index fdf2d66d07..e984db18f6 100644
--- a/nms-patches/World.patch
+++ b/nms-patches/World.patch
@@ -200,7 +200,7 @@
 +                this.m(blockposition);
 +            }
 +
-+            if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getState() != null && chunk.getState().a(PlayerChunk.State.TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
++            if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getState() != null && chunk.getState().isAtLeast(PlayerChunk.State.TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
 +                this.notify(blockposition, iblockdata1, iblockdata, i);
 +            }
 +
diff --git a/pom.xml b/pom.xml
index f3207c403d..f7819b635c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
     <groupId>org.bukkit</groupId>
     <artifactId>craftbukkit</artifactId>
     <packaging>jar</packaging>
-    <version>1.14.1-R0.1-SNAPSHOT</version>
+    <version>1.14.2-R0.1-SNAPSHOT</version>
     <name>CraftBukkit</name>
     <url>https://www.spigotmc.org/</url>
 
@@ -12,7 +12,7 @@
         <skipTests>true</skipTests>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <api.version>unknown</api.version>
-        <minecraft.version>1.14.1</minecraft.version>
+        <minecraft.version>1.14.2</minecraft.version>
         <minecraft_version>1_14_R1</minecraft_version>
         <buildtag.prefix>git-Bukkit-</buildtag.prefix>
         <buildtag.suffix></buildtag.suffix>
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
index 13f4ffaf5c..e736d3adca 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java
@@ -90,7 +90,7 @@ public class CraftLootTable implements org.bukkit.loot.LootTable {
             builder.set(LootContextParameters.DAMAGE_SOURCE, DamageSource.playerAttack(nmsKiller));
         }
 
-        return builder.build(getHandle().a());
+        return builder.build(getHandle().getLootContextParameterSet());
     }
 
     @Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/memory/CraftMemoryMapper.java b/src/main/java/org/bukkit/craftbukkit/entity/memory/CraftMemoryMapper.java
index 09a5961c68..d7a7951d53 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/memory/CraftMemoryMapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/memory/CraftMemoryMapper.java
@@ -30,13 +30,10 @@ public final class CraftMemoryMapper {
     }
 
     public static Location fromNms(GlobalPos globalPos) {
-        // PAIL: globalPos.a() -> getDimensionManager()
-        // PAIL: globalPos.b() -> getBlockPosition()
-        return new org.bukkit.Location(((CraftServer) Bukkit.getServer()).getServer().getWorldServer(globalPos.a()).getWorld(), globalPos.b().getX(), globalPos.b().getY(), globalPos.b().getZ());
+        return new org.bukkit.Location(((CraftServer) Bukkit.getServer()).getServer().getWorldServer(globalPos.getDimensionManager()).getWorld(), globalPos.getBlockPosition().getX(), globalPos.getBlockPosition().getY(), globalPos.getBlockPosition().getZ());
     }
 
     public static GlobalPos toNms(Location location) {
-        // PAIL: GlobalPos.a(DmensionManager, BlockPosition) -> create()
-        return GlobalPos.a(((CraftWorld) location.getWorld()).getHandle().getWorldProvider().getDimensionManager(), new BlockPosition(location.getX(), location.getY(), location.getZ()));
+        return GlobalPos.create(((CraftWorld) location.getWorld()).getHandle().getWorldProvider().getDimensionManager(), new BlockPosition(location.getX(), location.getY(), location.getZ()));
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
index 52d832f805..b9c99f2d1f 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
@@ -7,6 +7,8 @@ import net.minecraft.server.IMerchant;
 import net.minecraft.server.ItemStack;
 import net.minecraft.server.MerchantRecipe;
 import net.minecraft.server.MerchantRecipeList;
+import net.minecraft.server.SoundEffect;
+import net.minecraft.server.SoundEffects;
 import net.minecraft.server.World;
 import org.apache.commons.lang.Validate;
 
@@ -95,5 +97,10 @@ public class CraftMerchantCustom extends CraftMerchant {
         public boolean ea() {
             return true;
         }
+
+        @Override
+        public SoundEffect eb() {
+            return SoundEffects.ENTITY_VILLAGER_YES;
+        }
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index bed9719216..7fa66d338f 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -186,7 +186,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
      * @return string
      */
     public String getMappingsVersion() {
-        return "48be70f51ffe914d865f175ed3bf992d";
+        return "28fc84e92753a1f24483290e13e0ee4c";
     }
 
     @Override
diff --git a/src/test/java/org/bukkit/entity/memory/CraftMemoryKeyTest.java b/src/test/java/org/bukkit/entity/memory/CraftMemoryKeyTest.java
index 491d9a6258..f060c9beaf 100644
--- a/src/test/java/org/bukkit/entity/memory/CraftMemoryKeyTest.java
+++ b/src/test/java/org/bukkit/entity/memory/CraftMemoryKeyTest.java
@@ -56,7 +56,7 @@ public class CraftMemoryKeyTest extends AbstractTestingBase {
     @Test
     public void shouldReturnNullWhenBukkitRepresentationOfKeyisNotAvailableAndSerializerIsNotPresent() {
         for (MemoryModuleType<?> memoryModuleType : IRegistry.MEMORY_MODULE_TYPE) {
-            if (!memoryModuleType.a().isPresent()) { // PAIL: a() -> getSerializer()
+            if (!memoryModuleType.getSerializer().isPresent()) {
                 MemoryKey bukkitNoKey = CraftMemoryKey.toMemoryKey(memoryModuleType);
                 Assert.assertNull("MemoryModuleType should be null", bukkitNoKey);
             }
@@ -66,7 +66,7 @@ public class CraftMemoryKeyTest extends AbstractTestingBase {
     @Test
     public void shouldReturnAnInstanceOfMemoryKeyWhenBukkitRepresentationOfKeyisAvailableAndSerializerIsPresent() {
         for (MemoryModuleType<?> memoryModuleType : IRegistry.MEMORY_MODULE_TYPE) {
-            if (memoryModuleType.a().isPresent()) { // PAIL: a() -> getSerializer()
+            if (memoryModuleType.getSerializer().isPresent()) {
                 MemoryKey bukkitNoKey = CraftMemoryKey.toMemoryKey(memoryModuleType);
                 Assert.assertNotNull("MemoryModuleType should not be null", bukkitNoKey);
             }