diff options
Diffstat (limited to 'patches/server/0243-Improve-death-events.patch')
-rw-r--r-- | patches/server/0243-Improve-death-events.patch | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/patches/server/0243-Improve-death-events.patch b/patches/server/0243-Improve-death-events.patch new file mode 100644 index 0000000000..13a1d5d493 --- /dev/null +++ b/patches/server/0243-Improve-death-events.patch @@ -0,0 +1,512 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 <[email protected]> +Date: Tue, 21 Aug 2018 01:39:35 +0100 +Subject: [PATCH] Improve death events + +This adds the ability to cancel the death events and to modify the sound +an entity makes when dying. (In cases were no sound should it will be +called with shouldPlaySound set to false allowing unsilencing of silent +entities) + +It makes handling of entity deaths a lot nicer as you no longer need +to listen on the damage event and calculate if the entity dies yourself +to cancel the death which has the benefit of also receiving the dropped +items and experience which is otherwise only properly possible by using +internal code. + +== AT == +public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent; +public net.minecraft.world.entity.LivingEntity getSoundVolume()F + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 00a1a570e9f7abf97a25b4bab2b7532d3dad7912..0706dd82cfdb6808ef61149b2a8d8be971f19be9 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -268,6 +268,10 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + private int containerCounter; + public boolean wonGame; + private int containerUpdateDelay; // Paper - Configurable container update tick rate ++ // Paper start - cancellable death event ++ public boolean queueHealthUpdatePacket; ++ public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; ++ // Paper end - cancellable death event + + // CraftBukkit start + public CraftPlayer.TransferCookieConnection transferCookieConnection; +@@ -893,7 +897,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + @Override + public void die(DamageSource damageSource) { +- this.gameEvent(GameEvent.ENTITY_DIE); ++ // this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check + boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); + // CraftBukkit start - fire PlayerDeathEvent + if (this.isRemoved()) { +@@ -921,6 +925,16 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + String deathmessage = defaultMessage.getString(); + this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel + org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, damageSource, loot, PaperAdventure.asAdventure(defaultMessage), keepInventory); // Paper - Adventure ++ // Paper start - cancellable death event ++ if (event.isCancelled()) { ++ // make compatible with plugins that might have already set the health in an event listener ++ if (this.getHealth() <= 0) { ++ this.setHealth((float) event.getReviveHealth()); ++ } ++ return; ++ } ++ this.gameEvent(GameEvent.ENTITY_DIE); // moved from the top of this method ++ // Paper end + + // SPIGOT-943 - only call if they have an inventory open + if (this.containerMenu != this.inventoryMenu) { +@@ -1069,8 +1083,17 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + } + } +- +- return super.hurt(source, amount); ++ // Paper start - cancellable death events ++ //return super.hurt(source, amount); ++ this.queueHealthUpdatePacket = true; ++ boolean damaged = super.hurt(source, amount); ++ this.queueHealthUpdatePacket = false; ++ if (this.queuedHealthUpdatePacket != null) { ++ this.connection.send(this.queuedHealthUpdatePacket); ++ this.queuedHealthUpdatePacket = null; ++ } ++ return damaged; ++ // Paper end + } + } + } +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index f7a77b31dc196823510f96bd3b2344058e20feac..279fa00fd9043e1995f22c79f47d0b41c27bd933 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -283,6 +283,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + public Set<UUID> collidableExemptions = new HashSet<>(); + public boolean bukkitPickUpLoot; + public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper ++ public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event + + @Override + public float getBukkitYaw() { +@@ -1537,11 +1538,12 @@ public abstract class LivingEntity extends Entity implements Attackable { + + if (this.isDeadOrDying()) { + if (!this.checkTotemDeathProtection(source)) { +- if (flag1) { +- this.makeSound(this.getDeathSound()); +- } ++ // Paper start - moved into CraftEventFactory event caller for cancellable death event ++ this.silentDeath = !flag1; // mark entity as dying silently ++ // Paper end + + this.die(source); ++ this.silentDeath = false; // Paper - cancellable death event - reset to default + } + } else if (flag1) { + this.playHurtSound(source); +@@ -1700,6 +1702,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + Entity entity = damageSource.getEntity(); + LivingEntity entityliving = this.getKillCredit(); + ++ /* // Paper - move down to make death event cancellable - this is the awardKillScore below + if (this.deathScore >= 0 && entityliving != null) { + entityliving.awardKillScore(this, this.deathScore, damageSource); + } +@@ -1711,24 +1714,59 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.level().isClientSide && this.hasCustomName()) { + if (org.spigotmc.SpigotConfig.logNamedDeaths) LivingEntity.LOGGER.info("Named entity {} died: {}", this, this.getCombatTracker().getDeathMessage().getString()); // Spigot + } ++ */ // Paper - move down to make death event cancellable - this is the awardKillScore below + + this.dead = true; +- this.getCombatTracker().recheckStatus(); ++ // Paper - moved into if below + Level world = this.level(); + + if (world instanceof ServerLevel) { + ServerLevel worldserver = (ServerLevel) world; ++ // Paper - move below into if for onKill ++ ++ // Paper start ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(worldserver, damageSource); ++ if (deathEvent == null || !deathEvent.isCancelled()) { ++ if (this.deathScore >= 0 && entityliving != null) { ++ entityliving.awardKillScore(this, this.deathScore, damageSource); ++ } ++ // Paper start - clear equipment if event is not cancelled ++ if (this instanceof Mob) { ++ for (EquipmentSlot slot : this.clearedEquipmentSlots) { ++ this.setItemSlot(slot, ItemStack.EMPTY); ++ } ++ this.clearedEquipmentSlots.clear(); ++ } ++ // Paper end ++ ++ if (this.isSleeping()) { ++ this.stopSleeping(); ++ } + +- if (entity == null || entity.killedEntity(worldserver, this)) { ++ if (!this.level().isClientSide && this.hasCustomName()) { ++ if (org.spigotmc.SpigotConfig.logNamedDeaths) LivingEntity.LOGGER.info("Named entity {} died: {}", this, this.getCombatTracker().getDeathMessage().getString()); // Spigot ++ } ++ ++ this.getCombatTracker().recheckStatus(); ++ if (entity != null) { ++ entity.killedEntity((ServerLevel) this.level(), this); ++ } + this.gameEvent(GameEvent.ENTITY_DIE); +- this.dropAllDeathLoot(worldserver, damageSource); ++ } else { ++ this.dead = false; ++ this.setHealth((float) deathEvent.getReviveHealth()); ++ } ++ // Paper end + this.createWitherRose(entityliving); + } + ++ // Paper start ++ if (this.dead) { // Paper + this.level().broadcastEntityEvent(this, (byte) 3); +- } + + this.setPose(Pose.DYING); ++ } ++ // Paper end + } + } + +@@ -1736,7 +1774,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.level().isClientSide) { + boolean flag = false; + +- if (adversary instanceof WitherBoss) { ++ if (this.dead && adversary instanceof WitherBoss) { // Paper + if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + BlockPos blockposition = this.blockPosition(); + BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); +@@ -1765,24 +1803,37 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + } + +- protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { ++ // Paper start ++ protected boolean clearEquipmentSlots = true; ++ protected Set<EquipmentSlot> clearedEquipmentSlots = new java.util.HashSet<>(); ++ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { ++ // Paper end + boolean flag = this.lastHurtByPlayerTime > 0; + + this.dropEquipment(); // CraftBukkit - from below + if (this.shouldDropLoot() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + this.dropFromLootTable(damageSource, flag); ++ // Paper start ++ final boolean prev = this.clearEquipmentSlots; ++ this.clearEquipmentSlots = false; ++ this.clearedEquipmentSlots.clear(); ++ // Paper end + this.dropCustomDeathLoot(world, damageSource, flag); ++ this.clearEquipmentSlots = prev; // Paper + } + // CraftBukkit start - Call death event +- CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper ++ this.postDeathDropItems(deathEvent); // Paper + this.drops = new ArrayList<>(); + // CraftBukkit end + + // this.dropEquipment();// CraftBukkit - moved up + this.dropExperience(damageSource.getEntity()); ++ return deathEvent; // Paper + } + + protected void dropEquipment() {} ++ protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled + + public int getExpReward(@Nullable Entity entity) { // CraftBukkit + Level world = this.level(); +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index b7c216b79684a4dbb93899fd2d3bc5a9e1b04f2e..4b0e269f3580c1c6dac1e5f2dd3cdac1d8e1118a 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -1121,6 +1121,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + + } + ++ // Paper start ++ protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox) ++ return false; ++ } ++ // Paper end ++ + @Override + protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { + super.dropCustomDeathLoot(world, source, causedByPlayer); +@@ -1129,6 +1135,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + + for (int j = 0; j < i; ++j) { + EquipmentSlot enumitemslot = aenumitemslot[j]; ++ if (this.shouldSkipLoot(enumitemslot)) continue; // Paper + ItemStack itemstack = this.getItemBySlot(enumitemslot); + float f = this.getEquipmentDropChance(enumitemslot); + +@@ -1153,7 +1160,13 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + } + + this.spawnAtLocation(itemstack); ++ if (this.clearEquipmentSlots) { // Paper + this.setItemSlot(enumitemslot, ItemStack.EMPTY); ++ // Paper start ++ } else { ++ this.clearedEquipmentSlots.add(enumitemslot); ++ } ++ // Paper end + } + } + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java +index a6788da1505f9e119c03b94488f5e006da13e918..e46c8231ee318eda0512afbb6343b426b4838643 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java +@@ -704,16 +704,38 @@ public class Fox extends Animal implements VariantHolder<Fox.Type> { + return this.getTrustedUUIDs().contains(uuid); + } + ++ // Paper start - handle the bitten item separately like vanilla + @Override +- protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { ++ protected boolean shouldSkipLoot(EquipmentSlot slot) { ++ return slot == EquipmentSlot.MAINHAND; ++ } ++ // Paper end ++ ++ @Override ++ // Paper start - Cancellable death event ++ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { + ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND); + +- if (!itemstack.isEmpty()) { ++ boolean releaseMouth = false; ++ if (!itemstack.isEmpty() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Fix MC-153010 + this.spawnAtLocation(itemstack); ++ releaseMouth = true; ++ } ++ ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(world, damageSource); ++ ++ // Below is code to drop ++ ++ if (deathEvent == null || deathEvent.isCancelled()) { ++ return deathEvent; ++ } ++ ++ if (releaseMouth) { ++ // Paper end - Cancellable death event + this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); + } + +- super.dropAllDeathLoot(world, damageSource); ++ return deathEvent; // Paper - Cancellable death event + } + + public static boolean isPathClear(Fox fox, LivingEntity chasedEntity) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java +index 767817fb1418958c89d0db9da4ae7eb8a5a16076..5654c614f07f07ff642ba4851b0cb6fa185924ae 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractChestedHorse.java +@@ -71,9 +71,17 @@ public abstract class AbstractChestedHorse extends AbstractHorse { + this.spawnAtLocation(Blocks.CHEST); + } + ++ //this.setChest(false); // Paper - moved to post death logic ++ } ++ } ++ ++ // Paper start ++ protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) { ++ if (this.hasChest() && (event == null || !event.isCancelled())) { + this.setChest(false); + } + } ++ // Paper end + + @Override + public void addAdditionalSaveData(CompoundTag nbt) { +diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +index ee3902cbada46ffb78c42dbf6f00c859546c76e1..92bb0c63330ad3a4cb13b2dc655020714e9b1ffd 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -505,8 +505,10 @@ public class ArmorStand extends LivingEntity { + } + // CraftBukkit end + if (source.is(DamageTypeTags.IS_EXPLOSION)) { +- this.brokenByAnything(worldserver, source); +- this.kill(source); // CraftBukkit ++ // Paper start - avoid duplicate event call ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(worldserver, source); ++ if (!event.isCancelled()) this.kill(source, false); // CraftBukkit ++ // Paper end + return false; + } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + if (this.isOnFire()) { +@@ -549,9 +551,9 @@ public class ArmorStand extends LivingEntity { + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); + this.lastHit = i; + } else { +- this.brokenByPlayer(worldserver, source); ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(worldserver, source); // Paper + this.showBreakingParticles(); +- 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(source, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) + } + + return true; +@@ -604,8 +606,10 @@ public class ArmorStand extends LivingEntity { + + f1 -= amount; + if (f1 <= 0.5F) { +- this.brokenByAnything(world, damageSource); +- this.kill(damageSource); // CraftBukkit ++ // Paper start - avoid duplicate event call ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(world, damageSource); ++ if (!event.isCancelled()) this.kill(damageSource, false); // CraftBukkit ++ // Paper end + } else { + this.setHealth(f1); + this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); +@@ -613,15 +617,15 @@ public class ArmorStand extends LivingEntity { + + } + +- private void brokenByPlayer(ServerLevel world, DamageSource damageSource) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel world, DamageSource damageSource) { // Paper + ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); + + itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); + this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops +- this.brokenByAnything(world, damageSource); ++ return this.brokenByAnything(world, damageSource); // Paper + } + +- private void brokenByAnything(ServerLevel world, DamageSource damageSource) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(ServerLevel world, DamageSource damageSource) { // Paper + this.playBrokenSound(); + // this.dropAllDeathLoot(worldserver, damagesource); // CraftBukkit - moved down + +@@ -643,7 +647,7 @@ public class ArmorStand extends LivingEntity { + this.armorItems.set(i, ItemStack.EMPTY); + } + } +- this.dropAllDeathLoot(world, damageSource); // CraftBukkit - moved from above ++ return this.dropAllDeathLoot(world, damageSource); // CraftBukkit - moved from above // Paper + + } + +@@ -770,7 +774,15 @@ public class ArmorStand extends LivingEntity { + } + + public void kill(DamageSource damageSource) { +- org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (damageSource == null ? this.damageSources().genericKill() : damageSource), this.drops); // CraftBukkit - call event ++ // Paper start - make cancellable ++ this.kill(damageSource, true); ++ } ++ public void kill(DamageSource damageSource, boolean callEvent) { ++ if (callEvent) { ++ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (damageSource == null ? this.damageSources().genericKill() : damageSource), this.drops); // CraftBukkit - call event ++ if (event.isCancelled()) return; ++ } ++ // Paper end + this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + // CraftBukkit end + 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 +index 597594409b4d1fadf4ae1c3a7156421e70989d97..2d1e0e92e6d98a9cf597c3717c36ea5a337577c3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2517,7 +2517,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + @Override + public void sendHealthUpdate() { + FoodData foodData = this.getHandle().getFoodData(); +- this.sendHealthUpdate(this.getScaledHealth(), foodData.getFoodLevel(), foodData.getSaturationLevel()); ++ // Paper start - cancellable death event ++ ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket(this.getScaledHealth(), foodData.getFoodLevel(), foodData.getSaturationLevel()); ++ if (this.getHandle().queueHealthUpdatePacket) { ++ this.getHandle().queuedHealthUpdatePacket = packet; ++ } else { ++ this.getHandle().connection.send(packet); ++ } ++ // Paper end + } + + public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) { +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 1d2e9f3e5e232faca8de4760d3574fae6200b2b2..e7ba5b503e821d18467c2300f780ef37f996b34d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -894,9 +894,16 @@ public class CraftEventFactory { + CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); + CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); + EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity())); ++ populateFields(victim, event); // Paper - make cancellable + CraftWorld world = (CraftWorld) entity.getWorld(); + Bukkit.getServer().getPluginManager().callEvent(event); + ++ // Paper start - make cancellable ++ if (event.isCancelled()) { ++ return event; ++ } ++ playDeathSound(victim, event); ++ // Paper end + victim.expToDrop = event.getDroppedExp(); + + for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { +@@ -914,7 +921,14 @@ public class CraftEventFactory { + PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()), 0, deathMessage); + event.setKeepInventory(keepInventory); + event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel ++ populateFields(victim, event); // Paper - make cancellable + Bukkit.getServer().getPluginManager().callEvent(event); ++ // Paper start - make cancellable ++ if (event.isCancelled()) { ++ return event; ++ } ++ playDeathSound(victim, event); ++ // Paper end + + victim.keepLevel = event.getKeepLevel(); + victim.newLevel = event.getNewLevel(); +@@ -931,6 +945,31 @@ public class CraftEventFactory { + return event; + } + ++ // Paper start - helper methods for making death event cancellable ++ // Add information to death event ++ private static void populateFields(net.minecraft.world.entity.LivingEntity victim, EntityDeathEvent event) { ++ event.setReviveHealth(event.getEntity().getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue()); ++ event.setShouldPlayDeathSound(!victim.silentDeath && !victim.isSilent()); ++ net.minecraft.sounds.SoundEvent soundEffect = victim.getDeathSound(); ++ event.setDeathSound(soundEffect != null ? org.bukkit.craftbukkit.CraftSound.minecraftToBukkit(soundEffect) : null); ++ event.setDeathSoundCategory(org.bukkit.SoundCategory.valueOf(victim.getSoundSource().name())); ++ event.setDeathSoundVolume(victim.getSoundVolume()); ++ event.setDeathSoundPitch(victim.getVoicePitch()); ++ } ++ ++ // Play death sound manually ++ private static void playDeathSound(net.minecraft.world.entity.LivingEntity victim, EntityDeathEvent event) { ++ if (event.shouldPlayDeathSound() && event.getDeathSound() != null && event.getDeathSoundCategory() != null) { ++ net.minecraft.world.entity.player.Player source = victim instanceof net.minecraft.world.entity.player.Player ? (net.minecraft.world.entity.player.Player) victim : null; ++ double x = event.getEntity().getLocation().getX(); ++ double y = event.getEntity().getLocation().getY(); ++ double z = event.getEntity().getLocation().getZ(); ++ net.minecraft.sounds.SoundEvent soundEffect = org.bukkit.craftbukkit.CraftSound.bukkitToMinecraft(event.getDeathSound()); ++ net.minecraft.sounds.SoundSource soundCategory = net.minecraft.sounds.SoundSource.valueOf(event.getDeathSoundCategory().name()); ++ victim.level().playSound(source, x, y, z, soundEffect, soundCategory, event.getDeathSoundVolume(), event.getDeathSoundPitch()); ++ } ++ } ++ // Paper end + /** + * Server methods + */ |