--- a/net/minecraft/world/entity/Leashable.java +++ b/net/minecraft/world/entity/Leashable.java @@ -80,6 +_,11 @@ } default void writeLeashData(ValueOutput output, @Nullable Leashable.LeashData leashData) { + // CraftBukkit start - SPIGOT-7487: Don't save (and possible drop) leash, when the holder was removed by a plugin + if (leashData != null && leashData.leashHolder != null && leashData.leashHolder.pluginRemoved) { + return; + } + // CraftBukkit end output.storeNullable("leash", Leashable.LeashData.CODEC, leashData); } @@ -99,7 +_,9 @@ } if (entity.tickCount > 100) { + entity.forceDrops = true; // CraftBukkit entity.spawnAtLocation(serverLevel, Items.LEAD); + entity.forceDrops = false; // CraftBukkit entity.setLeashData(null); } } @@ -123,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) { @@ -143,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(); @@ -154,7 +_,7 @@ if (leashHolder != null && leashHolder.level() == entity.level()) { double d = entity.leashDistanceTo(leashHolder); entity.whenLeashedTo(leashHolder); - if (d > entity.leashSnapDistance()) { + if (d > entity.leashSnapDistanceOrConfig()) { // Paper - Configurable max leash distance level.playSound(null, leashHolder.getX(), leashHolder.getY(), leashHolder.getZ(), SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F); entity.leashTooFarBehaviour(); } else if (d > entity.leashElasticDistance() - leashHolder.getBbWidth() - entity.getBbWidth() @@ -175,6 +_,12 @@ entity.checkFallDistanceAccumulation(); } + // Paper start - Configurable max leash distance + default double leashSnapDistanceOrConfig() { + if (!(this instanceof final Entity entity)) return leashSnapDistance(); + return entity.level().paperConfig().misc.maxLeashDistance.or(leashSnapDistance()); + } + // Paper end - Configurable max leash distance default double leashSnapDistance() { return 12.0; } @@ -196,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) {