385 lines
18 KiB
Diff
385 lines
18 KiB
Diff
From cbdfe763326cfd3b4cf02eedd82e10ffa0f841d4 Mon Sep 17 00:00:00 2001
|
|
From: Phoenix616 <mail@moep.tv>
|
|
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.
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/CombatTracker.java b/src/main/java/net/minecraft/server/CombatTracker.java
|
|
index 20db76abd..a148cd437 100644
|
|
--- a/src/main/java/net/minecraft/server/CombatTracker.java
|
|
+++ b/src/main/java/net/minecraft/server/CombatTracker.java
|
|
@@ -175,6 +175,7 @@ public class CombatTracker {
|
|
this.h = null;
|
|
}
|
|
|
|
+ public void reset() { this.g(); } // Paper - OBFHELPER
|
|
public void g() {
|
|
int i = this.f ? 300 : 100;
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
|
|
index 784520342..ef7f0213b 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -1460,6 +1460,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
return false;
|
|
}
|
|
|
|
+ public void runKillTrigger(Entity entity, int kills, DamageSource damageSource) { this.a(entity, kills, damageSource); } // Paper - OBFHELPER
|
|
public void a(Entity entity, int i, DamageSource damagesource) {
|
|
if (entity instanceof EntityPlayer) {
|
|
CriterionTriggers.c.a((EntityPlayer) entity, this, damagesource);
|
|
@@ -2341,6 +2342,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
this.fallDistance = 0.0F;
|
|
}
|
|
|
|
+ public void onKill(EntityLiving entityLiving) { this.b(entityLiving); } // Paper - OBFHELPER
|
|
public void b(EntityLiving entityliving) {}
|
|
|
|
protected void i(double d0, double d1, double d2) {
|
|
diff --git a/src/main/java/net/minecraft/server/EntityArmorStand.java b/src/main/java/net/minecraft/server/EntityArmorStand.java
|
|
index 7031dd0e4..f6dc96434 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityArmorStand.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityArmorStand.java
|
|
@@ -675,7 +675,8 @@ public class EntityArmorStand extends EntityLiving {
|
|
|
|
@Override
|
|
public void killEntity() {
|
|
- org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event
|
|
+ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event // Paper - make cancellable
|
|
+ if (event.isCancelled()) return; // Paper - make cancellable
|
|
this.die();
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
|
|
index 064703afe..bd8385cd5 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityLiving.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
|
|
@@ -77,7 +77,7 @@ public abstract class EntityLiving extends Entity {
|
|
public float aN;
|
|
public float aO;
|
|
public EntityHuman killer;
|
|
- protected int lastDamageByPlayerTime;
|
|
+ public int lastDamageByPlayerTime; // Paper - public
|
|
protected boolean killed;
|
|
protected int ticksFarFromPlayer;
|
|
protected float aT;
|
|
@@ -85,7 +85,7 @@ public abstract class EntityLiving extends Entity {
|
|
protected float aV;
|
|
protected float aW;
|
|
protected float aX;
|
|
- protected int aY;
|
|
+ protected int aY; protected int getKillCount() { return this.aY; } // Paper - OBFHELPER
|
|
public float lastDamage;
|
|
protected boolean jumping;
|
|
public float bb;
|
|
@@ -128,6 +128,7 @@ public abstract class EntityLiving extends Entity {
|
|
public boolean collides = true;
|
|
public boolean canPickUpLoot;
|
|
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() {
|
|
@@ -1179,13 +1180,17 @@ public abstract class EntityLiving extends Entity {
|
|
|
|
if (this.getHealth() <= 0.0F) {
|
|
if (!this.f(damagesource)) {
|
|
- SoundEffect soundeffect = this.getSoundDeath();
|
|
+ // Paper start - moved into CraftEventFactory event caller for cancellable death event
|
|
+ //SoundEffect soundeffect = this.getSoundDeath();
|
|
|
|
- if (flag1 && soundeffect != null) {
|
|
- this.a(soundeffect, this.getSoundVolume(), this.cU());
|
|
- }
|
|
+ //if (flag1 && soundeffect != null) {
|
|
+ // this.a(soundeffect, this.getSoundVolume(), this.cU());
|
|
+ //}
|
|
+ this.silentDeath = !flag1; // mark entity as dying silently
|
|
+ // Paper end
|
|
|
|
this.die(damagesource);
|
|
+ this.silentDeath = false; // Paper - cancellable death event - reset to default
|
|
}
|
|
} else if (flag1) {
|
|
this.c(damagesource);
|
|
@@ -1323,22 +1328,40 @@ public abstract class EntityLiving extends Entity {
|
|
Entity entity = damagesource.getEntity();
|
|
EntityLiving entityliving = this.getKillingEntity();
|
|
|
|
- if (this.aY >= 0 && entityliving != null) {
|
|
- entityliving.a(this, this.aY, damagesource);
|
|
- }
|
|
-
|
|
- if (entity != null) {
|
|
- entity.b(this);
|
|
- }
|
|
-
|
|
- if (this.isSleeping()) {
|
|
- this.dy();
|
|
- }
|
|
-
|
|
+ // Paper start - move down to make death event cancellable
|
|
+ //if (this.aY >= 0 && entityliving != null) {
|
|
+ // entityliving.a(this, this.aY, damagesource);
|
|
+ //}
|
|
+ //
|
|
+ //if (entity != null) {
|
|
+ // entity.b(this);
|
|
+ //}
|
|
+ //
|
|
+ //if (this.isSleeping()) {
|
|
+ // this.dy();
|
|
+ //}
|
|
+ //
|
|
this.killed = true;
|
|
- this.getCombatTracker().g();
|
|
+ //this.getCombatTracker().g();
|
|
if (!this.world.isClientSide) {
|
|
- this.d(damagesource);
|
|
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.d(damagesource);
|
|
+ if (deathEvent == null || deathEvent.isCancelled()) {
|
|
+ if (this.getKillCount() >= 0 && entityliving != null) {
|
|
+ entityliving.runKillTrigger(this, this.getKillCount(), damagesource);
|
|
+ }
|
|
+ if (entity != null) {
|
|
+ entity.onKill(this);
|
|
+ }
|
|
+ if (this.isSleeping()) {
|
|
+ this.dy();
|
|
+ }
|
|
+ this.getCombatTracker().reset();
|
|
+ } else {
|
|
+ this.killed = false;
|
|
+ this.setHealth((float) deathEvent.getReviveHealth());
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
boolean flag = false;
|
|
|
|
if (entityliving instanceof EntityWither) {
|
|
@@ -1365,7 +1388,8 @@ public abstract class EntityLiving extends Entity {
|
|
}
|
|
}
|
|
|
|
- protected void d(DamageSource damagesource) {
|
|
+ protected org.bukkit.event.entity.EntityDeathEvent processDeath(DamageSource damagesource) { return d(damagesource); }
|
|
+ protected org.bukkit.event.entity.EntityDeathEvent d(DamageSource damagesource) { // Paper
|
|
Entity entity = damagesource.getEntity();
|
|
int i;
|
|
|
|
@@ -1376,19 +1400,20 @@ public abstract class EntityLiving extends Entity {
|
|
}
|
|
|
|
boolean flag = this.lastDamageByPlayerTime > 0;
|
|
-
|
|
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = null; // Paper
|
|
if (this.isDropExperience() && this.world.getGameRules().getBoolean("doMobLoot")) {
|
|
this.a(damagesource, flag);
|
|
this.dropDeathLoot(damagesource, i, flag);
|
|
// CraftBukkit start - Call death event
|
|
- CraftEventFactory.callEntityDeathEvent(this, this.drops);
|
|
- this.drops = new ArrayList<org.bukkit.inventory.ItemStack>();
|
|
+ deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper
|
|
+ if (!deathEvent.isCancelled()) this.drops = new ArrayList<org.bukkit.inventory.ItemStack>(); // Paper
|
|
} else {
|
|
- CraftEventFactory.callEntityDeathEvent(this);
|
|
+ deathEvent = CraftEventFactory.callEntityDeathEvent(this); // Paper
|
|
// CraftBukkit end
|
|
}
|
|
|
|
- this.cE();
|
|
+ if (!deathEvent.isCancelled()) this.cE(); // Paper
|
|
+ return deathEvent; // Paper
|
|
}
|
|
|
|
protected void cE() {}
|
|
@@ -1895,6 +1920,7 @@ public abstract class EntityLiving extends Entity {
|
|
return 1.0F;
|
|
}
|
|
|
|
+ public float getSoundPitch() { return cU();} // Paper - OBFHELPER
|
|
protected float cU() {
|
|
return this.isBaby() ? (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.5F : (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
index 634c30d93..332515128 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
@@ -74,6 +74,10 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|
public int ping;
|
|
public boolean viewingCredits;
|
|
private int containerUpdateDelay; // Paper
|
|
+ // Paper start - cancellable death event
|
|
+ public boolean queueHealthUpdatePacket = false;
|
|
+ public net.minecraft.server.PacketPlayOutUpdateHealth queuedHealthUpdatePacket;
|
|
+ // Paper end
|
|
|
|
// CraftBukkit start
|
|
public String displayName;
|
|
@@ -524,6 +528,15 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|
|
|
String deathmessage = defaultMessage.getString();
|
|
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory);
|
|
+ // 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;
|
|
+ }
|
|
+ // Paper end
|
|
|
|
// SPIGOT-943 - only call if they have an inventory open
|
|
if (this.activeContainer != this.defaultContainer) {
|
|
@@ -677,8 +690,17 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|
}
|
|
}
|
|
}
|
|
-
|
|
- return super.damageEntity(damagesource, f);
|
|
+ // Paper start - cancellable death events
|
|
+ //return super.damageEntity(damagesource, f);
|
|
+ this.queueHealthUpdatePacket = true;
|
|
+ boolean damaged = super.damageEntity(damagesource, f);
|
|
+ this.queueHealthUpdatePacket = false;
|
|
+ if (this.queuedHealthUpdatePacket != null) {
|
|
+ this.playerConnection.sendPacket(this.queuedHealthUpdatePacket);
|
|
+ this.queuedHealthUpdatePacket = null;
|
|
+ }
|
|
+ return damaged;
|
|
+ // Paper end
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftSound.java b/src/main/java/org/bukkit/craftbukkit/CraftSound.java
|
|
index 73cb64e09..9f317ff2e 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftSound.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftSound.java
|
|
@@ -806,6 +806,22 @@ public enum CraftSound {
|
|
WEATHER_RAIN_ABOVE("weather.rain.above");
|
|
private final String minecraftKey;
|
|
|
|
+ // Paper start - cancellable death event
|
|
+ public static CraftSound getBySoundEffect(final SoundEffect effect) {
|
|
+ MinecraftKey key = IRegistry.SOUND_EVENT.getKey(effect);
|
|
+ Preconditions.checkArgument(key != null, "Key for sound effect %s not found?", effect.toString());
|
|
+
|
|
+ return valueOf(key.getKey().replace('.', '_').toUpperCase(java.util.Locale.ENGLISH));
|
|
+ }
|
|
+
|
|
+ public static Sound getSoundByEffect(final SoundEffect effect) {
|
|
+ return Sound.valueOf(getBySoundEffect(effect).name());
|
|
+ }
|
|
+
|
|
+ public static SoundEffect getSoundEffect(final Sound sound) {
|
|
+ return getSoundEffect(getSound(sound));
|
|
+ }
|
|
+ // Paper end
|
|
CraftSound(String minecraftKey) {
|
|
this.minecraftKey = minecraftKey;
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
index d505af188..5f752784d 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -1711,7 +1711,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
}
|
|
|
|
public void sendHealthUpdate() {
|
|
- getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel()));
|
|
+ // Paper start - cancellable death event
|
|
+ //getHandle().playerConnection.sendPacket(new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel()));
|
|
+ PacketPlayOutUpdateHealth packet = new PacketPlayOutUpdateHealth(getScaledHealth(), getHandle().getFoodData().getFoodLevel(), getHandle().getFoodData().getSaturationLevel());
|
|
+ if (this.getHandle().queueHealthUpdatePacket) {
|
|
+ this.getHandle().queuedHealthUpdatePacket = packet;
|
|
+ } else {
|
|
+ this.getHandle().playerConnection.sendPacket(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 50444ed94..46c05c398 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
@@ -706,9 +706,16 @@ public class CraftEventFactory {
|
|
public static EntityDeathEvent callEntityDeathEvent(EntityLiving victim, List<org.bukkit.inventory.ItemStack> drops) {
|
|
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
|
|
EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
|
|
+ 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()) {
|
|
@@ -724,8 +731,15 @@ public class CraftEventFactory {
|
|
CraftPlayer entity = victim.getBukkitEntity();
|
|
PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage);
|
|
event.setKeepInventory(keepInventory);
|
|
+ populateFields(victim, event); // Paper - make cancellable
|
|
org.bukkit.World world = entity.getWorld();
|
|
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();
|
|
@@ -746,6 +760,31 @@ public class CraftEventFactory {
|
|
return event;
|
|
}
|
|
|
|
+ // Paper start - helper methods for making death event cancellable
|
|
+ // Add information to death event
|
|
+ private static void populateFields(EntityLiving victim, EntityDeathEvent event) {
|
|
+ event.setReviveHealth(event.getEntity().getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue());
|
|
+ event.setShouldPlayDeathSound(!victim.silentDeath && !victim.isSilent());
|
|
+ SoundEffect soundEffect = victim.getDeathSoundEffect();
|
|
+ event.setDeathSound(soundEffect != null ? org.bukkit.craftbukkit.CraftSound.getSoundByEffect(soundEffect) : null);
|
|
+ event.setDeathSoundCategory(org.bukkit.SoundCategory.valueOf(victim.getDeathSoundCategory().name()));
|
|
+ event.setDeathSoundVolume(victim.getDeathSoundVolume());
|
|
+ event.setDeathSoundPitch(victim.getDeathSoundPitch());
|
|
+ }
|
|
+
|
|
+ // Play death sound manually
|
|
+ private static void playDeathSound(EntityLiving victim, EntityDeathEvent event) {
|
|
+ if (event.shouldPlayDeathSound() && event.getDeathSound() != null && event.getDeathSoundCategory() != null) {
|
|
+ EntityHuman source = victim instanceof EntityHuman ? (EntityHuman) victim : null;
|
|
+ double x = event.getEntity().getLocation().getX();
|
|
+ double y = event.getEntity().getLocation().getY();
|
|
+ double z = event.getEntity().getLocation().getZ();
|
|
+ SoundEffect soundEffect = org.bukkit.craftbukkit.CraftSound.getSoundEffect(event.getDeathSound());
|
|
+ SoundCategory soundCategory = SoundCategory.valueOf(event.getDeathSoundCategory().name());
|
|
+ victim.world.sendSoundEffect(source, x, y, z, soundEffect, soundCategory, event.getDeathSoundVolume(), event.getDeathSoundPitch());
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
/**
|
|
* Server methods
|
|
*/
|
|
--
|
|
2.21.0
|
|
|