diff --git a/pom.xml b/pom.xml index 2daa4be20dab..fe7ecda44ade 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,8 @@ true - 1.8 - 1.8 + 17 + 17 UTF-8 diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java index 645516326108..db45423936d4 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java @@ -14,6 +14,7 @@ import org.bukkit.block.Biome; import org.bukkit.block.banner.PatternType; import org.bukkit.boss.KeyedBossBar; +import org.bukkit.damage.DamageType; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Cat; import org.bukkit.entity.EntityType; @@ -207,6 +208,13 @@ public Iterator iterator() { */ @ApiStatus.Experimental Registry TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class); + /** + * Damage types. + * + * @see DamageType + */ + @ApiStatus.Experimental + Registry DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); /** * Villager profession. * diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java index 4a9a82540e40..6ca5f7a85087 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java @@ -5,6 +5,9 @@ import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.BlockData; +import org.bukkit.damage.DamageEffect; +import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageType; import org.bukkit.entity.EntityType; import org.bukkit.inventory.CreativeCategory; import org.bukkit.inventory.EquipmentSlot; @@ -13,6 +16,7 @@ import org.bukkit.plugin.InvalidPluginException; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,4 +104,18 @@ public interface UnsafeValues { * @return an internal potion data */ PotionType.InternalPotionData getInternalPotionData(NamespacedKey key); + + @ApiStatus.Internal + @Nullable + DamageEffect getDamageEffect(@NotNull String key); + + /** + * Create a new {@link DamageSource.Builder}. + * + * @param damageType the {@link DamageType} to use + * @return a {@link DamageSource.Builder} + */ + @ApiStatus.Internal + @NotNull + DamageSource.Builder createDamageSourceBuilder(@NotNull DamageType damageType); } diff --git a/src/main/java/org/bukkit/damage/DamageEffect.java b/src/main/java/org/bukkit/damage/DamageEffect.java new file mode 100644 index 000000000000..8cf8fde6020f --- /dev/null +++ b/src/main/java/org/bukkit/damage/DamageEffect.java @@ -0,0 +1,53 @@ +package org.bukkit.damage; + +import com.google.common.base.Preconditions; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a type of effect that occurs when damage is inflicted. Currently, + * effects only determine the sound that plays. + */ +@ApiStatus.Experimental +public interface DamageEffect { + + /** + * The default damage effect. + */ + public static final DamageEffect HURT = getDamageEffect("hurt"); + /** + * Thorns. + */ + public static final DamageEffect THORNS = getDamageEffect("thorns"); + /** + * Drowning. + */ + public static final DamageEffect DROWNING = getDamageEffect("drowning"); + /** + * A single burn tick (fire, lava, etc.). + */ + public static final DamageEffect BURNING = getDamageEffect("burning"); + /** + * Poked by a berry bush. + */ + public static final DamageEffect POKING = getDamageEffect("poking"); + /** + * Freeze tick (powder snow). + */ + public static final DamageEffect FREEZING = getDamageEffect("freezing"); + + @NotNull + private static DamageEffect getDamageEffect(@NotNull String key) { + return Preconditions.checkNotNull(Bukkit.getUnsafe().getDamageEffect(key), "No DamageEffect found for %s. This is a bug.", key); + } + + /** + * Get the {@link Sound} played for this {@link DamageEffect}. + * + * @return the sound + */ + @NotNull + public Sound getSound(); +} diff --git a/src/main/java/org/bukkit/damage/DamageScaling.java b/src/main/java/org/bukkit/damage/DamageScaling.java new file mode 100644 index 000000000000..1c8ad044d86d --- /dev/null +++ b/src/main/java/org/bukkit/damage/DamageScaling.java @@ -0,0 +1,26 @@ +package org.bukkit.damage; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; + +/** + * A means of damage scaling with respect to the server's difficulty. + */ +@ApiStatus.Experimental +public enum DamageScaling { + + /** + * Damage is not scaled. + */ + NEVER, + /** + * Damage is scaled only when the + * {@link DamageSource#getCausingEntity() causing entity} is not a + * {@link Player}. + */ + WHEN_CAUSED_BY_LIVING_NON_PLAYER, + /** + * Damage is always scaled. + */ + ALWAYS; +} diff --git a/src/main/java/org/bukkit/damage/DamageSource.java b/src/main/java/org/bukkit/damage/DamageSource.java new file mode 100644 index 000000000000..7635610e56c0 --- /dev/null +++ b/src/main/java/org/bukkit/damage/DamageSource.java @@ -0,0 +1,155 @@ +package org.bukkit.damage; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a source of damage. + */ +@ApiStatus.Experimental +public interface DamageSource { + + /** + * Get the {@link DamageType}. + * + * @return the damage type + */ + @NotNull + public DamageType getDamageType(); + + /** + * Get the {@link Entity} that caused the damage to occur. + *

+ * Not to be confused with {@link #getDirectEntity()}, the causing entity is + * the entity to which the damage is ultimately attributed if the receiver + * is killed. If, for example, the receiver was damaged by a projectile, the + * shooter/thrower would be returned. + * + * @return an Entity or null + */ + @Nullable + public Entity getCausingEntity(); + + /** + * Get the {@link Entity} that directly caused the damage. + *

+ * Not to be confused with {@link #getCausingEntity()}, the direct entity is + * the entity that actually inflicted the damage. If, for example, the + * receiver was damaged by a projectile, the projectile would be returned. + * + * @return an Entity or null + */ + @Nullable + public Entity getDirectEntity(); + + /** + * Get the {@link Location} from where the damage originated. This will only + * be present if an entity did not cause the damage. + * + * @return the location, or null if none + */ + @Nullable + public Location getDamageLocation(); + + /** + * Get the {@link Location} from where the damage originated. + *

+ * This is a convenience method to get the final location of the damage. + * This method will attempt to return + * {@link #getDamageLocation() the damage location}. If this is null, the + * {@link #getCausingEntity() causing entity location} will be returned. + * Finally if there is no damage location nor a causing entity, null will be + * returned. + * + * @return the source of the location or null. + */ + @Nullable + public Location getSourceLocation(); + + /** + * Get if this damage is indirect. + *

+ * Damage is considered indirect if {@link #getCausingEntity()} is not equal + * to {@link #getDirectEntity()}. This will be the case, for example, if a + * skeleton shot an arrow or a player threw a potion. + * + * @return {@code true} if is indirect, {@code false} otherwise. + */ + public boolean isIndirect(); + + /** + * Get the amount of hunger exhaustion caused by this damage. + * + * @return the amount of hunger exhaustion caused. + */ + public float getFoodExhaustion(); + + /** + * Gets if this source of damage scales with difficulty. + * + * @return {@code True} if scales. + */ + public boolean scalesWithDifficulty(); + + /** + * Create a new {@link DamageSource.Builder}. + * + * @param damageType the {@link DamageType} to use + * @return a {@link DamageSource.Builder} + */ + @NotNull + @SuppressWarnings("deprecation") + public static Builder builder(@NotNull DamageType damageType) { + return Bukkit.getUnsafe().createDamageSourceBuilder(damageType); + } + + /** + * Utility class to make building a {@link DamageSource} easier. Only a + * {@link DamageType} is required. + */ + public static interface Builder { + + /** + * Set the {@link Entity} that caused the damage. + * + * @param entity the entity + * @return this instance. Allows for chained method calls + * @see DamageSource#getCausingEntity() + */ + @NotNull + public Builder withCausingEntity(@NotNull Entity entity); + + /** + * Set the {@link Entity} that directly inflicted the damage. + * + * @param entity the entity + * @return this instance. Allows for chained method calls + * @see DamageSource#getDirectEntity() + */ + @NotNull + public Builder withDirectEntity(@NotNull Entity entity); + + /** + * Set the {@link Location} of the source of damage. + * + * @param location the location where the damage occurred + * @return this instance. Allows for chained method calls + * @see DamageSource#getSourceLocation() + */ + @NotNull + public Builder withDamageLocation(@NotNull Location location); + + /** + * Create a new {@link DamageSource} instance using the supplied + * parameters. + * + * @return the damage source instance + */ + @NotNull + public DamageSource build(); + } +} diff --git a/src/main/java/org/bukkit/damage/DamageType.java b/src/main/java/org/bukkit/damage/DamageType.java new file mode 100644 index 000000000000..5fef0f8b7957 --- /dev/null +++ b/src/main/java/org/bukkit/damage/DamageType.java @@ -0,0 +1,117 @@ +package org.bukkit.damage; + +import com.google.common.base.Preconditions; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.Translatable; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Represent a type of damage that an entity can receive. + *

+ * Constants in this class include the base types provided by the vanilla + * server. Data packs are capable of registering more types of damage which may + * be obtained through the {@link Registry#DAMAGE_TYPE}. + * + * @see Minecraft Wiki + */ +@ApiStatus.Experimental +public interface DamageType extends Keyed, Translatable { + + public static final DamageType IN_FIRE = getDamageType("in_fire"); + public static final DamageType LIGHTNING_BOLT = getDamageType("lightning_bolt"); + public static final DamageType ON_FIRE = getDamageType("on_fire"); + public static final DamageType LAVA = getDamageType("lava"); + public static final DamageType HOT_FLOOR = getDamageType("hot_floor"); + public static final DamageType IN_WALL = getDamageType("in_wall"); + public static final DamageType CRAMMING = getDamageType("cramming"); + public static final DamageType DROWN = getDamageType("drown"); + public static final DamageType STARVE = getDamageType("starve"); + public static final DamageType CACTUS = getDamageType("cactus"); + public static final DamageType FALL = getDamageType("fall"); + public static final DamageType FLY_INTO_WALL = getDamageType("fly_into_wall"); + public static final DamageType OUT_OF_WORLD = getDamageType("out_of_world"); + public static final DamageType GENERIC = getDamageType("generic"); + public static final DamageType MAGIC = getDamageType("magic"); + public static final DamageType WITHER = getDamageType("wither"); + public static final DamageType DRAGON_BREATH = getDamageType("dragon_breath"); + public static final DamageType DRY_OUT = getDamageType("dry_out"); + public static final DamageType SWEET_BERRY_BUSH = getDamageType("sweet_berry_bush"); + public static final DamageType FREEZE = getDamageType("freeze"); + public static final DamageType STALAGMITE = getDamageType("stalagmite"); + public static final DamageType FALLING_BLOCK = getDamageType("falling_block"); + public static final DamageType FALLING_ANVIL = getDamageType("falling_anvil"); + public static final DamageType FALLING_STALACTITE = getDamageType("falling_stalactite"); + public static final DamageType STING = getDamageType("sting"); + public static final DamageType MOB_ATTACK = getDamageType("mob_attack"); + public static final DamageType MOB_ATTACK_NO_AGGRO = getDamageType("mob_attack_no_aggro"); + public static final DamageType PLAYER_ATTACK = getDamageType("player_attack"); + public static final DamageType ARROW = getDamageType("arrow"); + public static final DamageType TRIDENT = getDamageType("trident"); + public static final DamageType MOB_PROJECTILE = getDamageType("mob_projectile"); + public static final DamageType FIREWORKS = getDamageType("fireworks"); + public static final DamageType FIREBALL = getDamageType("fireball"); + public static final DamageType UNATTRIBUTED_FIREBALL = getDamageType("unattributed_fireball"); + public static final DamageType WITHER_SKULL = getDamageType("wither_skull"); + public static final DamageType THROWN = getDamageType("thrown"); + public static final DamageType INDIRECT_MAGIC = getDamageType("indirect_magic"); + public static final DamageType THORNS = getDamageType("thorns"); + public static final DamageType EXPLOSION = getDamageType("explosion"); + public static final DamageType PLAYER_EXPLOSION = getDamageType("player_explosion"); + public static final DamageType SONIC_BOOM = getDamageType("sonic_boom"); + public static final DamageType BAD_RESPAWN_POINT = getDamageType("bad_respawn_point"); + public static final DamageType OUTSIDE_BORDER = getDamageType("outside_border"); + public static final DamageType GENERIC_KILL = getDamageType("generic_kill"); + + @NotNull + private static DamageType getDamageType(@NotNull String key) { + NamespacedKey namespacedKey = NamespacedKey.minecraft(key); + return Preconditions.checkNotNull(Registry.DAMAGE_TYPE.get(namespacedKey), "No DamageType found for %s. This is a bug.", namespacedKey); + } + + /** + * {@inheritDoc} + *

+ * The returned key is that of the death message sent when this damage type + * is responsible for the death of an entity. + *

+ * Note This translation key is only used if + * {@link #getDeathMessageType()} is {@link DeathMessageType#DEFAULT} + */ + @NotNull + @Override + public String getTranslationKey(); + + /** + * Get the {@link DamageScaling} for this damage type. + * + * @return the damage scaling + */ + @NotNull + public DamageScaling getDamageScaling(); + + /** + * Get the {@link DamageEffect} for this damage type. + * + * @return the damage effect + */ + @NotNull + public DamageEffect getDamageEffect(); + + /** + * Get the {@link DeathMessageType} for this damage type. + * + * @return the death message type + */ + @NotNull + public DeathMessageType getDeathMessageType(); + + /** + * Get the amount of hunger exhaustion caused by this damage type. + * + * @return the exhaustion + */ + public float getExhaustion(); +} diff --git a/src/main/java/org/bukkit/damage/DeathMessageType.java b/src/main/java/org/bukkit/damage/DeathMessageType.java new file mode 100644 index 000000000000..e182eb4df2ab --- /dev/null +++ b/src/main/java/org/bukkit/damage/DeathMessageType.java @@ -0,0 +1,26 @@ +package org.bukkit.damage; + +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents a type of death message used by a {@link DamageSource}. + */ +@ApiStatus.Experimental +public enum DeathMessageType { + + /** + * No special death message logic is applied. + */ + DEFAULT, + /** + * Shows a variant of fall damage death instead of a regular death message. + *
+ * Example: death.fell.assist.item + */ + FALL_VARIANTS, + /** + * Shows the intentional game design death message instead of a regular + * death message. + */ + INTENTIONAL_GAME_DESIGN; +} diff --git a/src/main/java/org/bukkit/damage/package-info.java b/src/main/java/org/bukkit/damage/package-info.java new file mode 100644 index 000000000000..c2ff9942be2a --- /dev/null +++ b/src/main/java/org/bukkit/damage/package-info.java @@ -0,0 +1,5 @@ +/** + * Classes concerning damage types and sources applicable to living entities. + */ +@org.jetbrains.annotations.ApiStatus.Experimental +package org.bukkit.damage; diff --git a/src/main/java/org/bukkit/entity/Damageable.java b/src/main/java/org/bukkit/entity/Damageable.java index a9341849945f..c4537080ee18 100644 --- a/src/main/java/org/bukkit/entity/Damageable.java +++ b/src/main/java/org/bukkit/entity/Damageable.java @@ -1,6 +1,9 @@ package org.bukkit.entity; import org.bukkit.attribute.Attribute; +import org.bukkit.damage.DamageSource; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -15,14 +18,24 @@ public interface Damageable extends Entity { void damage(double amount); /** - * Deals the given amount of damage to this entity, from a specified - * entity. + * Deals the given amount of damage to this entity from a specified + * {@link Entity}. * - * @param amount Amount of damage to deal - * @param source Entity which to attribute this damage from + * @param amount amount of damage to deal + * @param source entity to which the damage should be attributed */ void damage(double amount, @Nullable Entity source); + /** + * Deals the given amount of damage to this entity from a specified + * {@link DamageSource}. + * + * @param amount amount of damage to deal + * @param damageSource source to which the damage should be attributed + */ + @ApiStatus.Experimental + void damage(double amount, @NotNull DamageSource damageSource); + /** * Gets the entity's health from 0 to {@link #getMaxHealth()}, where 0 is dead. * diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java index 461727dc7f06..5ba9f7edf3bb 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByBlockEvent.java @@ -3,6 +3,7 @@ import com.google.common.base.Function; import java.util.Map; import org.bukkit.block.Block; +import org.bukkit.damage.DamageSource; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -13,13 +14,13 @@ public class EntityDamageByBlockEvent extends EntityDamageEvent { private final Block damager; - public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { - super(damagee, cause, damage); + public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, final double damage) { + super(damagee, cause, damageSource, damage); this.damager = damager; } - public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { - super(damagee, cause, modifiers, modifierFunctions); + public EntityDamageByBlockEvent(@Nullable final Block damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { + super(damagee, cause, damageSource, modifiers, modifierFunctions); this.damager = damager; } diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java index 869bad7405ec..0a43b1ffdb03 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java @@ -2,6 +2,7 @@ import com.google.common.base.Function; import java.util.Map; +import org.bukkit.damage.DamageSource; import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; @@ -11,13 +12,13 @@ public class EntityDamageByEntityEvent extends EntityDamageEvent { private final Entity damager; - public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { - super(damagee, cause, damage); + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, final double damage) { + super(damagee, cause, damageSource, damage); this.damager = damager; } - public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { - super(damagee, cause, modifiers, modifierFunctions); + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { + super(damagee, cause, damageSource, modifiers, modifierFunctions); this.damager = damager; } diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java index 4773f537dec2..3b20000d9ac3 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java @@ -9,6 +9,7 @@ import java.util.Objects; import org.bukkit.Material; import org.bukkit.WorldBorder; +import org.bukkit.damage.DamageSource; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -27,12 +28,13 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable { private final Map originals; private boolean cancelled; private final DamageCause cause; + private final DamageSource damageSource; - public EntityDamageEvent(@NotNull final Entity damagee, @NotNull 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(@NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, final double damage) { + this(damagee, cause, damageSource, new EnumMap(ImmutableMap.of(DamageModifier.BASE, damage)), new EnumMap>(ImmutableMap.of(DamageModifier.BASE, ZERO))); } - public EntityDamageEvent(@NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { + public EntityDamageEvent(@NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final DamageSource damageSource, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { super(damagee); Preconditions.checkArgument(modifiers.containsKey(DamageModifier.BASE), "BASE DamageModifier missing"); Preconditions.checkArgument(!modifiers.containsKey(null), "Cannot have null DamageModifier"); @@ -43,6 +45,7 @@ public EntityDamageEvent(@NotNull final Entity damagee, @NotNull final DamageCau this.cause = cause; this.modifiers = modifiers; this.modifierFunctions = modifierFunctions; + this.damageSource = damageSource; } @Override @@ -64,14 +67,9 @@ public void setCancelled(boolean cancel) { * @throws IllegalArgumentException if type is null */ public double getOriginalDamage(@NotNull DamageModifier type) throws IllegalArgumentException { + Preconditions.checkArgument(type != null, "Cannot have null DamageModifier"); final Double damage = originals.get(type); - if (damage != null) { - return damage; - } - if (type == null) { - throw new IllegalArgumentException("Cannot have null DamageModifier"); - } - return 0; + return (damage != null) ? damage : 0; } /** @@ -86,8 +84,9 @@ public double getOriginalDamage(@NotNull DamageModifier type) throws IllegalArgu * @see #getFinalDamage() */ public void setDamage(@NotNull DamageModifier type, double damage) throws IllegalArgumentException, UnsupportedOperationException { + Preconditions.checkArgument(type != null, "Cannot have null DamageModifier"); if (!modifiers.containsKey(type)) { - throw type == null ? new IllegalArgumentException("Cannot have null DamageModifier") : new UnsupportedOperationException(type + " is not applicable to " + getEntity()); + throw new UnsupportedOperationException(type + " is not applicable to " + getEntity()); } modifiers.put(type, damage); } @@ -185,14 +184,32 @@ public void setDamage(double damage) { /** * Gets the cause of the damage. + *

+ * While a DamageCause may indicate a specific Bukkit-assigned cause of damage, + * {@link #getDamageSource()} may expose additional types of damage such as custom + * damage types provided by data packs, as well as any direct or indirect entities, + * locations, or other contributing factors to the damage being inflicted. The + * alternative is generally preferred, but DamageCauses provided to this event + * should largely encompass most common use cases for developers if a simple cause + * is required. * - * @return A DamageCause value detailing the cause of the damage. + * @return a DamageCause value detailing the cause of the damage. */ @NotNull public DamageCause getCause() { return cause; } + /** + * Get the source of damage. + * + * @return a DamageSource detailing the source of the damage. + */ + @NotNull + public DamageSource getDamageSource() { + return damageSource; + } + @NotNull @Override public HandlerList getHandlers() { @@ -210,7 +227,7 @@ public static HandlerList getHandlerList() { * @deprecated This API is responsible for a large number of implementation * problems and is in general unsustainable to maintain. It is likely to be * removed very soon in a subsequent release. Please see - * https://www.spigotmc.org/threads/194446/ for more information. + * this thread for more information. */ @Deprecated public enum DamageModifier {