From 77d1524b3d11f2580cf5792a79cd4c72385fdee9 Mon Sep 17 00:00:00 2001
From: feildmaster <admin@feildmaster.com>
Date: Tue, 9 Apr 2013 22:25:06 -0500
Subject: [PATCH] Refactor EntityDamageEvents. Adds BUKKIT-1944 & BUKKIT-3684

---
 .../java/net/minecraft/server/Entity.java     | 34 +---------
 .../minecraft/server/EntityEnderDragon.java   | 16 +----
 .../net/minecraft/server/EntityLiving.java    | 67 ++++++-------------
 .../net/minecraft/server/EntitySnowman.java   | 24 ++-----
 .../net/minecraft/server/FoodMetaData.java    | 10 +--
 .../net/minecraft/server/MobEffectList.java   | 25 +------
 .../craftbukkit/event/CraftEventFactory.java  | 64 +++++++++++++++---
 .../craftbukkit/util/CraftDamageSource.java   | 31 +++++++++
 8 files changed, 116 insertions(+), 155 deletions(-)
 create mode 100644 src/main/java/org/bukkit/craftbukkit/util/CraftDamageSource.java

diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 7890d6f54e..51a5b38cc3 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -24,7 +24,6 @@ import org.bukkit.craftbukkit.entity.CraftEntity;
 import org.bukkit.craftbukkit.entity.CraftPlayer;
 import org.bukkit.event.entity.EntityCombustEvent;
 import org.bukkit.event.entity.EntityDamageByBlockEvent;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
 import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.event.entity.EntityPortalEvent;
 import org.bukkit.plugin.PluginManager;
@@ -325,19 +324,7 @@ public abstract class Entity {
                 }
             } else {
                 if (this.fireTicks % 20 == 0) {
-                    // CraftBukkit start - TODO: this event spams!
-                    if (this instanceof EntityLiving) {
-                        EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FIRE_TICK, 1);
-                        this.world.getServer().getPluginManager().callEvent(event);
-
-                        if (!event.isCancelled()) {
-                            event.getEntity().setLastDamageCause(event);
-                            this.damageEntity(DamageSource.BURN, event.getDamage());
-                        }
-                    } else {
-                        this.damageEntity(DamageSource.BURN, 1);
-                    }
-                    // CraftBukkit end
+                    this.damageEntity(DamageSource.BURN, 1);
                 }
 
                 --this.fireTicks;
@@ -790,20 +777,6 @@ public abstract class Entity {
 
     protected void burn(int i) {
         if (!this.fireProof) {
-            // CraftBukkit start
-            if (this instanceof EntityLiving) {
-                EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FIRE, i);
-                this.world.getServer().getPluginManager().callEvent(event);
-
-                if (event.isCancelled()) {
-                    return;
-                }
-
-                i = event.getDamage();
-                event.getEntity().setLastDamageCause(event);
-            }
-            // CraftBukkit end
-
             this.damageEntity(DamageSource.FIRE, i);
         }
     }
@@ -1594,14 +1567,11 @@ public abstract class Entity {
             }
         }
 
-        EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(stormBukkitEntity, thisBukkitEntity, EntityDamageEvent.DamageCause.LIGHTNING, 5);
-        pluginManager.callEvent(event);
-
+        EntityDamageEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDamageEvent(entitylightning, this, EntityDamageEvent.DamageCause.LIGHTNING, 5);
         if (event.isCancelled()) {
             return;
         }
 
-        thisBukkitEntity.setLastDamageCause(event);
         this.burn(event.getDamage());
         // CraftBukkit end
 
diff --git a/src/main/java/net/minecraft/server/EntityEnderDragon.java b/src/main/java/net/minecraft/server/EntityEnderDragon.java
index 7d4c4f5b66..decb9057fc 100644
--- a/src/main/java/net/minecraft/server/EntityEnderDragon.java
+++ b/src/main/java/net/minecraft/server/EntityEnderDragon.java
@@ -7,7 +7,6 @@ import java.util.List;
 import org.bukkit.block.BlockState;
 import org.bukkit.craftbukkit.util.BlockStateListPopulator;
 import org.bukkit.event.entity.EntityCreatePortalEvent;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
 import org.bukkit.event.entity.EntityExplodeEvent;
 import org.bukkit.event.entity.EntityRegainHealthEvent;
 import org.bukkit.Bukkit;
@@ -363,20 +362,7 @@ public class EntityEnderDragon extends EntityLiving implements IComplex {
             Entity entity = (Entity) list.get(i);
 
             if (entity instanceof EntityLiving) {
-                // CraftBukkit start - Throw damage events when the dragon attacks
-                // The EntityHuman case is handled in EntityHuman, so don't throw it here
-                if (!(entity instanceof EntityHuman)) {
-                    EntityDamageByEntityEvent damageEvent = new EntityDamageByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, 10);
-                    Bukkit.getPluginManager().callEvent(damageEvent);
-
-                    if (!damageEvent.isCancelled()) {
-                        entity.getBukkitEntity().setLastDamageCause(damageEvent);
-                        entity.damageEntity(DamageSource.mobAttack(this), damageEvent.getDamage());
-                    }
-                } else {
-                    entity.damageEntity(DamageSource.mobAttack(this), 10);
-                }
-                // CraftBukkit end
+                entity.damageEntity(DamageSource.mobAttack(this), 10);
             }
         }
     }
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index 9210d9692c..21819eeb96 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -322,17 +322,9 @@ public abstract class EntityLiving extends Entity {
             this.aR();
         }
 
-        // CraftBukkit start
-        if (this.isAlive() && this.inBlock() && !(this instanceof EntityEnderDragon)) { // EnderDragon's don't suffocate.
-            EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.SUFFOCATION, 1);
-            this.world.getServer().getPluginManager().callEvent(event);
-
-            if (!event.isCancelled()) {
-                event.getEntity().setLastDamageCause(event);
-                this.damageEntity(DamageSource.STUCK, event.getDamage());
-            }
+        if (this.isAlive() && this.inBlock()) {
+            this.damageEntity(DamageSource.STUCK, 1);
         }
-        // CraftBukkit end
 
         if (this.isFireproof() || this.world.isStatic) {
             this.extinguish();
@@ -353,15 +345,7 @@ public abstract class EntityLiving extends Entity {
                     this.world.addParticle("bubble", this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, this.motX, this.motY, this.motZ);
                 }
 
-                // CraftBukkit start
-                EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.DROWNING, 2);
-                this.world.getServer().getPluginManager().callEvent(event);
-
-                if (!event.isCancelled() && event.getDamage() != 0) {
-                    event.getEntity().setLastDamageCause(event);
-                    this.damageEntity(DamageSource.DROWN, event.getDamage());
-                }
-                // CraftBukkit end
+                this.damageEntity(DamageSource.DROWN, 2);
             }
 
             this.extinguish();
@@ -690,8 +674,8 @@ public abstract class EntityLiving extends Entity {
                 boolean flag = true;
 
                 // CraftBukkit start
-                if (damagesource instanceof EntityDamageSource) {
-                    EntityDamageEvent event = CraftEventFactory.handleEntityDamageEvent(this, damagesource, i);
+                EntityDamageEvent event = CraftEventFactory.handleEntityDamageEvent(this, damagesource, i);
+                if (event != null) {
                     if (event.isCancelled()) {
                         return false;
                     }
@@ -970,25 +954,26 @@ public abstract class EntityLiving extends Entity {
         super.a(f);
         int i = MathHelper.f(f - 3.0F);
 
+        // CraftBukkit start
         if (i > 0) {
-            // CraftBukkit start
-            EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.FALL, i);
-            this.world.getServer().getPluginManager().callEvent(event);
-
-            if (!event.isCancelled() && event.getDamage() != 0) {
+            EntityDamageEvent event = CraftEventFactory.callEntityDamageEvent(null, this, EntityDamageEvent.DamageCause.FALL, i);
+            if (!event.isCancelled()) {
                 i = event.getDamage();
-
-                if (i > 4) {
-                    this.makeSound("damage.fallbig", 1.0F, 1.0F);
-                } else {
-                    this.makeSound("damage.fallsmall", 1.0F, 1.0F);
+                if (i > 0) {
+                    this.getBukkitEntity().setLastDamageCause(event);
                 }
-
-                this.getBukkitEntity().setLastDamageCause(event);
-                this.damageEntity(DamageSource.FALL, i);
             }
-            // CraftBukkit end
+        }
+        // CraftBukkit end
 
+        if (i > 0) {
+            if (i > 4) {
+                this.makeSound("damage.fallbig", 1.0F, 1.0F);
+            } else {
+                this.makeSound("damage.fallsmall", 1.0F, 1.0F);
+            }
+
+            this.damageEntity(DamageSource.FALL, i);
             int j = this.world.getTypeId(MathHelper.floor(this.locX), MathHelper.floor(this.locY - 0.20000000298023224D - (double) this.height), MathHelper.floor(this.locZ));
 
             if (j > 0) {
@@ -1633,17 +1618,7 @@ public abstract class EntityLiving extends Entity {
     }
 
     protected void B() {
-        // CraftBukkit start
-        EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(null, this.getBukkitEntity(), EntityDamageEvent.DamageCause.VOID, 4);
-        this.world.getServer().getPluginManager().callEvent(event);
-
-        if (event.isCancelled() || event.getDamage() == 0) {
-            return;
-        }
-
-        event.getEntity().setLastDamageCause(event);
-        this.damageEntity(DamageSource.OUT_OF_WORLD, event.getDamage());
-        // CraftBukkit end
+        this.damageEntity(DamageSource.OUT_OF_WORLD, 4);
     }
 
     public Vec3D Y() {
diff --git a/src/main/java/net/minecraft/server/EntitySnowman.java b/src/main/java/net/minecraft/server/EntitySnowman.java
index fd88beabb9..8b9fb83c3c 100644
--- a/src/main/java/net/minecraft/server/EntitySnowman.java
+++ b/src/main/java/net/minecraft/server/EntitySnowman.java
@@ -1,8 +1,8 @@
 package net.minecraft.server;
 
 // CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
 import org.bukkit.event.block.EntityBlockFormEvent;
-import org.bukkit.event.entity.EntityDamageEvent;
 // CraftBukkit end
 
 public class EntitySnowman extends EntityGolem implements IRangedEntity {
@@ -30,30 +30,14 @@ public class EntitySnowman extends EntityGolem implements IRangedEntity {
     public void c() {
         super.c();
         if (this.F()) {
-            // CraftBukkit start
-            EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.DROWNING, 1);
-            this.world.getServer().getPluginManager().callEvent(event);
-
-            if (!event.isCancelled()) {
-                event.getEntity().setLastDamageCause(event);
-                this.damageEntity(DamageSource.DROWN, event.getDamage());
-            }
-            // CraftBukkit end
+            this.damageEntity(DamageSource.DROWN, 1);
         }
 
         int i = MathHelper.floor(this.locX);
         int j = MathHelper.floor(this.locZ);
 
         if (this.world.getBiome(i, j).j() > 1.0F) {
-            // CraftBukkit start
-            EntityDamageEvent event = new EntityDamageEvent(this.getBukkitEntity(), EntityDamageEvent.DamageCause.MELTING, 1);
-            this.world.getServer().getPluginManager().callEvent(event);
-
-            if (!event.isCancelled()) {
-                event.getEntity().setLastDamageCause(event);
-                this.damageEntity(DamageSource.BURN, event.getDamage());
-            }
-            // CraftBukkit end
+            this.damageEntity(CraftEventFactory.MELTING, 1); // CraftBukkit - DamageSource.BURN -> CraftEventFactory.MELTING
         }
 
         for (i = 0; i < 4; ++i) {
@@ -90,7 +74,7 @@ public class EntitySnowman extends EntityGolem implements IRangedEntity {
             loot.add(new org.bukkit.inventory.ItemStack(Item.SNOW_BALL.id, j));
         }
 
-        org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, loot);
+        CraftEventFactory.callEntityDeathEvent(this, loot);
         // CraftBukkit end
     }
 
diff --git a/src/main/java/net/minecraft/server/FoodMetaData.java b/src/main/java/net/minecraft/server/FoodMetaData.java
index 0242c365ac..80e9d93844 100644
--- a/src/main/java/net/minecraft/server/FoodMetaData.java
+++ b/src/main/java/net/minecraft/server/FoodMetaData.java
@@ -55,15 +55,7 @@ public class FoodMetaData {
             ++this.foodTickTimer;
             if (this.foodTickTimer >= 80) {
                 if (entityhuman.getHealth() > 10 || i >= 3 || entityhuman.getHealth() > 1 && i >= 2) {
-                    // CraftBukkit start
-                    EntityDamageEvent event = new EntityDamageEvent(entityhuman.getBukkitEntity(), EntityDamageEvent.DamageCause.STARVATION, 1);
-                    entityhuman.world.getServer().getPluginManager().callEvent(event);
-
-                    if (!event.isCancelled()) {
-                        event.getEntity().setLastDamageCause(event);
-                        entityhuman.damageEntity(DamageSource.STARVE, event.getDamage());
-                    }
-                    // CraftBukkit end
+                    entityhuman.damageEntity(DamageSource.STARVE, 1);
                 }
 
                 this.foodTickTimer = 0;
diff --git a/src/main/java/net/minecraft/server/MobEffectList.java b/src/main/java/net/minecraft/server/MobEffectList.java
index 8ec6d25362..6a5a5f1755 100644
--- a/src/main/java/net/minecraft/server/MobEffectList.java
+++ b/src/main/java/net/minecraft/server/MobEffectList.java
@@ -2,7 +2,6 @@ package net.minecraft.server;
 
 // CraftBukkit start
 import org.bukkit.craftbukkit.event.CraftEventFactory;
-import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
 // CraftBukkit end
 
@@ -80,33 +79,15 @@ public class MobEffectList {
             }
         } else if (this.id == POISON.id) {
             if (entityliving.getHealth() > 1) {
-                // CraftBukkit start
-                EntityDamageEvent event = CraftEventFactory.callEntityDamageEvent(null, entityliving, EntityDamageEvent.DamageCause.POISON, 1);
-
-                if (!event.isCancelled() && event.getDamage() > 0) {
-                    entityliving.damageEntity(DamageSource.MAGIC, event.getDamage());
-                }
-                // CraftBukkit end
+                entityliving.damageEntity(CraftEventFactory.POISON, 1); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON
             }
         } else if (this.id == WITHER.id) {
-            // CraftBukkit start
-            EntityDamageEvent event = CraftEventFactory.callEntityDamageEvent(null, entityliving, EntityDamageEvent.DamageCause.WITHER, 1);
-
-            if (!event.isCancelled() && event.getDamage() > 0) {
-                entityliving.damageEntity(DamageSource.WITHER, event.getDamage());
-            }
-            // CraftBukkit end
+            entityliving.damageEntity(DamageSource.WITHER, 1);
         } else if (this.id == HUNGER.id && entityliving instanceof EntityHuman) {
             ((EntityHuman) entityliving).j(0.025F * (float) (i + 1));
         } else if ((this.id != HEAL.id || entityliving.bD()) && (this.id != HARM.id || !entityliving.bD())) {
             if (this.id == HARM.id && !entityliving.bD() || this.id == HEAL.id && entityliving.bD()) {
-                // CraftBukkit start
-                EntityDamageEvent event = CraftEventFactory.callEntityDamageEvent(null, entityliving, EntityDamageEvent.DamageCause.MAGIC, 6 << i);
-
-                if (!event.isCancelled() && event.getDamage() > 0) {
-                    entityliving.damageEntity(DamageSource.MAGIC, event.getDamage());
-                }
-                // CraftBukkit end
+                entityliving.damageEntity(DamageSource.MAGIC, 6 << i);
             }
         } else {
             entityliving.heal(6 << i, RegainReason.MAGIC); // CraftBukkit
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index f65b7f8598..07970c00d4 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -39,6 +39,7 @@ import org.bukkit.craftbukkit.entity.CraftLivingEntity;
 import org.bukkit.craftbukkit.entity.CraftPlayer;
 import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting;
 import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.util.CraftDamageSource;
 import org.bukkit.entity.AnimalTamer;
 import org.bukkit.entity.Arrow;
 import org.bukkit.entity.Creeper;
@@ -64,6 +65,9 @@ import org.bukkit.event.server.ServerListPingEvent;
 import org.bukkit.inventory.InventoryView;
 
 public class CraftEventFactory {
+    public static final DamageSource MELTING = CraftDamageSource.copyOf(DamageSource.BURN);
+    public static final DamageSource POISON = CraftDamageSource.copyOf(DamageSource.MAGIC);
+
     // helper methods
     private static boolean canBuild(CraftWorld world, Player player, int x, int z) {
         WorldServer worldServer = world.getHandle();
@@ -379,21 +383,58 @@ public class CraftEventFactory {
     }
 
     public static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSource source, int damage) {
-        Entity damager = source.getEntity();
-        DamageCause cause = DamageCause.ENTITY_ATTACK;
+        if (source instanceof EntityDamageSource) {
+            Entity damager = source.getEntity();
+            DamageCause cause = DamageCause.ENTITY_ATTACK;
 
-        if (source instanceof EntityDamageSourceIndirect) {
-            damager = ((EntityDamageSourceIndirect) source).getProximateDamageSource();
-            if (damager.getBukkitEntity() instanceof ThrownPotion) {
-                cause = DamageCause.MAGIC;
-            } else if (damager.getBukkitEntity() instanceof Projectile) {
-                cause = DamageCause.PROJECTILE;
+            if (source instanceof EntityDamageSourceIndirect) {
+                damager = ((EntityDamageSourceIndirect) source).getProximateDamageSource();
+                if (damager.getBukkitEntity() instanceof ThrownPotion) {
+                    cause = DamageCause.MAGIC;
+                } else if (damager.getBukkitEntity() instanceof Projectile) {
+                    cause = DamageCause.PROJECTILE;
+                }
+            } else if ("thorns".equals(source.translationIndex)) {
+                cause = DamageCause.THORNS;
             }
-        } else if ("thorns".equals(source.translationIndex)) {
-            cause = DamageCause.THORNS;
+
+            return callEntityDamageEvent(damager, entity, cause, damage);
+        } else if (source == DamageSource.OUT_OF_WORLD) {
+            EntityDamageEvent event = callEvent(new EntityDamageByBlockEvent(null, entity.getBukkitEntity(), DamageCause.VOID, damage));
+            if (!event.isCancelled()) {
+                event.getEntity().setLastDamageCause(event);
+            }
+            return event;
         }
 
-        return callEntityDamageEvent(damager, entity, cause, damage);
+        DamageCause cause = null;
+        if (source == DamageSource.FIRE) {
+            cause = DamageCause.FIRE;
+        } else if (source == DamageSource.STARVE) {
+            cause = DamageCause.STARVATION;
+        } else if (source == DamageSource.WITHER) {
+            cause = DamageCause.WITHER;
+        } else if (source == DamageSource.STUCK) {
+            cause = DamageCause.SUFFOCATION;
+        } else if (source == DamageSource.DROWN) {
+            cause = DamageCause.DROWNING;
+        } else if (source == DamageSource.BURN) {
+            cause = DamageCause.FIRE_TICK;
+        } else if (source == MELTING) {
+            cause = DamageCause.MELTING;
+        } else if (source == POISON) {
+            cause = DamageCause.POISON;
+        } else if (source == DamageSource.MAGIC) {
+            cause = DamageCause.MAGIC;
+        }
+
+        if (cause != null) {
+            return callEntityDamageEvent(null, entity, cause, damage);
+        }
+
+        // If an event was called earlier, we return null.
+        // EG: Cactus, Lava, EntityEnderPearl "fall", FallingSand
+        return null;
     }
 
     // Non-Living Entities such as EntityEnderCrystal need to call this
@@ -401,6 +442,7 @@ public class CraftEventFactory {
         if (!(source instanceof EntityDamageSource)) {
             return false;
         }
+        // We don't need to check for null, since EntityDamageSource will always return an event
         EntityDamageEvent event = handleEntityDamageEvent(entity, source, damage);
         return event.isCancelled() || event.getDamage() == 0;
     }
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftDamageSource.java b/src/main/java/org/bukkit/craftbukkit/util/CraftDamageSource.java
new file mode 100644
index 0000000000..3374fe2a9b
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftDamageSource.java
@@ -0,0 +1,31 @@
+package org.bukkit.craftbukkit.util;
+
+import net.minecraft.server.DamageSource;
+
+// Util class to create custom DamageSources.
+public final class CraftDamageSource extends DamageSource {
+    public static DamageSource copyOf(final DamageSource original) {
+        CraftDamageSource newSource = new CraftDamageSource(original.translationIndex);
+
+        // Check ignoresArmor
+        if (original.ignoresArmor()) {
+            newSource.j();
+        }
+
+        // Check magic
+        if (original.q()) {
+            newSource.r();
+        }
+
+        // Check fire
+        if (original.c()) {
+            newSource.l();
+        }
+
+        return newSource;
+    }
+
+    private CraftDamageSource(String identifier) {
+        super(identifier);
+    }
+}