
org.bukkit.event.entity.EntityDamageEvent Maven / Gradle / Ivy
package org.bukkit.event.entity;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.util.NumberConversions;
import java.util.EnumMap;
import java.util.Map;
/**
* Stores data for damage events
*/
public class EntityDamageEvent extends EntityEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private static final DamageModifier[] MODIFIERS = DamageModifier.values();
private static final Function super Double, Double> ZERO = Functions.constant(-0.0);
private final Map modifiers;
private final Map> modifierFunctions;
private final Map originals;
private final DamageCause cause;
private boolean cancelled;
@Deprecated
public EntityDamageEvent(final Entity damagee, final DamageCause cause, final int damage) {
this(damagee, cause, (double) damage);
}
@Deprecated
public EntityDamageEvent(final Entity damagee, final DamageCause cause, final double damage) {
this(damagee, cause, new EnumMap<>(ImmutableMap.of(DamageModifier.BASE, damage)), new EnumMap>(ImmutableMap.of(DamageModifier.BASE, ZERO)));
}
public EntityDamageEvent(final Entity damagee, final DamageCause cause, final Map modifiers, final Map> modifierFunctions) {
super(damagee);
Validate.isTrue(modifiers.containsKey(DamageModifier.BASE), "BASE DamageModifier missing");
Validate.isTrue(!modifiers.containsKey(null), "Cannot have null DamageModifier");
Validate.noNullElements(modifiers.values(), "Cannot have null modifier values");
Validate.isTrue(modifiers.keySet().equals(modifierFunctions.keySet()), "Must have a modifier function for each DamageModifier");
Validate.noNullElements(modifierFunctions.values(), "Cannot have null modifier function");
this.originals = new EnumMap(modifiers);
this.cause = cause;
this.modifiers = modifiers;
this.modifierFunctions = modifierFunctions;
}
public static HandlerList getHandlerList() {
return handlers;
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
/**
* Gets the original damage for the specified modifier, as defined at this
* event's construction.
*
* @param type the modifier
* @return the original damage
* @throws IllegalArgumentException if type is null
*/
public double getOriginalDamage(DamageModifier type) throws IllegalArgumentException {
final Double damage = originals.get(type);
if (damage != null) {
return damage;
}
if (type == null) {
throw new IllegalArgumentException("Cannot have null DamageModifier");
}
return 0;
}
/**
* Sets the damage for the specified modifier.
*
* @param type the damage modifier
* @param damage the scalar value of the damage's modifier
* @throws IllegalArgumentException if type is null
* @throws UnsupportedOperationException if the caller does not support
* the particular DamageModifier, or to rephrase, when {@link
* #isApplicable(DamageModifier)} returns false
* @see #getFinalDamage()
*/
public void setDamage(DamageModifier type, double damage) throws IllegalArgumentException, UnsupportedOperationException {
if (!modifiers.containsKey(type)) {
throw type == null ? new IllegalArgumentException("Cannot have null DamageModifier") : new UnsupportedOperationException(type + " is not applicable to " + getEntity());
}
modifiers.put(type, damage);
}
/**
* Gets the damage change for some modifier
*
* @param type the damage modifier
* @return The raw amount of damage caused by the event
* @throws IllegalArgumentException if type is null
* @see DamageModifier#BASE
*/
public double getDamage(DamageModifier type) throws IllegalArgumentException {
Validate.notNull(type, "Cannot have null DamageModifier");
final Double damage = modifiers.get(type);
return damage == null ? 0 : damage;
}
/**
* This checks to see if a particular modifier is valid for this event's
* caller, such that, {@link #setDamage(DamageModifier, double)} will not
* throw an {@link UnsupportedOperationException}.
*
* {@link DamageModifier#BASE} is always applicable.
*
* @param type the modifier
* @return true if the modifier is supported by the caller, false otherwise
* @throws IllegalArgumentException if type is null
*/
public boolean isApplicable(DamageModifier type) throws IllegalArgumentException {
Validate.notNull(type, "Cannot have null DamageModifier");
return modifiers.containsKey(type);
}
/**
* Gets the raw amount of damage caused by the event
*
* @return The raw amount of damage caused by the event
* @see DamageModifier#BASE
*/
public double getDamage() {
return getDamage(DamageModifier.BASE);
}
/**
* Sets the raw amount of damage caused by the event.
*
* For compatibility this also recalculates the modifiers and scales
* them by the difference between the modifier for the previous damage
* value and the new one.
*
* @param damage The raw amount of damage caused by the event
*/
public void setDamage(double damage) {
// These have to happen in the same order as the server calculates them, keep the enum sorted
double remaining = damage;
double oldRemaining = getDamage(DamageModifier.BASE);
for (DamageModifier modifier : MODIFIERS) {
if (!isApplicable(modifier)) {
continue;
}
Function super Double, Double> modifierFunction = modifierFunctions.get(modifier);
double newVanilla = modifierFunction.apply(remaining);
double oldVanilla = modifierFunction.apply(oldRemaining);
double difference = oldVanilla - newVanilla;
// Don't allow value to cross zero, assume zero values should be negative
double old = getDamage(modifier);
if (old > 0) {
setDamage(modifier, Math.max(0, old - difference));
} else {
setDamage(modifier, Math.min(0, old - difference));
}
remaining += newVanilla;
oldRemaining += oldVanilla;
}
setDamage(DamageModifier.BASE, damage);
}
/**
* Gets the amount of damage caused by the event after all damage
* reduction is applied.
*
* @return the amount of damage caused by the event
*/
public final double getFinalDamage() {
double damage = 0;
for (DamageModifier modifier : MODIFIERS) {
damage += getDamage(modifier);
}
return damage;
}
/**
* This method exists for legacy reasons to provide backwards
* compatibility. It will not exist at runtime and should not be used
* under any circumstances.
*
* @return the (rounded) damage
*/
@Deprecated
public int _INVALID_getDamage() {
return NumberConversions.ceil(getDamage());
}
/**
* This method exists for legacy reasons to provide backwards
* compatibility. It will not exist at runtime and should not be used
* under any circumstances.
*
* @param damage the new damage value
*/
@Deprecated
public void _INVALID_setDamage(int damage) {
setDamage(damage);
}
/**
* Gets the cause of the damage.
*
* @return A DamageCause value detailing the cause of the damage.
*/
public DamageCause getCause() {
return cause;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
/**
* An enum to specify the types of modifier
*/
public enum DamageModifier {
/**
* This represents the amount of damage being done, also known as the
* raw {@link EntityDamageEvent#getDamage()}.
*/
BASE,
/**
* This represents the damage reduced by a wearing a helmet when hit
* by a falling block.
*/
HARD_HAT,
/**
* This represents the damage reduction caused by blocking, only present for
* {@link Player Players}.
*/
BLOCKING,
/**
* This represents the damage reduction caused by wearing armor.
*/
ARMOR,
/**
* This represents the damage reduction caused by the Resistance potion effect.
*/
RESISTANCE,
/**
* This represents the damage reduction caused by the combination of:
*
* -
* Armor enchantments
*
-
* Witch's potion resistance
*
*
*/
MAGIC,
/**
* This represents the damage reduction caused by the absorption potion
* effect.
*/
ABSORPTION,
}
/**
* An enum to specify the cause of the damage
*/
public enum DamageCause {
/**
* Damage caused when an entity contacts a block such as a Cactus.
*
* Damage: 1 (Cactus)
*/
CONTACT,
/**
* Damage caused when an entity attacks another entity.
*
* Damage: variable
*/
ENTITY_ATTACK,
/**
* Damage caused when attacked by a projectile.
*
* Damage: variable
*/
PROJECTILE,
/**
* Damage caused by being put in a block
*
* Damage: 1
*/
SUFFOCATION,
/**
* Damage caused when an entity falls a distance greater than 3 blocks
*
* Damage: fall height - 3.0
*/
FALL,
/**
* Damage caused by direct exposure to fire
*
* Damage: 1
*/
FIRE,
/**
* Damage caused due to burns caused by fire
*
* Damage: 1
*/
FIRE_TICK,
/**
* Damage caused due to a snowman melting
*
* Damage: 1
*/
MELTING,
/**
* Damage caused by direct exposure to lava
*
* Damage: 4
*/
LAVA,
/**
* Damage caused by running out of air while in water
*
* Damage: 2
*/
DROWNING,
/**
* Damage caused by being in the area when a block explodes.
*
* Damage: variable
*/
BLOCK_EXPLOSION,
/**
* Damage caused by being in the area when an entity, such as a
* Creeper, explodes.
*
* Damage: variable
*/
ENTITY_EXPLOSION,
/**
* Damage caused by falling into the void
*
* Damage: 4 for players
*/
VOID,
/**
* Damage caused by being struck by lightning
*
* Damage: 5
*/
LIGHTNING,
/**
* Damage caused by committing suicide using the command "/kill"
*
* Damage: 1000
*/
SUICIDE,
/**
* Damage caused by starving due to having an empty hunger bar
*
* Damage: 1
*/
STARVATION,
/**
* Damage caused due to an ongoing poison effect
*
* Damage: 1
*/
POISON,
/**
* Damage caused by being hit by a damage potion or spell
*
* Damage: variable
*/
MAGIC,
/**
* Damage caused by Wither potion effect
*/
WITHER,
/**
* Damage caused by being hit by a falling block which deals damage
*
* Note: Not every block deals damage
*
* Damage: variable
*/
FALLING_BLOCK,
/**
* Damage caused in retaliation to another attack by the Thorns
* enchantment.
*
* Damage: 1-4 (Thorns)
*/
THORNS,
/**
* Custom damage.
*
* Damage: variable
*/
CUSTOM
}
}