--- a/net/minecraft/world/entity/Leashable.java +++ b/net/minecraft/world/entity/Leashable.java @@ -56,7 +_,13 @@ @Nullable private static Leashable.LeashData readLeashDataInternal(CompoundTag tag) { if (tag.contains("leash", 10)) { - return new Leashable.LeashData(Either.left(tag.getCompound("leash").getUUID("UUID"))); + // Paper start + final CompoundTag leashTag = tag.getCompound("leash"); + if (!leashTag.hasUUID("UUID")) { + return null; + } + return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID"))); + // Paper end } else { if (tag.contains("leash", 11)) { Either either = NbtUtils.readBlockPos(tag, "leash").>map(Either::right).orElse(null); @@ -72,6 +_,11 @@ default void writeLeashData(CompoundTag tag, @Nullable Leashable.LeashData leashData) { if (leashData != null) { Either either = leashData.delayedLeashInfo; + // CraftBukkit start - SPIGOT-7487: Don't save (and possible drop) leash, when the holder was removed by a plugin + if (leashData.leashHolder != null && leashData.leashHolder.pluginRemoved) { + return; + } + // CraftBukkit end if (leashData.leashHolder instanceof LeashFenceKnotEntity leashFenceKnotEntity) { either = Either.right(leashFenceKnotEntity.getPos()); } else if (leashData.leashHolder != null) { @@ -104,7 +_,9 @@ } if (entity.tickCount > 100) { + entity.forceDrops = true; // CraftBukkit entity.spawnAtLocation(serverLevel, Items.LEAD); + entity.forceDrops = false; // CraftBukkit entity.setLeashData(null); } } @@ -128,7 +_,9 @@ entity.onLeashRemoved(); if (entity.level() instanceof ServerLevel serverLevel) { if (dropItem) { + entity.forceDrops = true; // CraftBukkit entity.spawnAtLocation(serverLevel, Items.LEAD); + entity.forceDrops = false; // CraftBukkit } if (broadcastPacket) { @@ -146,7 +_,15 @@ if (leashData != null && leashData.leashHolder != null) { if (!entity.isAlive() || !leashData.leashHolder.isAlive()) { - if (level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + // Paper start - Expand EntityUnleashEvent + final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent( + entity.getBukkitEntity(), + !entity.isAlive() ? org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.PLAYER_UNLEASH : org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.HOLDER_GONE, + level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved + ); + event.callEvent(); + if (event.isDropLeash()) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin + // Paper end - Expand EntityUnleashEvent entity.dropLeash(); } else { entity.removeLeash(); @@ -160,7 +_,7 @@ return; } - if (f > 10.0) { + if (f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance entity.leashTooFarBehaviour(); } else if (f > 6.0) { entity.elasticRangeLeashBehaviour(leashHolder, f); @@ -177,7 +_,21 @@ } default void leashTooFarBehaviour() { - this.dropLeash(); + // CraftBukkit start + boolean dropLeash = true; // Paper + if (this instanceof Entity entity) { + // Paper start - Expand EntityUnleashEvent + final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(entity.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true); + if (!event.callEvent()) return; + dropLeash = event.isDropLeash(); + } + // CraftBukkit end + if (dropLeash) { + this.dropLeash(); + } else { + this.removeLeash(); + } + // Paper end - Expand EntityUnleashEvent } default void closeRangeLeashBehaviour(Entity entity) {