From 1863ac217f94f910d83624db067b5e513dbd90dd Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 23 Feb 2024 14:37:33 +0100 Subject: [PATCH] Updated Upstream (Bukkit/CraftBukkit/Spigot) (#10277) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 9a80d38c SPIGOT-336, SPIGOT-3366, SPIGOT-5768, SPIGOT-6409, SPIGOT-6861, PR-722: Add EntityRemoveEvent 258086d9 SPIGOT-7417, PR-967: Add Sign#getTargetSide and Sign#getAllowedEditor ffaba051 SPIGOT-7584: Add missing Tag.ITEMS_NON_FLAMMABLE_WOOD CraftBukkit Changes: 98b6c1ac7 SPIGOT-7589 Fix NullPointerException when bans expire a2736ddb0 SPIGOT-336, SPIGOT-3366, SPIGOT-5768, SPIGOT-6409, SPIGOT-6861, PR-1008: Add EntityRemoveEvent 5bf12cb89 SPIGOT-7565: Throw a more descriptive error message when a developer tries to spawn an entity from a CraftBukkit class 76d95fe7e SPIGOT-7417, PR-1343: Add Sign#getTargetSide and Sign#getAllowedEditor Spigot Changes: e9ec5485 Rebuild patches f1b62e0c Rebuild patches --- .../api/Add-Sign-getInteractableSideFor.patch | 5 +-- patches/api/Added-missing-vanilla-tags.patch | 23 ---------- patches/api/Adventure.patch | 2 +- ...Entity-AddTo-RemoveFrom-World-Events.patch | 29 ++++++++++++ .../Ability-to-apply-mending-to-XP-API.patch | 2 +- .../Add-API-for-item-entity-health.patch | 2 +- .../Add-PlayerUseUnknownEntityEvent.patch | 5 +-- ...onfigurable-entity-despawn-distances.patch | 2 +- .../server/Add-drops-to-shear-events.patch | 2 +- .../Add-exception-reporting-event.patch | 2 +- patches/server/Adventure.patch | 4 +- ...urable-Non-Player-Arrow-Despawn-Rate.patch | 2 +- ...ck-and-tnt-entities-at-the-specified.patch | 6 +-- .../Duplicate-UUID-Resolve-Option.patch | 6 +-- patches/server/EnderDragon-Events.patch | 10 ++--- .../server/EntityPickupItemEvent-fixes.patch | 2 +- .../server/Expand-LingeringPotion-API.patch | 2 +- .../server/Expand-PlayerItemMendEvent.patch | 2 +- ...PI-for-Reason-Source-Triggering-play.patch | 2 +- ...-entity-death-event-for-ender-dragon.patch | 2 +- .../server/Fix-a-bunch-of-vanilla-bugs.patch | 4 +- .../server/Fix-potions-splash-events.patch | 4 +- patches/server/Fix-sand-duping.patch | 2 +- .../server/Fix-villager-boat-exploit.patch | 2 +- ...and-additions-to-the-SpawnReason-API.patch | 10 ++--- ...Folia-scheduler-and-owned-region-API.patch | 12 ++--- patches/server/Improve-death-events.patch | 4 +- .../server/Improve-tag-parser-handling.patch | 45 +++++++++++++++++++ ...-maximum-exp-value-when-merging-orbs.patch | 2 +- .../server/Player-affects-spawning-API.patch | 2 +- .../server/PlayerAttemptPickupItemEvent.patch | 4 +- ...PlayerPickupItemEvent-setFlyAtPlayer.patch | 2 +- ...vent-block-entity-and-entity-crashes.patch | 2 +- patches/server/Rewrite-chunk-system.patch | 17 +++---- patches/server/Setup-Gradle-project.patch | 7 +++ patches/server/Test-changes.patch | 2 +- .../Toggle-for-removing-existing-dragon.patch | 2 +- work/Bukkit | 2 +- work/CraftBukkit | 2 +- work/Spigot | 2 +- 40 files changed, 150 insertions(+), 91 deletions(-) delete mode 100644 patches/api/Added-missing-vanilla-tags.patch diff --git a/patches/api/Add-Sign-getInteractableSideFor.patch b/patches/api/Add-Sign-getInteractableSideFor.patch index 12c6fd314..bf9fd5e4d 100644 --- a/patches/api/Add-Sign-getInteractableSideFor.patch +++ b/patches/api/Add-Sign-getInteractableSideFor.patch @@ -10,9 +10,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/org/bukkit/block/Sign.java @@ -0,0 +0,0 @@ public interface Sign extends TileState, Colorable { */ - @NotNull - public SignSide getSide(@NotNull Side side); -+ + @Nullable + public Player getAllowedEditor(); + // Paper start - get side for player + /** + * Compute the side facing the specified entity. diff --git a/patches/api/Added-missing-vanilla-tags.patch b/patches/api/Added-missing-vanilla-tags.patch deleted file mode 100644 index 9431f5197..000000000 --- a/patches/api/Added-missing-vanilla-tags.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 20:03:40 -0800 -Subject: [PATCH] Added missing vanilla tags - - -diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/Tag.java -+++ b/src/main/java/org/bukkit/Tag.java -@@ -0,0 +0,0 @@ public interface Tag extends Keyed { - * Vanilla item tag representing all chest boat items. - */ - Tag ITEMS_CHEST_BOATS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("chest_boats"), Material.class); -+ // Paper start -+ /** -+ * Vanilla item tag representing all non-flammable wood items. -+ */ -+ Tag ITEMS_NON_FLAMMABLE_WOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("non_flammable_wood"), Material.class); -+ // Paper end - /** - * Vanilla item tag representing all fish items. - */ diff --git a/patches/api/Adventure.patch b/patches/api/Adventure.patch index 670a4a027..56c19c2a8 100644 --- a/patches/api/Adventure.patch +++ b/patches/api/Adventure.patch @@ -1598,7 +1598,7 @@ diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/block/Sign.java +++ b/src/main/java/org/bukkit/block/Sign.java -@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable; * Represents a captured state of either a SignPost or a WallSign. */ public interface Sign extends TileState, Colorable { diff --git a/patches/api/Entity-AddTo-RemoveFrom-World-Events.patch b/patches/api/Entity-AddTo-RemoveFrom-World-Events.patch index b8d176441..4b61acb2f 100644 --- a/patches/api/Entity-AddTo-RemoveFrom-World-Events.patch +++ b/patches/api/Entity-AddTo-RemoveFrom-World-Events.patch @@ -104,3 +104,32 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return HANDLER_LIST; + } +} +diff --git a/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java b/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityRemoveEvent.java +@@ -0,0 +0,0 @@ + package org.bukkit.event.entity; + ++import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; + import org.bukkit.entity.Entity; + import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.ApiStatus; +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; + * This event should only be used for monitoring. The result + * of modifying the entity during or after this event is unspecified. + * This event is not called for a {@link org.bukkit.entity.Player}. ++ * @deprecated use {@link EntityRemoveFromWorldEvent} instead + */ +-@ApiStatus.Experimental ++@Deprecated(forRemoval = true) + public class EntityRemoveEvent extends EntityEvent { + + private static final HandlerList handlers = new HandlerList(); +@@ -0,0 +0,0 @@ public class EntityRemoveEvent extends EntityEvent { + * When the chunk an entity is in gets unloaded. + */ + UNLOAD, ++ DISCARD + } + } diff --git a/patches/server/Ability-to-apply-mending-to-XP-API.patch b/patches/server/Ability-to-apply-mending-to-XP-API.patch index 3d55295d2..37a9248a1 100644 --- a/patches/server/Ability-to-apply-mending-to-XP-API.patch +++ b/patches/server/Ability-to-apply-mending-to-XP-API.patch @@ -38,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + int i = Math.min(orb.xpToDurability(amount), itemstack.getDamageValue()); + org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.getKey(), i); + i = event.getRepairAmount(); -+ orb.discard(); ++ orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); + if (!event.isCancelled()) { + amount -= orb.durabilityToXp(i); + itemstack.setDamageValue(itemstack.getDamageValue() - i); diff --git a/patches/server/Add-API-for-item-entity-health.patch b/patches/server/Add-API-for-item-entity-health.patch index a7f459fcf..8ebe6a359 100644 --- a/patches/server/Add-API-for-item-entity-health.patch +++ b/patches/server/Add-API-for-item-entity-health.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void setHealth(int health) { + if (health <= 0) { + this.getHandle().getItem().onDestroyed(this.getHandle()); -+ this.getHandle().discard(); ++ this.getHandle().discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PLUGIN); + } else { + this.getHandle().health = health; + } diff --git a/patches/server/Add-PlayerUseUnknownEntityEvent.patch b/patches/server/Add-PlayerUseUnknownEntityEvent.patch index 9f076a43c..1e8af013c 100644 --- a/patches/server/Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/server/Add-PlayerUseUnknownEntityEvent.patch @@ -63,10 +63,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -0,0 +0,0 @@ public class CraftEventFactory { - Bukkit.getPluginManager().callEvent(event); - return event; + + Bukkit.getPluginManager().callEvent(new EntityRemoveEvent(entity.getBukkitEntity(), cause)); } -+ + // Paper start - PlayerUseUnknownEntityEvent + public static void callPlayerUseUnknownEntityEvent(net.minecraft.world.entity.player.Player player, net.minecraft.network.protocol.game.ServerboundInteractPacket packet, InteractionHand hand, @Nullable net.minecraft.world.phys.Vec3 vector) { + new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent( diff --git a/patches/server/Add-configurable-entity-despawn-distances.patch b/patches/server/Add-configurable-entity-despawn-distances.patch index ad508a570..e9bd8df5e 100644 --- a/patches/server/Add-configurable-entity-despawn-distances.patch +++ b/patches/server/Add-configurable-entity-despawn-distances.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int j = i * i; if (d0 > (double) j && this.removeWhenFarAway(d0)) { - this.discard(); + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } - int k = this.getType().getCategory().getNoDespawnDistance(); diff --git a/patches/server/Add-drops-to-shear-events.patch b/patches/server/Add-drops-to-shear-events.patch index fdcea1765..6fc6a6c45 100644 --- a/patches/server/Add-drops-to-shear-events.patch +++ b/patches/server/Add-drops-to-shear-events.patch @@ -93,7 +93,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!this.level().isClientSide()) { Cow entitycow = (Cow) EntityType.COW.create(this.level()); @@ -0,0 +0,0 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder= ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)) { // Spigot + if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - Configurable non-player arrow despawn rate; TODO: Extract this to init? - this.discard(); + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } diff --git a/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch b/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch index 56c1288b2..1e5cc9925 100644 --- a/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch +++ b/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch @@ -19,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.spawnAtLocation(block); + } + -+ this.discard(); ++ this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD); + return; + } + // Paper end - Configurable falling blocks height nerf @@ -36,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.move(MoverType.SELF, this.getDeltaMovement()); + // Paper start - Configurable TNT height nerf + if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) { -+ this.discard(); ++ this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD); + return; + } + // Paper end - Configurable TNT height nerf @@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.fuse > 0) { + // Paper start - Configurable TNT height nerf + if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) { -+ this.discard(); ++ this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD); + return; + } + // Paper end - Configurable TNT height nerf diff --git a/patches/server/Duplicate-UUID-Resolve-Option.patch b/patches/server/Duplicate-UUID-Resolve-Option.patch index d1136adc1..3d1e7352b 100644 --- a/patches/server/Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/Duplicate-UUID-Resolve-Option.patch @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - entity.discard(); + entity.discard(null); // CraftBukkit - add Bukkit remove cause needsRemoval = true; } + checkDupeUUID(world, entity); // Paper - duplicate uuid resolving @@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + && Objects.equals(other.getEncodeId(), entity.getEncodeId()) + && entity.getBukkitEntity().getLocation().distance(other.getBukkitEntity().getLocation()) < level.paperConfig().entities.spawning.duplicateUuid.safeRegenDeleteRange + ) { -+ entity.discard(); ++ entity.discard(null); + return true; + } + if (!other.isRemoved()) { @@ -77,7 +77,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + break; + } + case DELETE: { -+ entity.discard(); ++ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + return true; + } + default: diff --git a/patches/server/EnderDragon-Events.patch b/patches/server/EnderDragon-Events.patch index 489b85c18..42fbf03a5 100644 --- a/patches/server/EnderDragon-Events.patch +++ b/patches/server/EnderDragon-Events.patch @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 dragonFireball.moveTo(o, p, q, 0.0F, 0.0F); + if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) // Paper - EnderDragon Events this.dragon.level().addFreshEntity(dragonFireball); -+ else dragonFireball.discard(); // Paper - EnderDragon Events ++ else dragonFireball.discard(null); // Paper - EnderDragon Events this.fireballCharge = 0; if (this.currentPath != null) { while(!this.currentPath.isDone()) { @@ -44,10 +44,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) areaEffectCloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events ++ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) entityareaeffectcloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events this.level().levelEvent(2006, this.blockPosition(), this.isSilent() ? -1 : 1); - this.level().addFreshEntity(areaEffectCloud); -+ } else areaEffectCloud.discard(); // Paper - EnderDragon Events - this.discard(); + this.level().addFreshEntity(entityareaeffectcloud); ++ } else entityareaeffectcloud.discard(null); // Paper - EnderDragon Events + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } diff --git a/patches/server/EntityPickupItemEvent-fixes.patch b/patches/server/EntityPickupItemEvent-fixes.patch index 582b58e1c..835745279 100644 --- a/patches/server/EntityPickupItemEvent-fixes.patch +++ b/patches/server/EntityPickupItemEvent-fixes.patch @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - EntityPickupItemEvent fixes piglin.take(drop, drop.getItem().getCount()); itemstack = drop.getItem(); - drop.discard(); + drop.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, drop, drop.getItem().getCount() - 1, false).isCancelled()) { + piglin.onItemPickup(drop); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification piglin.take(drop, 1); diff --git a/patches/server/Expand-LingeringPotion-API.patch b/patches/server/Expand-LingeringPotion-API.patch index 575da86bd..60895d996 100644 --- a/patches/server/Expand-LingeringPotion-API.patch +++ b/patches/server/Expand-LingeringPotion-API.patch @@ -16,4 +16,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && entityareaeffectcloud.effects.isEmpty() && entityareaeffectcloud.getPotion().getEffects().isEmpty())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling this.level().addFreshEntity(entityareaeffectcloud); } else { - entityareaeffectcloud.discard(); + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause diff --git a/patches/server/Expand-PlayerItemMendEvent.patch b/patches/server/Expand-PlayerItemMendEvent.patch index ae1c525eb..775dd2275 100644 --- a/patches/server/Expand-PlayerItemMendEvent.patch +++ b/patches/server/Expand-PlayerItemMendEvent.patch @@ -43,7 +43,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.getKey(), i); + org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.getKey(), i, orb::durabilityToXp); // Paper - Expand PlayerItemMendEvent i = event.getRepairAmount(); - orb.discard(); + orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); if (!event.isCancelled()) { - amount -= orb.durabilityToXp(i); + amount -= event.getDurabilityToXpOperation().applyAsInt(i); // Paper - Expand PlayerItemMendEvent diff --git a/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch index 88bba4842..b8d5838c2 100644 --- a/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch +++ b/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch @@ -269,7 +269,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - ExperienceOrb.award((ServerLevel) this.level(), this.position(), i); + ExperienceOrb.award((ServerLevel) this.level(), this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper - this.discard(); + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java diff --git a/patches/server/Fire-entity-death-event-for-ender-dragon.patch b/patches/server/Fire-entity-death-event-for-ender-dragon.patch index 90c3ad407..852e793fd 100644 --- a/patches/server/Fire-entity-death-event-for-ender-dragon.patch +++ b/patches/server/Fire-entity-death-event-for-ender-dragon.patch @@ -21,6 +21,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - Fire entity death event + - this.remove(Entity.RemovalReason.KILLED); + this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause this.gameEvent(GameEvent.ENTITY_DIE); if (this.dragonFight != null) { diff --git a/patches/server/Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/Fix-a-bunch-of-vanilla-bugs.patch index f879fa02e..0babf43fa 100644 --- a/patches/server/Fix-a-bunch-of-vanilla-bugs.patch +++ b/patches/server/Fix-a-bunch-of-vanilla-bugs.patch @@ -180,11 +180,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Player player = entity.getBukkitEntity(); PlayerLoginEvent event = new PlayerLoginEvent(player, loginlistener.connection.hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.channel.remoteAddress()).getAddress()); -- if (this.getBans().isBanned(gameprofile) && !this.getBans().get(gameprofile).hasExpired()) { +- if (this.bans.isBanned(gameprofile)) { - UserBanListEntry gameprofilebanentry = (UserBanListEntry) this.bans.get(gameprofile); + // Paper start - Fix MC-158900 + UserBanListEntry gameprofilebanentry; -+ if (getBans().isBanned(gameprofile) && (gameprofilebanentry = getBans().get(gameprofile)) != null) { ++ if (this.bans.isBanned(gameprofile) && (gameprofilebanentry = this.bans.get(gameprofile)) != null) { + // Paper end - Fix MC-158900 ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); diff --git a/patches/server/Fix-potions-splash-events.patch b/patches/server/Fix-potions-splash-events.patch index 5249eb34b..51b6728d5 100644 --- a/patches/server/Fix-potions-splash-events.patch +++ b/patches/server/Fix-potions-splash-events.patch @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.level().levelEvent(i, this.blockPosition(), PotionUtils.getColor(itemstack)); + } // Paper - Fix potions splash events - this.discard(); + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } @@ -146,7 +146,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (noEffects && entityareaeffectcloud.effects.isEmpty() && entityareaeffectcloud.getPotion().getEffects().isEmpty()))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling this.level().addFreshEntity(entityareaeffectcloud); } else { - entityareaeffectcloud.discard(); + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause } // CraftBukkit end + return !event.isCancelled(); // Paper - Fix potions splash events diff --git a/patches/server/Fix-sand-duping.patch b/patches/server/Fix-sand-duping.patch index 94491dcf4..c91250421 100644 --- a/patches/server/Fix-sand-duping.patch +++ b/patches/server/Fix-sand-duping.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - fix sand duping if (this.blockState.isAir()) { - this.discard(); + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else { @@ -0,0 +0,0 @@ public class FallingBlockEntity extends Entity { } diff --git a/patches/server/Fix-villager-boat-exploit.patch b/patches/server/Fix-villager-boat-exploit.patch index 7029eb21a..948e84af6 100644 --- a/patches/server/Fix-villager-boat-exploit.patch +++ b/patches/server/Fix-villager-boat-exploit.patch @@ -20,6 +20,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + // Paper end - Fix villager boat exploit - entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER); + entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause }); } diff --git a/patches/server/Fixes-and-additions-to-the-SpawnReason-API.patch b/patches/server/Fixes-and-additions-to-the-SpawnReason-API.patch index 821ef5fce..c87efa95a 100644 --- a/patches/server/Fixes-and-additions-to-the-SpawnReason-API.patch +++ b/patches/server/Fixes-and-additions-to-the-SpawnReason-API.patch @@ -26,12 +26,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java @@ -0,0 +0,0 @@ public class DragonFireball extends AbstractHurtingProjectile { - if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) areaEffectCloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events + if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) entityareaeffectcloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events this.level().levelEvent(2006, this.blockPosition(), this.isSilent() ? -1 : 1); -- this.level().addFreshEntity(areaEffectCloud); -+ this.level().addFreshEntity(areaEffectCloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason - } else areaEffectCloud.discard(); // Paper - EnderDragon Events - this.discard(); +- this.level().addFreshEntity(entityareaeffectcloud); ++ this.level().addFreshEntity(entityareaeffectcloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason + } else entityareaeffectcloud.discard(null); // Paper - EnderDragon Events + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } diff --git a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Folia-scheduler-and-owned-region-API.patch b/patches/server/Folia-scheduler-and-owned-region-API.patch index 3bcfd6559..82c9c81d6 100644 --- a/patches/server/Folia-scheduler-and-owned-region-API.patch +++ b/patches/server/Folia-scheduler-and-owned-region-API.patch @@ -1214,19 +1214,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public CommandSender getBukkitSender(CommandSourceStack wrapper) { return this.getBukkitEntity(); @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - - @Override - public final void setRemoved(Entity.RemovalReason reason) { + public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { + CraftEventFactory.callEntityRemoveEvent(this, cause); + // CraftBukkit end + final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { - this.removalReason = reason; + this.removalReason = entity_removalreason; } @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S this.getPassengers().forEach(Entity::stopRiding); - this.levelCallback.onRemove(reason); + this.levelCallback.onRemove(entity_removalreason); + // Paper start - Folia schedulers -+ if (!(this instanceof ServerPlayer) && reason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { ++ if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { + // Players need to be special cased, because they are regularly removed from the world + this.retireScheduler(); + } diff --git a/patches/server/Improve-death-events.patch b/patches/server/Improve-death-events.patch index 8e1d9be85..95f0b8562 100644 --- a/patches/server/Improve-death-events.patch +++ b/patches/server/Improve-death-events.patch @@ -367,7 +367,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.brokenByPlayer(source); + org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(source); // Paper this.showBreakingParticles(); -- this.discard(); // CraftBukkit - SPIGOT-4890: remain as this.discard() since above damagesource method will call death event +- this.discard(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - SPIGOT-4890: remain as this.discard() since above damagesource method will call death event + if (!event.isCancelled()) this.kill(false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) } @@ -431,7 +431,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, this.drops); // CraftBukkit - call event // Paper - make cancellable + if (event.isCancelled()) return; // Paper - make cancellable + } // Paper - this.remove(Entity.RemovalReason.KILLED); + this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause this.gameEvent(GameEvent.ENTITY_DIE); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java diff --git a/patches/server/Improve-tag-parser-handling.patch b/patches/server/Improve-tag-parser-handling.patch index 3b8988ef7..b86a852b9 100644 --- a/patches/server/Improve-tag-parser-handling.patch +++ b/patches/server/Improve-tag-parser-handling.patch @@ -122,6 +122,51 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } } +diff --git a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java +@@ -0,0 +0,0 @@ public class TranslatableContents implements ComponentContents { + + @Override + public Optional visit(FormattedText.ContentConsumer visitor) { ++ // Paper start ++ try { ++ return this.visit(new TranslatableContentConsumer<>(visitor)); ++ } catch (IllegalArgumentException var5) { ++ return Optional.empty(); ++ } ++ } ++ private Optional visit(TranslatableContentConsumer visitor) { ++ // Paper end + this.decompose(); + + for(FormattedText formattedText : this.decomposedParts) { +@@ -0,0 +0,0 @@ public class TranslatableContents implements ComponentContents { + + return Optional.empty(); + } ++ // Paper start ++ private static final class TranslatableContentConsumer implements FormattedText.ContentConsumer { ++ private final FormattedText.ContentConsumer visitor; ++ private int visited; ++ ++ private TranslatableContentConsumer(FormattedText.ContentConsumer visitor) { ++ this.visitor = visitor; ++ } ++ ++ @Override ++ public Optional accept(final String asString) { ++ if (visited++ > 32) { ++ throw new IllegalArgumentException("Too long"); ++ } ++ return this.visitor.accept(asString); ++ } ++ } ++ // Paper end + + @Override + public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity sender, int depth) throws CommandSyntaxException { diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java diff --git a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch index e47d59976..090130c8b 100644 --- a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch +++ b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch @@ -30,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + xp.value = maxValue; + } else { xp.value += loopItem.value; - loopItem.discard(); + loopItem.discard(null); // Add Bukkit remove cause + } // Paper end - Maximum exp value when merging } } diff --git a/patches/server/Player-affects-spawning-API.patch b/patches/server/Player-affects-spawning-API.patch index 9bca4718f..3e8f00ef8 100644 --- a/patches/server/Player-affects-spawning-API.patch +++ b/patches/server/Player-affects-spawning-API.patch @@ -26,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements Targeting { if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { - this.discard(); + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { - Player entityhuman = this.level().getNearestPlayer(this, -1.0D); + Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API diff --git a/patches/server/PlayerAttemptPickupItemEvent.patch b/patches/server/PlayerAttemptPickupItemEvent.patch index 477ca45b5..76cafe7d0 100644 --- a/patches/server/PlayerAttemptPickupItemEvent.patch +++ b/patches/server/PlayerAttemptPickupItemEvent.patch @@ -8,8 +8,8 @@ diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -0,0 +0,0 @@ import org.bukkit.entity.Player; - import org.bukkit.event.entity.EntityPickupItemEvent; +@@ -0,0 +0,0 @@ import org.bukkit.event.entity.EntityPickupItemEvent; + import org.bukkit.event.entity.EntityRemoveEvent; import org.bukkit.event.player.PlayerPickupItemEvent; // CraftBukkit end +import org.bukkit.event.player.PlayerAttemptPickupItemEvent; // Paper diff --git a/patches/server/PlayerPickupItemEvent-setFlyAtPlayer.patch b/patches/server/PlayerPickupItemEvent-setFlyAtPlayer.patch index 6888157f2..9d79ac980 100644 --- a/patches/server/PlayerPickupItemEvent-setFlyAtPlayer.patch +++ b/patches/server/PlayerPickupItemEvent-setFlyAtPlayer.patch @@ -38,4 +38,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (flyAtPlayer) // Paper - PlayerPickupItemEvent player.take(this, i); if (itemstack.isEmpty()) { - this.discard(); + this.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause diff --git a/patches/server/Prevent-block-entity-and-entity-crashes.patch b/patches/server/Prevent-block-entity-and-entity-crashes.patch index 8695c85b8..ca9144fe4 100644 --- a/patches/server/Prevent-block-entity-and-entity-crashes.patch +++ b/patches/server/Prevent-block-entity-and-entity-crashes.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Prevent block entity and entity crashes + final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); + MinecraftServer.LOGGER.error(msg, throwable); -+ entity.discard(); ++ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + // Paper end - Prevent block entity and entity crashes } } diff --git a/patches/server/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch index 2789e6449..98a24e6af 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -14926,6 +14926,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import java.util.Iterator; +import java.util.List; +import java.util.function.Predicate; ++import org.bukkit.event.entity.EntityRemoveEvent; + +public final class ChunkEntitySlices { + @@ -15021,12 +15022,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + if (entity.shouldBeSaved()) { -+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); ++ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, EntityRemoveEvent.Cause.UNLOAD); + if (entity.isVehicle()) { + // we cannot assume that these entities are contained within this chunk, because entities can + // desync - so we need to remove them all + for (final Entity passenger : entity.getIndirectPassengers()) { -+ passenger.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); ++ passenger.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, EntityRemoveEvent.Cause.UNLOAD); + } + } + } @@ -19480,7 +19481,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @Override - public final void setRemoved(Entity.RemovalReason reason) { + public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { + // Paper start - rewrite chunk system + io.papermc.paper.util.TickThread.ensureTickThread(this, "Cannot remove entity off-main"); + if (!((ServerLevel)this.level).getEntityLookup().canRemoveEntity(this)) { @@ -19488,18 +19489,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + // Paper end - rewrite chunk system + CraftEventFactory.callEntityRemoveEvent(this, cause); + // CraftBukkit end final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers - if (this.removalReason == null) { - this.removalReason = reason; @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S this.stopRiding(); } - this.getPassengers().forEach(Entity::stopRiding); -+ if (reason != RemovalReason.UNLOADED_TO_CHUNK) this.getPassengers().forEach(Entity::stopRiding); // Paper - chunk system - don't adjust passenger state when unloading, it's just not safe (and messes with our logic in entity chunk unload) - this.levelCallback.onRemove(reason); ++ if (entity_removalreason != RemovalReason.UNLOADED_TO_CHUNK) this.getPassengers().forEach(Entity::stopRiding); // Paper - chunk system - don't adjust passenger state when unloading, it's just not safe (and messes with our logic in entity chunk unload) + this.levelCallback.onRemove(entity_removalreason); // Paper start - Folia schedulers - if (!(this instanceof ServerPlayer) && reason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { + if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @Override diff --git a/patches/server/Setup-Gradle-project.patch b/patches/server/Setup-Gradle-project.patch index 9421a57b4..f07ccb5d7 100644 --- a/patches/server/Setup-Gradle-project.patch +++ b/patches/server/Setup-Gradle-project.patch @@ -58,6 +58,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") + testImplementation("org.hamcrest:hamcrest:2.2") + testImplementation("org.mockito:mockito-core:5.5.0") ++ testImplementation("org.ow2.asm:asm-tree:9.5") +} + +val craftbukkitPackageVersion = "1_20_R3" // Paper @@ -474,6 +475,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 5.5.0 - test - +- +- org.ow2.asm +- asm-tree +- 9.5 +- test +- - - - diff --git a/patches/server/Test-changes.patch b/patches/server/Test-changes.patch index 305b3e8ec..a46db529d 100644 --- a/patches/server/Test-changes.patch +++ b/patches/server/Test-changes.patch @@ -9,9 +9,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -0,0 +0,0 @@ dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") testImplementation("org.hamcrest:hamcrest:2.2") testImplementation("org.mockito:mockito-core:5.5.0") + testImplementation("org.ow2.asm:asm-tree:9.5") + testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest } diff --git a/patches/server/Toggle-for-removing-existing-dragon.patch b/patches/server/Toggle-for-removing-existing-dragon.patch index ebe4ea5bd..78b891bb9 100644 --- a/patches/server/Toggle-for-removing-existing-dragon.patch +++ b/patches/server/Toggle-for-removing-existing-dragon.patch @@ -15,5 +15,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (!flag) { + if (!flag && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { // Paper - Toggle for removing existing dragon EndDragonFight.LOGGER.info("But we didn't have a portal, let's remove it."); - entityenderdragon.discard(); + entityenderdragon.discard(null); // CraftBukkit - add Bukkit remove cause this.dragonUUID = null; diff --git a/work/Bukkit b/work/Bukkit index 58ce1b0f1..9a80d38c0 160000 --- a/work/Bukkit +++ b/work/Bukkit @@ -1 +1 @@ -Subproject commit 58ce1b0f157c419bab3c256659a7e632f91aeb25 +Subproject commit 9a80d38c002509a4849c5e5f735dca9f9b5731e4 diff --git a/work/CraftBukkit b/work/CraftBukkit index 38fd4bd50..98b6c1ac7 160000 --- a/work/CraftBukkit +++ b/work/CraftBukkit @@ -1 +1 @@ -Subproject commit 38fd4bd5034e9adcc0a3122e43eb8d0273d1bc51 +Subproject commit 98b6c1ac7d4698ded83d96217861b071e519b300 diff --git a/work/Spigot b/work/Spigot index c198da22a..e9ec54852 160000 --- a/work/Spigot +++ b/work/Spigot @@ -1 +1 @@ -Subproject commit c198da22a814a0ba9c3128c3a9946286e0839b5a +Subproject commit e9ec54852f825ba470576cd1b5a33b0d76091fbe