diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageFunction.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageFunction.java
deleted file mode 100644
index 6efb3adc728..00000000000
--- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageFunction.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event.cause.entity.damage;
-
-import org.checkerframework.checker.nullness.qual.Nullable;
-
-import java.util.Objects;
-import java.util.StringJoiner;
-import java.util.function.DoubleUnaryOperator;
-
-public class DamageFunction implements ModifierFunction {
-
- public static final DoubleUnaryOperator ZERO_DAMAGE = value -> 0.0D;
-
- /**
- * Constructs a new damage function.
- *
- * @param first The damage modifier to use
- * @param second The unary operator to use
- * @return The resulting damage function
- */
- public static DamageFunction of(final DamageModifier first, final DoubleUnaryOperator second) {
- return new DamageFunction(first, second);
- }
-
- private final DamageModifier modifier;
- private final DoubleUnaryOperator function;
-
- /**
- * Creates a new {@link DamageFunction} with the provided
- * {@link DamageModifier}. The caveat is that the provided
- * {@link DamageFunction} is by default going to provide {@code 0}
- * damage modifications.
- *
- * @param modifier The damage modifier
- */
- public DamageFunction(final DamageModifier modifier) {
- this(modifier, DamageFunction.ZERO_DAMAGE);
- }
-
- /**
- * Creates a new {@link DamageFunction} with the provided
- * {@link DamageModifier} and {@link DoubleUnaryOperator}.
- *
- * @param modifier The modifier
- * @param function The function
- */
- public DamageFunction(final DamageModifier modifier, final DoubleUnaryOperator function) {
- this.modifier = java.util.Objects.requireNonNull(modifier, "modifier");
- this.function = java.util.Objects.requireNonNull(function, "function");
- }
-
- /**
- * Gets the {@link DamageModifier} for this function.
- *
- * @return The damage modifier
- */
- @Override
- public DamageModifier modifier() {
- return this.modifier;
- }
-
- /**
- * Gets the {@link DoubleUnaryOperator} for this function.
- *
- * @return The damage function
- */
- @Override
- public DoubleUnaryOperator function() {
- return this.function;
- }
-
- @Override
- public String toString() {
- return new StringJoiner(",", DamageFunction.class.getSimpleName() + "[", "]")
- .add("modifier=" + this.modifier())
- .add("function=" + this.function())
- .toString();
- }
-
- @Override
- public boolean equals(final @Nullable Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || this.getClass() != o.getClass()) {
- return false;
- }
- final DamageFunction that = (DamageFunction) o;
- return Objects.equals(this.modifier, that.modifier)
- && Objects.equals(this.function, that.function);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.modifier, this.function);
- }
-}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifier.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifier.java
index 19079591c34..1e7a0284b49 100644
--- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifier.java
+++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifier.java
@@ -24,271 +24,18 @@
*/
package org.spongepowered.api.event.cause.entity.damage;
-import org.checkerframework.checker.nullness.qual.Nullable;
-import org.spongepowered.api.entity.Entity;
-import org.spongepowered.api.event.Cause;
-import org.spongepowered.api.item.ItemTypes;
-import org.spongepowered.api.item.enchantment.Enchantment;
-import org.spongepowered.api.item.inventory.ItemStack;
-import org.spongepowered.api.item.inventory.ItemStackLike;
-import org.spongepowered.api.item.inventory.ItemStackSnapshot;
-import org.spongepowered.api.util.CopyableBuilder;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.StringJoiner;
-import java.util.function.DoubleUnaryOperator;
-import java.util.function.Supplier;
-
/**
- * Represents a modifier that will apply a function on a damage value to deal
- * towards an entity such that the raw damage is the input of a
- * {@link DoubleUnaryOperator} such that the output will be the final damage
- * applied to the {@link Entity}.
+ * A damage modifier that will be applied before or after a {@link DamageStep}.
*/
+@FunctionalInterface
public interface DamageModifier {
/**
- * Creates a new {@link Builder} for constructing a {@link DamageModifier}.
- *
- * @return A new builder
- */
- static Builder builder() {
- return new Builder();
- }
-
- /**
- * Gets the {@link DamageModifierType} for this {@link DamageModifier}.
- *
- * @return The damage modifier type
- */
- DamageModifierType type();
-
- /**
- * Returns the damage modifier group.
- * Grouped modifiers calculate their damage independently from each other
- *
- * @return The damage modifier group
- */
- String group();
-
- /**
- * Gets the cause of this {@link DamageModifier}.
- *
- * @return The cause of this damage modifier
- */
- Cause cause();
-
- /**
- * Gets the contributing {@link ItemStackSnapshot} that provided the
- * "reason" for this {@link DamageModifier} to exist. An example of a
- * contributing {@link ItemStack} is if an {@link ItemTypes#DIAMOND_SWORD}
- * provided an {@link Enchantment} that provided a
- * {@link DamageModifierTypes#WEAPON_ENCHANTMENT}, this modifier would have
- * the {@link ItemStackSnapshot} for the weapon used. Some modifiers however,
- * do not require an {@link ItemStack} to be the contributing factor for
- * this modifier to exist.
+ * Modifies the damage.
*
- * @return The contributing item, if available
+ * @param step The damage step this modifier is associated with.
+ * @param damage The current damage value.
+ * @return The next damage value
*/
- Optional contributingItem();
-
- /**
- * A builder that creates {@link DamageModifier}s, for use in both plugin and
- * implementation requirements.
- */
- final class Builder implements org.spongepowered.api.util.Builder, CopyableBuilder {
-
- @Nullable DamageModifierType type;
- @Nullable Cause cause;
- @Nullable String group;
- @Nullable ItemStackSnapshot snapshot;
-
- Builder() {
- }
-
-
- /**
- * Sets the {@link DamageModifierType} for the {@link DamageModifier} to
- * build.
- *
- * @param damageModifierType The damage modifier type
- * @return This builder, for chaining
- */
- public Builder type(final Supplier extends DamageModifierType> damageModifierType) {
- return this.type(damageModifierType.get());
- }
-
- /**
- * Sets the {@link DamageModifierType} for the {@link DamageModifier} to
- * build.
- *
- * @param damageModifierType The damage modifier type
- * @return This builder, for chaining
- */
- public Builder type(final DamageModifierType damageModifierType) {
- this.type = java.util.Objects.requireNonNull(damageModifierType);
- return this;
- }
-
- /**
- * The main attack damage calculated for an {@link org.spongepowered.api.event.entity.AttackEntityEvent}
- *
- * @return This builder, for chaining
- */
- public Builder attackDamageGroup() {
- return this.group("minecraft:attack_damage");
- }
-
- /**
- * The enchantment attack damage calculated for an {@link org.spongepowered.api.event.entity.AttackEntityEvent}
- *
- * @return This builder, for chaining
- */
- public Builder attackEnchantmentGroup() {
- return this.group("minecraft:attack_enchantment");
- }
-
- /**
- * The damage calculated for an {@link org.spongepowered.api.event.entity.DamageEntityEvent}
- *
- * @return This builder, for chaining
- */
- public Builder damageReductionGroup() {
- return this.group("minecraft:damage_reduction");
- }
-
- public Builder group(final String group) {
- this.group = group;
- return this;
- }
-
- /**
- * @deprecated Use {@link #item(ItemStackLike)} instead.
- */
- @Deprecated(forRemoval = true)
- public Builder item(final ItemStack itemStack) {
- return this.item((ItemStackLike) itemStack);
- }
-
- /**
- * @deprecated Use {@link #item(ItemStackLike)} instead.
- */
- @Deprecated(forRemoval = true)
- public Builder item(final ItemStackSnapshot snapshot) {
- return this.item((ItemStackLike) snapshot);
- }
-
- public Builder item(final ItemStackLike item) {
- this.snapshot = java.util.Objects.requireNonNull(item, "item").asImmutable();
- return this;
- }
-
- /**
- * Sets the {@link Cause} for the {@link DamageModifier} to build.
- *
- * @param cause The cause for the damage modifier
- * @return This builder, for chaining
- */
- public Builder cause(final Cause cause) {
- this.cause = java.util.Objects.requireNonNull(cause);
- return this;
- }
-
- /**
- * Creates a new {@link DamageModifier} with this builder's provided
- * {@link Cause} and {@link DamageModifierType}.
- *
- * @return The newly created damage modifier
- */
- @Override
- public DamageModifier build() {
- if (this.type == null) {
- throw new IllegalStateException("The DamageModifierType must not be null!");
- }
- if (this.cause == null) {
- throw new IllegalStateException("The cause for the DamageModifier must not be null!");
- }
- return new ImplementedDamageModifier(this);
- }
-
- @Override
- public Builder from(final DamageModifier value) {
- this.type = value.type();
- this.cause = value.cause();
- this.snapshot = value.contributingItem().orElse(null);
- return this;
- }
-
- @Override
- public Builder reset() {
- this.type = null;
- this.cause = null;
- return this;
- }
-
-
- private static class ImplementedDamageModifier implements DamageModifier {
- private final DamageModifierType type;
- private final Cause cause;
- @Nullable private final ItemStackSnapshot snapshot;
- private final String group;
-
- ImplementedDamageModifier(final Builder builder) {
- this.type = java.util.Objects.requireNonNull(builder.type, "DamageType is null!");
- this.cause = java.util.Objects.requireNonNull(builder.cause, "Cause is null!");
- this.group = java.util.Objects.requireNonNull(builder.group, "Group is null!");
- this.snapshot = builder.snapshot;
- }
-
- @Override
- public DamageModifierType type() {
- return this.type;
- }
-
- @Override
- public Cause cause() {
- return this.cause;
- }
-
- @Override
- public Optional contributingItem() {
- return Optional.ofNullable(this.snapshot);
- }
-
- @Override
- public String group() {
- return group;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.type, this.cause);
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || this.getClass() != obj.getClass()) {
- return false;
- }
- final ImplementedDamageModifier other = (ImplementedDamageModifier) obj;
- return Objects.equals(this.type, other.type)
- && Objects.equals(this.cause, other.cause)
- && Objects.equals(this.snapshot, other.snapshot);
- }
-
- @Override
- public String toString() {
- return new StringJoiner(", ", "DamageModifier[", "]")
- .add("type=" + this.type)
- .add("cause=" + this.cause)
- .add("snapshot=" + this.snapshot)
- .toString();
- }
- }
-
- }
+ double modify(DamageStep step, double damage);
}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierTypes.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierTypes.java
deleted file mode 100644
index 69fe4d3804f..00000000000
--- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierTypes.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event.cause.entity.damage;
-
-import org.spongepowered.api.ResourceKey;
-import org.spongepowered.api.Sponge;
-import org.spongepowered.api.effect.potion.PotionEffect;
-import org.spongepowered.api.effect.potion.PotionEffectType;
-import org.spongepowered.api.effect.potion.PotionEffectTypes;
-import org.spongepowered.api.entity.Entity;
-import org.spongepowered.api.entity.living.player.Player;
-import org.spongepowered.api.event.cause.entity.damage.source.DamageSource;
-import org.spongepowered.api.item.enchantment.Enchantment;
-import org.spongepowered.api.item.enchantment.EnchantmentType;
-import org.spongepowered.api.item.inventory.ItemStack;
-import org.spongepowered.api.item.inventory.ItemStackSnapshot;
-import org.spongepowered.api.registry.DefaultedRegistryReference;
-import org.spongepowered.api.registry.Registry;
-import org.spongepowered.api.registry.RegistryKey;
-import org.spongepowered.api.registry.RegistryScope;
-import org.spongepowered.api.registry.RegistryScopes;
-import org.spongepowered.api.registry.RegistryTypes;
-import org.spongepowered.api.world.World;
-import org.spongepowered.api.world.difficulty.Difficulty;
-
-@SuppressWarnings("unused")
-@RegistryScopes(scopes = RegistryScope.GAME)
-public final class DamageModifierTypes {
-
- // @formatter:off
-
- // SORTFIELDS:ON
-
- /**
- * Represents a {@link DamageModifier} that "absorbs" damage based on
- * the {@link PotionEffectTypes#ABSORPTION} level on the
- * {@link Entity}.
- */
- public static final DefaultedRegistryReference ABSORPTION = DamageModifierTypes.key(ResourceKey.sponge("absorption"));
-
- /**
- * Represents a {@link DamageModifier} that will reduce damage based on
- * the armor {@link ItemStack}s.
- */
- public static final DefaultedRegistryReference ARMOR = DamageModifierTypes.key(ResourceKey.sponge("armor"));
-
- /**
- * Represents a {@link DamageModifier} that will reduce damage based on
- * the {@link EnchantmentType}s applicable to an {@link ItemStack} that is
- * considered to be "armor" currently equipped on the owner.
- *
- * Usually, within the {@link DamageModifier#cause ()} will reside
- * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
- * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
- * incoming/outgoing damage. There can be multiple {@link DamageModifier}s
- * of this type in a single event due to the variety of possibilities in
- * customization of armor handling.
- */
- public static final DefaultedRegistryReference ARMOR_ENCHANTMENT = DamageModifierTypes.key(ResourceKey.sponge("armor_enchantment"));
-
- /**
- * Represents the {@link DamageModifier} that will reduce damage from a
- * {@link Player} if their attack cooldown has not been completed yet.
- */
- public static final DefaultedRegistryReference ATTACK_COOLDOWN = DamageModifierTypes.key(ResourceKey.sponge("attack_cooldown"));
-
- /**
- * Represents a {@link DamageModifier} that will modify damage from the attacks strength.
- * For vanilla this only reduces damage when repeating attacks too quickly
- */
- public static final DefaultedRegistryReference ATTACK_STRENGTH = DamageModifierTypes.key(ResourceKey.sponge("attack_strength"));
-
- /**
- * Represents the {@link DamageModifier} that will modify damage output
- * based on the fact that the attacking source is critically hitting the
- * target.
- */
- public static final DefaultedRegistryReference CRITICAL_HIT = DamageModifierTypes.key(ResourceKey.sponge("critical_hit"));
-
- /**
- * Represents a {@link DamageModifier} that will reduce damage based on
- * the {@link PotionEffectTypes#RESISTANCE} or any other
- * {@link PotionEffectType} that can be deemed as reducing incoming damage.
- *
- * Usually, within the {@link DamageModifier#cause ()} will reside
- * a {@link PotionEffect} including the amplifier and duration, signifying
- * that the {@link PotionEffectType} is modifying the incoming damage.
- */
- public static final DefaultedRegistryReference DEFENSIVE_POTION_EFFECT = DamageModifierTypes.key(ResourceKey.sponge("defensive_potion_effect"));
-
- /**
- * Represents a {@link DamageModifier} that enhances damage based on the
- * current {@link Difficulty} of the {@link World}.
- */
- public static final DefaultedRegistryReference DIFFICULTY = DamageModifierTypes.key(ResourceKey.sponge("difficulty"));
-
- /**
- * Represents a {@link DamageModifier} that will modify freezing damage.
- * E.g. {@link org.spongepowered.api.entity.living.monster.Blaze} take more damage from freezing sources.
- */
- public static final DefaultedRegistryReference FREEZING_BONUS = DamageModifierTypes.key(ResourceKey.sponge("freezing_bonus"));
-
-
- /**
- * Represents the {@link DamageModifier} that will modify damage from
- * a {@link DamageSource#source()} that is a {@link org.spongepowered.api.entity.FallingBlock}.
- *
- * Usually, within the {@link DamageModifier#cause ()} will reside
- * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
- * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
- * incoming/outgoing damage.
- */
- public static final DefaultedRegistryReference HARD_HAT = DamageModifierTypes.key(ResourceKey.sponge("hard_hat"));
-
- /**
- * Represents a {@link DamageModifier} that will modify damage based on
- * magic.
- */
- public static final DefaultedRegistryReference MAGIC = DamageModifierTypes.key(ResourceKey.sponge("magic"));
-
- /**
- * Represents a {@link DamageModifier} that will reduce outgoing damage
- * based on a {@link PotionEffect}.
- *
- * Usually, within the {@link DamageModifier#cause ()} will reside
- * a {@link PotionEffect} including the amplifier and duration, signifying
- * that the {@link PotionEffectType} is reducing the outgoing damage.
- */
- public static final DefaultedRegistryReference NEGATIVE_POTION_EFFECT = DamageModifierTypes.key(ResourceKey.sponge("negative_potion_effect"));
-
- /**
- * Represents the {@link DamageModifier} that will increase damage from
- * a {@link PotionEffect} affecting the attacker.
- */
- public static final DefaultedRegistryReference OFFENSIVE_POTION_EFFECT = DamageModifierTypes.key(ResourceKey.sponge("offensive_potion_effect"));
-
- /**
- * Represents a {@link DamageModifier} that will reduce damage due to using a shield.
- */
- public static final DefaultedRegistryReference SHIELD = DamageModifierTypes.key(ResourceKey.sponge("shield"));
-
- /**
- * Represents a {@link DamageModifier} that is applied for a sweeping attack.
- */
- public static final DefaultedRegistryReference SWEEPING = DamageModifierTypes.key(ResourceKey.sponge("sweeping"));
-
- /**
- * Represents a {@link DamageModifier} that will add bonus damage based on the weapon used.
- */
- public static final DefaultedRegistryReference WEAPON_BONUS = DamageModifierTypes.key(ResourceKey.sponge("weapon_bonus"));
-
- /**
- * Represents the {@link DamageModifier} that will modify damage from
- * an {@link EnchantmentType} on an equipped {@link ItemStack}.
- *
- * Usually, within the {@link DamageModifier#cause ()} will reside
- * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
- * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
- * incoming/outgoing damage.
- */
- public static final DefaultedRegistryReference WEAPON_ENCHANTMENT = DamageModifierTypes.key(ResourceKey.sponge("weapon_enchantment"));
-
- // SORTFIELDS:OFF
-
- // @formatter:on
-
- private DamageModifierTypes() {
- }
-
- public static Registry registry() {
- return Sponge.game().registry(RegistryTypes.DAMAGE_MODIFIER_TYPE);
- }
-
- private static DefaultedRegistryReference key(final ResourceKey location) {
- return RegistryKey.of(RegistryTypes.DAMAGE_MODIFIER_TYPE, location).asDefaultedReference(Sponge::game);
- }
-}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStep.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStep.java
new file mode 100644
index 00000000000..bdb84430473
--- /dev/null
+++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStep.java
@@ -0,0 +1,121 @@
+/*
+ * This file is part of SpongeAPI, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) SpongePowered
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.spongepowered.api.event.cause.entity.damage;
+
+import org.spongepowered.api.event.Cause;
+
+import java.util.List;
+
+/**
+ * Represents a step in the damage calculation.
+ */
+public interface DamageStep {
+
+ /**
+ * Gets the {@link DamageStepType} for this {@link DamageStep}.
+ *
+ * @return The damage step type
+ */
+ DamageStepType type();
+
+ /**
+ * Gets the cause of this {@link DamageStep}.
+ *
+ * @return The cause of this step
+ */
+ Cause cause();
+
+ /**
+ * Gets whether this step is skipped.
+ * When skipped, only the step and its side effects are ignored, modifiers are still applied.
+ * A modifier willing to ignore every previous modifiers should revert the damage to {@link #damageBeforeModifiers()}.
+ *
+ * @return Whether this step is skipped
+ */
+ boolean isSkipped();
+
+ /**
+ * Sets whether this step is skipped.
+ *
+ * @see #isSkipped()
+ * @throws IllegalStateException if called after the step has finished.
+ */
+ void setSkipped(boolean skipped);
+
+ /**
+ * Skips this step.
+ *
+ * @see #isSkipped()
+ * @throws IllegalStateException if called after the step has finished.
+ */
+ default void skip() {
+ this.setSkipped(true);
+ }
+
+ /**
+ * The damage just before the modifiers of this step.
+ *
+ * @return The damage before this step
+ */
+ double damageBeforeModifiers();
+
+ /**
+ * The damage just before this step.
+ *
+ * @return The damage before this step
+ * @throws IllegalStateException if called before the "before" modifiers have finished.
+ */
+ double damageBeforeStep();
+
+ /**
+ * The damage just after this step.
+ *
+ * @return The damage after this step
+ * @throws IllegalStateException if called before this step has finished
+ */
+ double damageAfterStep();
+
+ /**
+ * The damage just after the modifiers of this step.
+ *
+ * @return The damage after this step
+ * @throws IllegalStateException if called before the modifiers have finished.
+ */
+ double damageAfterModifiers();
+
+ /**
+ * Gets an immutable list of all modifiers that applies just before this step.
+ *
+ * @return The list of modifiers
+ */
+ List modifiersBefore();
+
+ /**
+ * Gets an immutable list of all modifiers that applies just after this step.
+ *
+ * @return The list of modifiers
+ */
+ List modifiersAfter();
+}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierType.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepType.java
similarity index 84%
rename from src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierType.java
rename to src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepType.java
index e27d91de2bc..32288996331 100644
--- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageModifierType.java
+++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepType.java
@@ -29,13 +29,13 @@
import org.spongepowered.api.util.annotation.CatalogedBy;
/**
- * A type of {@link DamageModifier} that can apply a "grouping" so to speak
+ * A type of {@link DamageStep} that can apply a "grouping" so to speak
* for the damage modifier. The use case is being able to differentiate between
- * various {@link DamageModifier}s based on the {@link DamageModifierType}
+ * various {@link DamageStep}s based on the {@link DamageStepType}
* without digging through the {@link Cause} provided by
- * {@link DamageModifier#cause()}.
+ * {@link DamageStep#cause()}.
*/
-@CatalogedBy(DamageModifierTypes.class)
-public interface DamageModifierType extends DefaultedRegistryValue {
+@CatalogedBy(DamageStepTypes.class)
+public interface DamageStepType extends DefaultedRegistryValue {
}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepTypes.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepTypes.java
new file mode 100644
index 00000000000..c65dd4573cc
--- /dev/null
+++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepTypes.java
@@ -0,0 +1,190 @@
+/*
+ * This file is part of SpongeAPI, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) SpongePowered
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.spongepowered.api.event.cause.entity.damage;
+
+import org.spongepowered.api.ResourceKey;
+import org.spongepowered.api.Sponge;
+import org.spongepowered.api.effect.potion.PotionEffect;
+import org.spongepowered.api.effect.potion.PotionEffectType;
+import org.spongepowered.api.effect.potion.PotionEffectTypes;
+import org.spongepowered.api.entity.Entity;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.event.cause.entity.damage.source.DamageSource;
+import org.spongepowered.api.item.enchantment.Enchantment;
+import org.spongepowered.api.item.enchantment.EnchantmentType;
+import org.spongepowered.api.item.inventory.ItemStack;
+import org.spongepowered.api.item.inventory.ItemStackSnapshot;
+import org.spongepowered.api.registry.DefaultedRegistryReference;
+import org.spongepowered.api.registry.Registry;
+import org.spongepowered.api.registry.RegistryKey;
+import org.spongepowered.api.registry.RegistryScope;
+import org.spongepowered.api.registry.RegistryScopes;
+import org.spongepowered.api.registry.RegistryTypes;
+
+@SuppressWarnings("unused")
+@RegistryScopes(scopes = RegistryScope.GAME)
+public final class DamageStepTypes {
+
+ // @formatter:off
+
+ // SORTFIELDS:ON
+
+ /**
+ * Represents a {@link DamageStep} that "absorbs" damage based on
+ * the {@link PotionEffectTypes#ABSORPTION} level on the
+ * {@link Entity}.
+ */
+ public static final DefaultedRegistryReference ABSORPTION = DamageStepTypes.key(ResourceKey.sponge("absorption"));
+
+ /**
+ * Represents a {@link DamageStep} that will reduce damage based on
+ * the armor {@link ItemStack}s.
+ */
+ public static final DefaultedRegistryReference ARMOR = DamageStepTypes.key(ResourceKey.sponge("armor"));
+
+ /**
+ * Represents a {@link DamageStep} that will reduce damage based on
+ * the {@link EnchantmentType}s applicable to an {@link ItemStack} that is
+ * considered to be "armor" currently equipped on the owner.
+ *
+ * Usually, within the {@link DamageStep#cause()} will reside
+ * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
+ * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
+ * incoming/outgoing damage. There can be multiple {@link DamageStep}s
+ * of this type in a single event due to the variety of possibilities in
+ * customization of armor handling.
+ */
+ public static final DefaultedRegistryReference ARMOR_ENCHANTMENT = DamageStepTypes.key(ResourceKey.sponge("armor_enchantment"));
+
+ /**
+ * Represents the {@link DamageStep} that will reduce the base damage from a
+ * {@link Player} if their attack cooldown has not been completed yet.
+ */
+ public static final DefaultedRegistryReference BASE_COOLDOWN = DamageStepTypes.key(ResourceKey.sponge("base_cooldown"));
+
+ /**
+ * Represents the {@link DamageStep} that will modify damage output
+ * based on the fact that the attacking source is critically hitting the
+ * target.
+ */
+ public static final DefaultedRegistryReference CRITICAL_HIT = DamageStepTypes.key(ResourceKey.sponge("critical_hit"));
+
+ /**
+ * Represents a {@link DamageStep} that will reduce damage based on
+ * the {@link PotionEffectTypes#RESISTANCE} or any other
+ * {@link PotionEffectType} that can be deemed as reducing incoming damage.
+ *
+ * Usually, within the {@link DamageStep#cause()} will reside
+ * a {@link PotionEffect} including the amplifier and duration, signifying
+ * that the {@link PotionEffectType} is modifying the incoming damage.
+ */
+ public static final DefaultedRegistryReference DEFENSIVE_POTION_EFFECT = DamageStepTypes.key(ResourceKey.sponge("defensive_potion_effect"));
+
+ /**
+ * Represents the {@link DamageStep} that will reduce the enchantment damage from a
+ * {@link Player} if their attack cooldown has not been completed yet.
+ */
+ public static final DefaultedRegistryReference ENCHANTMENT_COOLDOWN = DamageStepTypes.key(ResourceKey.sponge("enchantment_cooldown"));
+
+ /**
+ * Represents a {@link DamageStep} that will modify freezing damage.
+ * E.g. {@link org.spongepowered.api.entity.living.monster.Blaze} take more damage from freezing sources.
+ */
+ public static final DefaultedRegistryReference FREEZING_BONUS = DamageStepTypes.key(ResourceKey.sponge("freezing_bonus"));
+
+ /**
+ * Represents the {@link DamageStep} that will modify damage from
+ * a {@link DamageSource#source()} that is a {@link org.spongepowered.api.entity.FallingBlock}.
+ *
+ * Usually, within the {@link DamageStep#cause()} will reside
+ * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
+ * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
+ * incoming/outgoing damage.
+ */
+ public static final DefaultedRegistryReference HARD_HAT = DamageStepTypes.key(ResourceKey.sponge("hard_hat"));
+
+ /**
+ * Represents a {@link DamageStep} that will modify damage based on
+ * magic.
+ */
+ public static final DefaultedRegistryReference MAGIC = DamageStepTypes.key(ResourceKey.sponge("magic"));
+
+ /**
+ * Represents a {@link DamageStep} that will reduce outgoing damage
+ * based on a {@link PotionEffect}.
+ *
+ * Usually, within the {@link DamageStep#cause()} will reside
+ * a {@link PotionEffect} including the amplifier and duration, signifying
+ * that the {@link PotionEffectType} is reducing the outgoing damage.
+ */
+ public static final DefaultedRegistryReference NEGATIVE_POTION_EFFECT = DamageStepTypes.key(ResourceKey.sponge("negative_potion_effect"));
+
+ /**
+ * Represents the {@link DamageStep} that will increase damage from
+ * a {@link PotionEffect} affecting the attacker.
+ */
+ public static final DefaultedRegistryReference OFFENSIVE_POTION_EFFECT = DamageStepTypes.key(ResourceKey.sponge("offensive_potion_effect"));
+
+ /**
+ * Represents a {@link DamageStep} that will reduce damage due to using a shield.
+ */
+ public static final DefaultedRegistryReference SHIELD = DamageStepTypes.key(ResourceKey.sponge("shield"));
+
+ /**
+ * Represents a {@link DamageStep} that is applied for a sweeping attack.
+ */
+ public static final DefaultedRegistryReference SWEEPING = DamageStepTypes.key(ResourceKey.sponge("sweeping"));
+
+ /**
+ * Represents a {@link DamageStep} that will add bonus damage based on the weapon used.
+ */
+ public static final DefaultedRegistryReference WEAPON_BONUS = DamageStepTypes.key(ResourceKey.sponge("weapon_bonus"));
+
+ /**
+ * Represents the {@link DamageStep} that will modify damage from
+ * an {@link EnchantmentType} on an equipped {@link ItemStack}.
+ *
+ * Usually, within the {@link DamageStep#cause()} will reside
+ * an {@link ItemStackSnapshot} and an {@link Enchantment} signifying
+ * that the {@link EnchantmentType} of the {@link ItemStack} is modifying the
+ * incoming/outgoing damage.
+ */
+ public static final DefaultedRegistryReference WEAPON_ENCHANTMENT = DamageStepTypes.key(ResourceKey.sponge("weapon_enchantment"));
+
+ // SORTFIELDS:OFF
+
+ // @formatter:on
+
+ private DamageStepTypes() {
+ }
+
+ public static Registry registry() {
+ return Sponge.game().registry(RegistryTypes.DAMAGE_STEP_TYPE);
+ }
+
+ private static DefaultedRegistryReference key(final ResourceKey location) {
+ return RegistryKey.of(RegistryTypes.DAMAGE_STEP_TYPE, location).asDefaultedReference(Sponge::game);
+ }
+}
diff --git a/src/main/java/org/spongepowered/api/event/entity/AttackEntityEvent.java b/src/main/java/org/spongepowered/api/event/entity/AttackEntityEvent.java
index 208f68a4108..38948d73ca1 100644
--- a/src/main/java/org/spongepowered/api/event/entity/AttackEntityEvent.java
+++ b/src/main/java/org/spongepowered/api/event/entity/AttackEntityEvent.java
@@ -25,38 +25,19 @@
package org.spongepowered.api.event.entity;
import org.spongepowered.api.block.entity.carrier.Dispenser;
-import org.spongepowered.api.effect.potion.PotionEffect;
import org.spongepowered.api.entity.Entity;
-import org.spongepowered.api.entity.living.Living;
import org.spongepowered.api.entity.living.monster.skeleton.Skeleton;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.projectile.arrow.ArrowLike;
-import org.spongepowered.api.event.Cancellable;
import org.spongepowered.api.event.Cause;
-import org.spongepowered.api.event.Event;
-import org.spongepowered.api.event.cause.entity.damage.DamageFunction;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierType;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierTypes;
import org.spongepowered.api.event.cause.entity.damage.DamageType;
import org.spongepowered.api.event.cause.entity.damage.source.DamageSource;
-import org.spongepowered.api.event.impl.entity.AbstractAttackEntityEvent;
import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.api.item.inventory.ItemStack;
-import org.spongepowered.api.item.inventory.ItemStackSnapshot;
-import org.spongepowered.api.util.Tuple;
-import org.spongepowered.api.util.annotation.eventgen.ImplementedBy;
-import org.spongepowered.api.util.annotation.eventgen.PropertySettings;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.difficulty.Difficulties;
import org.spongepowered.api.world.difficulty.Difficulty;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.DoubleUnaryOperator;
-import java.util.function.Function;
-
/**
* Represents the base event for when an {@link Entity} is being "attacked".
* The uniqueness of this event is that all {@link DamageSource}s can deal
@@ -77,7 +58,7 @@
* to a particular {@link DamageType}, has no static finalized amount of damage
* to deal to a particular {@link Entity}. To properly represent this,
* a {@link DamageSource} has various "states" such as:
- * {@link DamageSource#isAbsolute()}, or {@link DamageSource#isBypassingArmor()}.
+ * {@link DamageSource#isMagic()}, or {@link DamageSource#isBypassingArmor()}.
* Quite simply, the {@link DamageSource} will always be the "first" element
* within a {@link Cause} that can be retrieved from {@link #cause()}.
*
@@ -88,316 +69,43 @@
* the {@link Cause}. The same can be said if an {@link ArrowLike} was shot from
* a {@link Dispenser} that was triggered by a {@link Player} flipping a
* switch.
- *
- * Continuing with the notion of "modifiers" to damage, the "base" damage
- * is modified or added onto after various unknown methods are called or
- * processed on the damage. Optimally, these modifiers can be traced to a
- * particular object, be it an {@link ItemStack}, {@link Difficulty}, or
- * simply an an attribute. The interesting part is that these "modifiers"
- * do not just define a static value to add to the "base" damage, they
- * are usually a loose form of a {@link Function} that are applied to
- * the "base" damage. Given that {@link Cause} has a unique capability of
- * storing any and every {@link Object} willing to be passed into it, we
- * can easily represent these "sources" of "modifiers" in a {@link Cause}.
- * Now, knowing the "source" will not provide enough information, so a
- * {@link DamageModifierType} is provided with a {@link DamageModifier} to
- * paint the fullest picture of "explaining" the {@link DamageModifier} as to
- * why it is present, and why it is "modifying" the "base" damage. Finally,
- * we can associate a {@link DamageModifier} with a {@link Function} that is
- * passed the current "damage" into {@link Function#apply(Object)}, being added
- * to the current "damage". After all {@link DamageModifier} {@link Function}s
- * are "applied", the overall "damage" is now the final damage to actually
- * throw a {@link AttackEntityEvent}.
- *
- * Note that due to the mechanics of the game, {@link DamageModifier}s
- * are always ordered in the order of which they apply their modifier onto
- * the "base" damage. The implementation for {@link #finalOutputDamage()} can
- * be exemplified like so:
- *
- * {@code
- * double damage = this.baseDamage;
- * for (Map.Entry> entry : this.modifierFunctions.entrySet()) {
- * damage += checkNotNull(entry.getValue().apply(damage));
- * }
- * return damage;
- * }
- *
- * TODO explain groups
- * After which, the "final" damage is simply the summation of the
- * "base" damage and all "modified damage" for each {@link DamageModifier}
- * provided in this event.
- *
- * Coming forward, it is possible to further customize not only the "base"
- * damage, but override pre-existing {@link DamageModifier} {@link Function}s
- * by calling {@link #setOutputDamage(DamageModifier, DoubleUnaryOperator)} at which point the
- * end result may be undefined. However, if a custom {@link DamageModifier}
- * that aims to alter the "final" damage based on some custom circumstances,
- * calling {@link #setOutputDamage(DamageModifier, DoubleUnaryOperator)} on a new
- * {@link DamageModifier} instance, easily created from the
- * {@link org.spongepowered.api.event.cause.entity.damage.DamageModifier.Builder},
- * the provided pairing will be added at the
- * "end" of the list for "modifying" the "base" damage.
- *
- * Note that this event is intended for processing incoming damage to
- * an {@link Entity} prior to any {@link DamageModifier}s associated with
- * the {@link #entity()}. The {@link AttackEntityEvent} is used
- * to process the various {@link DamageModifier}s of which originate or are
- * associated with the targeted {@link Entity}.
*/
-@ImplementedBy(AbstractAttackEntityEvent.class)
-public interface AttackEntityEvent extends Event, Cancellable {
-
- /**
- * For use with the {@link DamageSource} that is known as the "source"
- * of the damage.
- */
- String SOURCE = "Source";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#HARD_HAT} and the {@link Cause} contains
- * an {@link ItemStackSnapshot}, usually a helmet.
- */
- String HARD_HAT_ARMOR = "HardHat";
-
- /**
- * or use with a {@link DamageModifier} where its type is a
- * {@link DamageModifierTypes#SHIELD} and the {@link Cause} contains
- * an {@link ItemStackSnapshot} (in Vanilla, a shield).
- */
- String SHIELD = "Shield";
-
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ARMOR} and the {@link Cause} contains
- * an {@link ItemStackSnapshot}. Separate from hard hat but still
- * considered as "armor" where it will absorb a certain amount of damage
- * before dealing damage to the wearer.
- */
- String GENERAL_ARMOR = "GeneralArmor";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ARMOR} and the {@link Cause} contains
- * an {@link ItemStackSnapshot} for a "helmet".
- */
- String HELMET = AttackEntityEvent.GENERAL_ARMOR + ":head";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ARMOR} and the {@link Cause} contains
- * an {@link ItemStackSnapshot} for a "chestplate".
- */
- String CHESTPLATE = AttackEntityEvent.GENERAL_ARMOR + ":chestplate";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ARMOR} and the {@link Cause} contains
- * an {@link ItemStackSnapshot} for "leggings".
- */
- String LEGGINGS = AttackEntityEvent.GENERAL_ARMOR + ":leggings";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ARMOR} and the {@link Cause} contains
- * an {@link ItemStackSnapshot} for "boots".
- */
- String BOOTS = AttackEntityEvent.GENERAL_ARMOR + ":boots";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#HARD_HAT} and the {@link Cause} contains
- * a {@link PotionEffect}.
- */
- String RESISTANCE = "Resistance";
- /**
- * For use with a {@link DamageModifier} where it's type is a
- * {@link DamageModifierTypes#ABSORPTION} and the {@link Cause} contains
- * a {@link PotionEffect}.
- */
- String ABSORPTION = "AbsorptionPotion";
- /**
- * For use with a {@link DamageModifier} where the root cause is "created"
- * by an object, usually the {@link Entity} or {@link Living} entity.
- */
- String CREATOR = "Creator";
- /**
- * For use with a {@link DamageSource} with a {@link DamageSource#source() entity} or
- * {@link DamageSource#blockSnapshot()} such that it was last "notified" by the object
- * represented in the cause.
- *
- * Usually this is used where a {@link Player} interacted with the
- * now {@link DamageSource} such that they
- */
- String NOTIFIER = "Notifier";
-
- /**
- * Gets the {@link Entity}.
- *
- * @return The entity
- */
- Entity entity();
-
- /**
- * Gets the original "raw" amount of damage to deal to the targeted
- * {@link Entity}.
- *
- * @return The original "raw" damage
- */
- double originalDamage();
-
- /**
- * Gets the original "final" amount of damage after all original
- * {@link DamageModifier}s are applied to {@link #originalDamage()}.
- * The "final" damage is considered the amount of health being lost by
- * the {@link Entity}, if health is tracked.
- *
- * @return The final amount of damage to originally deal
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double originalFinalDamage();
-
- /**
- * Gets an immutable {@link Map} of all original {@link DamageModifier}s
- * and their associated "modified" damage. Note that ordering is not
- * retained.
- *
- * @return An immutable map of the original modified damages
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- Map> originalDamages();
-
- /**
- * Gets the original damage for the provided {@link DamageModifier}. If
- * the provided {@link DamageModifier} was not included in
- * {@link #originalDamages()}, an {@link IllegalArgumentException} is
- * thrown.
- *
- * @param damageModifier The original damage modifier
- * @return The original damage change
- */
- Tuple originalModifierDamage(DamageModifier damageModifier);
-
- /**
- * Gets the original {@link List} of {@link DamageModifier} to
- * {@link Function} that was originally passed into the event.
- *
- * @return The list of damage modifier functions
- */
- List originalFunctions();
-
- /**
- * Gets the "base" damage to deal to the targeted {@link Entity}. The
- * "base" damage is the original value before passing along the chain of
- * {@link Function}s for all known {@link DamageModifier}s.
- *
- * @return The base damage
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double baseOutputDamage();
-
- /**
- * Sets the "base" damage to deal to the targeted {@link Entity}. The
- * "base" damage is the original value before passing along the chain of
- * {@link Function}s for all known {@link DamageModifier}s.
- *
- * @param baseDamage The base damage
- */
- void setBaseOutputDamage(double baseDamage);
+public interface AttackEntityEvent extends DamageCalculationEvent {
/**
- * Gets the final damage that will be passed into the proceeding
- * {@link AttackEntityEvent}. The final damage is the end result of the
- * {@link #baseOutputDamage()} being applied in {@link Function#apply(Object)}
- * available from all the {@link Tuple}s of {@link DamageModifier} to
- * {@link Function} in {@link #originalFunctions()}.
- *
- * @return The final damage to deal
+ * Fires before the damage steps and their side effects are applied.
+ * The final damage is still unknown.
*/
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double finalOutputDamage();
+ interface Pre extends AttackEntityEvent, DamageCalculationEvent.Pre {
+ }
/**
- * Checks whether the provided {@link DamageModifier} is applicable to the
- * current available {@link DamageModifier}s.
- *
- * @param damageModifier The damage modifier to check
- * @return True if the damage modifier is relevant to this event
+ * Fires after the damage steps and their side effects have been applied.
*/
- boolean isModifierApplicable(DamageModifier damageModifier);
+ interface Post extends AttackEntityEvent, DamageCalculationEvent.Post {
- /**
- * Gets the damage for the provided {@link DamageModifier}. Providing that
- * {@link #isModifierApplicable(DamageModifier)} returns true
,
- * the cached "damage" for the {@link DamageModifier} is returned.
- *
- * @param damageModifier The damage modifier to get the damage for
- * @return The modifier
- */
- Tuple outputDamage(DamageModifier damageModifier);
-
- /**
- * Sets the provided {@link Function} to be used for the given
- * {@link DamageModifier}. If the {@link DamageModifier} is already
- * included in {@link #modifiers()}, the {@link Function} replaces
- * the existing function. If there is no {@link Tuple} for the
- * {@link DamageModifier}, a new one is created and added to the end
- * of the list of {@link Function}s to be applied to the
- * {@link #baseOutputDamage()}.
- *
- * If needing to create a custom {@link DamageModifier} is required,
- * usage of the
- * {@link org.spongepowered.api.event.cause.entity.damage.DamageModifier.Builder}
- * is recommended.
- *
- * @param damageModifier The damage modifier
- * @param function The function to map to the modifier
- */
- void setOutputDamage(DamageModifier damageModifier, DoubleUnaryOperator function);
+ /**
+ * Gets the original knockback modifier.
+ *
+ * @see #knockbackModifier()
+ * @return The original knockback modifier
+ */
+ double originalKnockbackModifier();
- /**
- * Adds the provided {@link DamageModifier} and {@link Function} to the
- * list of modifiers, such that the {@link Set} containing
- * {@link DamageModifierType}s provided in {@code before} will appear
- * after the provided damage modifier.
- *
- * @param damageModifier The damage modifier to add
- * @param function The associated function
- * @param before The set containing the modifier types to come after
- * the provided modifier
- */
- void addDamageModifierBefore(DamageModifier damageModifier, DoubleUnaryOperator function, Set before);
+ /**
+ * Gets the knockback modifier. The modifier itself will apply to the
+ * momentum of the attacked entity.
+ *
+ * @return The knockback modifier
+ */
+ double knockbackModifier();
- /**
- * Adds the provided {@link DamageModifier} and {@link Function} to the list
- * of modifiers, such that the modifier will appear in order after any
- * current modifiers whose type are included in the provided {@link Set}
- * of {@link DamageModifierType}s.
- *
- * @param damageModifier The damage modifier to add
- * @param function The associated function
- * @param after The set of modifier types to come before the new modifier
- */
- void addDamageModifierAfter(DamageModifier damageModifier, DoubleUnaryOperator function, Set after);
-
- /**
- * Gets a list of simple {@link Tuple}s of {@link DamageModifier} keyed to
- * their representative {@link Function}s. All {@link DamageModifier}s are
- * applicable to the entity based on the {@link DamageSource} and any
- * possible invulnerabilities due to the {@link DamageSource}.
- *
- * @return A list of damage modifiers to functions
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- List modifiers();
-
- /**
- * Gets the knock back modifier. The modifier itself will apply to the
- * momentum of the attacked entity.
- *
- * @return The knock back modifier
- */
- float knockbackModifier();
-
- /**
- * Sets the knock back modifier. The modifier itself will apply to the
- * momentum of the attacked entity.
- *
- * @param modifier The knock back modifier to set
- */
- void setKnockbackModifier(float modifier);
+ /**
+ * Sets the knockback modifier.
+ *
+ * @see #knockbackModifier()
+ * @param modifier The knockback modifier to set
+ */
+ void setKnockbackModifier(double modifier);
+ }
}
diff --git a/src/main/java/org/spongepowered/api/event/entity/DamageCalculationEvent.java b/src/main/java/org/spongepowered/api/event/entity/DamageCalculationEvent.java
new file mode 100644
index 00000000000..046b2635711
--- /dev/null
+++ b/src/main/java/org/spongepowered/api/event/entity/DamageCalculationEvent.java
@@ -0,0 +1,157 @@
+/*
+ * This file is part of SpongeAPI, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) SpongePowered
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.spongepowered.api.event.entity;
+
+import org.spongepowered.api.entity.Entity;
+import org.spongepowered.api.event.Cancellable;
+import org.spongepowered.api.event.Cause;
+import org.spongepowered.api.event.Event;
+import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
+import org.spongepowered.api.event.cause.entity.damage.DamageStep;
+import org.spongepowered.api.event.cause.entity.damage.DamageStepType;
+import org.spongepowered.api.event.impl.entity.AbstractDamageCalculationEventPre;
+import org.spongepowered.api.item.inventory.ItemStack;
+import org.spongepowered.api.util.annotation.eventgen.ImplementedBy;
+import org.spongepowered.api.world.difficulty.Difficulty;
+
+import java.util.List;
+
+/**
+ * The base event for when some damage is calculated,
+ * whether it is the damage output of an attack, or the damage inflicted to an entity.
+ *
+ * The damage calculation starts with a base damage which is modified
+ * by a series of operations to obtain a final value.
+ * Some of these operations are captured as {@link DamageStep}s and are modifiable.
+ *
+ * Optimally, these steps can be traced to a
+ * particular object, be it an {@link ItemStack}, {@link Difficulty}, or
+ * simply an an attribute. Given that {@link Cause} has a unique capability of
+ * storing any and every {@link Object} willing to be passed into it, we
+ * can easily represent these "sources" of "steps" in a {@link Cause}.
+ * Now, knowing the "source" will not provide enough information, so a
+ * {@link DamageStepType} is provided with a {@link DamageStep} to
+ * paint the fullest picture of "explaining" the {@link DamageStep} as to
+ * why it is present, and why it is modifying the base damage.
+ */
+public interface DamageCalculationEvent extends Event, Cancellable {
+
+ /**
+ * Gets the targeted {@link Entity}.
+ *
+ * @return The targeted entity
+ */
+ Entity entity();
+
+ /**
+ * Gets the original base damage to deal to the targeted {@link Entity}.
+ *
+ * @see #baseDamage()
+ * @return The original base damage
+ */
+ double originalBaseDamage();
+
+ /**
+ * Gets the base damage to deal to the targeted {@link Entity}.
+ * The base damage is the value before the calculation and its {@link DamageStep}s.
+ *
+ * @return The base damage
+ */
+ double baseDamage();
+
+ /**
+ * Fires before the damage steps and their side effects are applied.
+ * The final damage is still unknown.
+ */
+ @ImplementedBy(AbstractDamageCalculationEventPre.class)
+ interface Pre extends DamageCalculationEvent {
+
+ /**
+ * Sets the base damage to deal to the targeted {@link Entity}.
+ *
+ * @see #baseDamage()
+ * @param baseDamage The base damage
+ */
+ void setBaseDamage(double baseDamage);
+
+ /**
+ * Gets a mutable list of all modifiers that applies just before the step.
+ *
+ * @param type The step type
+ * @return The list of modifiers
+ */
+ List modifiersBefore(DamageStepType type);
+
+ /**
+ * Gets a mutable list of all modifiers that applies just after the step.
+ *
+ * @param type The step type
+ * @return The list of modifiers
+ */
+ List modifiersAfter(DamageStepType type);
+ }
+
+ /**
+ * Fires after the damage steps and their side effects have been applied.
+ * The steps have been captured and can't be changed.
+ * The final damage can still be changed.
+ */
+ interface Post extends DamageCalculationEvent {
+
+ /**
+ * Gets the original final damage to deal to the targeted {@link Entity}.
+ *
+ * @see #finalDamage()
+ * @return The final amount of damage to originally deal
+ */
+ double originalFinalDamage();
+
+ /**
+ * Gets the final damage to deal to the targeted {@link Entity}.
+ * The final damage is the value after the calculation and its {@link DamageStep}s.
+ * The final damage is the amount of health being lost by the {@link Entity}, if health is tracked.
+ *
+ * @return The final damage
+ */
+ double finalDamage();
+
+ /**
+ * Sets the final damage to deal to the targeted {@link Entity}.
+ *
+ * @see #finalDamage()
+ * @param finalDamage The base damage
+ */
+ void setFinalDamage(double finalDamage);
+
+ /**
+ * Gets the list of the captured steps during the damage calculation in the order they have been applied.
+ * Note that this list is not an exhaustive representation of all the operations applied,
+ * especially in a modded environment.
+ *
+ * @return The list of steps
+ */
+ List steps();
+ }
+}
diff --git a/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java b/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java
index 990a05a1deb..833798d7dc7 100644
--- a/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java
+++ b/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java
@@ -25,36 +25,24 @@
package org.spongepowered.api.event.entity;
import org.spongepowered.api.block.entity.carrier.Dispenser;
+import org.spongepowered.api.data.Keys;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.living.monster.skeleton.Skeleton;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.projectile.arrow.ArrowLike;
-import org.spongepowered.api.event.Cancellable;
import org.spongepowered.api.event.Cause;
-import org.spongepowered.api.event.Event;
-import org.spongepowered.api.event.cause.entity.damage.DamageFunction;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier.Builder;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierType;
import org.spongepowered.api.event.cause.entity.damage.DamageType;
import org.spongepowered.api.event.cause.entity.damage.source.DamageSource;
-import org.spongepowered.api.event.impl.entity.AbstractDamageEntityEvent;
import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.api.item.inventory.ItemStack;
-import org.spongepowered.api.util.Tuple;
-import org.spongepowered.api.util.annotation.eventgen.ImplementedBy;
-import org.spongepowered.api.util.annotation.eventgen.PropertySettings;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.difficulty.Difficulties;
import org.spongepowered.api.world.difficulty.Difficulty;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.DoubleUnaryOperator;
+import java.util.Optional;
/**
- * Represents the base event for when an {@link Entity} is being "attacked".
+ * Represents the base event for when an {@link Entity} is being "damaged".
* The uniqueness of this event is that all {@link DamageSource}s can deal
* varying amounts of damage with varying modifiers based on various reasons.
* Due to this ambiguous variety of information that is possible to provide,
@@ -73,7 +61,7 @@
* to a particular {@link DamageType}, has no static finalized amount of damage
* to deal to a particular {@link Entity}. To properly represent this,
* a {@link DamageSource} has various "states" such as:
- * {@link DamageSource#isAbsolute()}, or {@link DamageSource#isBypassingArmor()}.
+ * {@link DamageSource#isMagic()}, or {@link DamageSource#isBypassingArmor()}.
* Quite simply, the {@link DamageSource} will always be the "first" element
* within a {@link Cause} that can be retrieved from {@link #cause()}.
*
@@ -84,233 +72,30 @@
* the {@link Cause}. The same can be said if an {@link ArrowLike} was shot from
* a {@link Dispenser} that was triggered by a {@link Player} flipping a
* switch.
- *
- * Continuing with the notion of "modifiers" to damage, the "base" damage
- * is modified or added onto after various unknown methods are called or
- * processed on the damage. Optimally, these modifiers can be traced to a
- * particular object, be it an {@link ItemStack}, {@link Difficulty}, or
- * simply an an attribute. The interesting part is that these "modifiers"
- * do not just define a static value to add to the "base" damage, they
- * are usually a loose form of a {@link DamageFunction} that are applied to
- * the "base" damage. Given that {@link Cause} has a unique capability of
- * storing any and every {@link Object} willing to be passed into it, we
- * can easily represent these "sources" of "modifiers" in a {@link Cause}.
- * Now, knowning the "source" will not provide enough information, so a
- * {@link DamageModifierType} is provided with a {@link DamageModifier} to
- * paint the fullest picture of "explaining" the {@link DamageModifier} as to
- * why it is present, and why it is "modifying" the "base" damage. Finally,
- * we can associate a {@link DamageModifier} with a {@link DamageFunction} that is
- * passed the current "damage" into {@link DoubleUnaryOperator#applyAsDouble(double)}
- * , being added
- * to the current "damage". After all {@link DamageModifier} {@link DamageFunction}s
- * are "applied", the overall "damage" is now the final damage to actually
- * throw a {@link DamageEntityEvent}.
- *
- * Note that due to the mechanics of the game, {@link DamageModifier}s
- * are always ordered in the order of which they apply their modifier onto
- * the "base" damage. The implementation for {@link #finalDamage()} can be
- * exemplified like so:
- *
- * {@code
- * double damage = this.baseDamage;
- * for (Map.Entry> entry : this.modifierFunctions.entrySet()) {
- * damage += checkNotNull(entry.getValue().apply(damage));
- * }
- * return damage;
- * }
- *
- * TODO explain groups
- * After which, the "final" damage is simply the summation of the
- * "base" damage and all "modified damage" for each {@link DamageModifier}
- * provided in this event.
- *
- * Coming forward, it is possible to further customize not only the "base"
- * damage, but override pre-existing {@link DamageModifier} {@link DamageFunction}s
- * by calling {@link #setDamage(DamageModifier, DoubleUnaryOperator)} at which point the
- * end result may be undefined. However, if a custom {@link DamageModifier}
- * that aims to alter the "final" damage based on some custom circumstances,
- * calling {@link #setDamage(DamageModifier, DoubleUnaryOperator)} on a new
- * {@link DamageModifier} instance, easily created from the
- * {@link org.spongepowered.api.event.cause.entity.damage.DamageModifier.Builder},
- * the provided pairing will be added at the
- * "end" of the list for "modifying" the "base" damage.
- *
- * TODO this is wrong?
- * Note that this event is intended for processing incoming damage to
- * an {@link Entity} prior to any {@link DamageModifier}s associated with
- * the {@link #entity()}. The {@link DamageEntityEvent} is used
- * to process the various {@link DamageModifier}s of which originate or are
- * associated with the targeted {@link Entity}.
*/
-@ImplementedBy(AbstractDamageEntityEvent.class)
-public interface DamageEntityEvent extends Event, Cancellable {
-
- /**
- * Gets the {@link Entity}.
- *
- * @return The entity
- */
- Entity entity();
-
- /**
- * Gets the original "raw" amount of damage to deal to the targeted
- * {@link Entity}.
- *
- * @return The original "raw" damage
- */
- double originalDamage();
-
- /**
- * Gets the original "final" amount of damage after all original
- * {@link DamageModifier}s are applied to {@link #originalDamage()}.
- * The "final" damage is considered the amount of health being lost by
- * the {@link Entity}, if health is tracked.
- *
- * @return The final amount of damage to originally deal
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double originalFinalDamage();
-
- /**
- * Gets an immutable {@link Map} of all original {@link DamageModifier}s
- * and their associated "modified" damage. Note that ordering is not
- * retained.
- *
- * @return An immutable map of the original modified damages
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- Map> originalDamages();
-
- /**
- * Gets the original damage for the provided {@link DamageModifier}. If
- * the provided {@link DamageModifier} was not included in
- * {@link #originalDamages()}, an {@link IllegalArgumentException} is
- * thrown.
- *
- * @param damageModifier The original damage modifier
- * @return The original damage change
- */
- Tuple originalModifierDamage(DamageModifier damageModifier);
-
- /**
- * Gets the original {@link List} of {@link DamageModifier} to
- * {@link DamageFunction} that was originally passed into the event.
- *
- * @return The list of damage modifier functions
- */
- List originalFunctions();
-
- /**
- * Gets the "base" damage to deal to the targeted {@link Entity}. The
- * "base" damage is the original value before passing along the chain of
- * {@link DamageFunction}s for all known {@link DamageModifier}s.
- *
- * @return The base damage
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double baseDamage();
-
- /**
- * Sets the "base" damage to deal to the targeted {@link Entity}. The
- * "base" damage is the original value before passing along the chain of
- * {@link DamageFunction}s for all known {@link DamageModifier}s.
- *
- * @param baseDamage The base damage
- */
- void setBaseDamage(double baseDamage);
-
- /**
- * Gets the final damage that will be passed into the proceeding
- * {@link DamageEntityEvent}. The final damage is the end result of the
- * {@link #baseDamage()} being applied in {@link DoubleUnaryOperator#applyAsDouble(double)}
- * available from all the {@link Tuple}s of {@link DamageModifier} to
- * {@link DamageFunction} in {@link #originalFunctions()}.
- *
- * @return The final damage to deal
- */
- @PropertySettings(requiredParameter = false, generateMethods = false)
- double finalDamage();
-
- /**
- * Checks whether the provided {@link DamageModifier} is applicable to the
- * current available {@link DamageModifier}s.
- *
- * @param damageModifier The damage modifier to check
- * @return True if the damage modifier is relevant to this event
- */
- boolean isModifierApplicable(DamageModifier damageModifier);
-
- /**
- * Gets the damage for the provided {@link DamageModifier}. Providing that
- * {@link #isModifierApplicable(DamageModifier)} returns true
,
- * the cached "damage" for the {@link DamageModifier} is returned.
- *
- * @param damageModifier The damage modifier to get the damage for
- * @return The modifier
- */
- Tuple damage(DamageModifier damageModifier);
-
- /**
- * Sets the provided {@link DamageFunction} to be used for the given
- * {@link DamageModifier}. If the {@link DamageModifier} is already
- * included in {@link #modifiers()}, the {@link DoubleUnaryOperator} replaces
- * the existing function. If there is no {@link Tuple} for the
- * {@link DamageModifier}, a new one is created and added to the end
- * of the list of {@link DoubleUnaryOperator}s to be applied to the
- * {@link #baseDamage()}.
- *
- * If needing to create a custom {@link DamageModifier} is required,
- * usage of the {@link Builder} is recommended.
- *
- * @param damageModifier The damage modifier
- * @param function The function to map to the modifier
- */
- void setDamage(DamageModifier damageModifier, DoubleUnaryOperator function);
-
- /**
- * Adds the provided {@link DamageModifier} and {@link DoubleUnaryOperator} to the
- * list of modifiers, such that the {@link Set} containing
- * {@link DamageModifierType}s provided in {@code before} will appear
- * after the provided damage modifier.
- *
- * @param damageModifier The damage modifier to add
- * @param function The associated function
- * @param before The set containing the modifier types to come after
- * the provided modifier
- */
- void addDamageModifierBefore(DamageModifier damageModifier, DoubleUnaryOperator function, Set before);
-
- /**
- * Adds the provided {@link DamageModifier} and {@link DoubleUnaryOperator} to the list
- * of modifiers, such that the modifier will appear in order after any
- * current modifiers whose type are included in the provided {@link Set} of
- * {@link DamageModifierType}s.
- *
- * @param damageModifier The damage modifier to add
- * @param function The associated function
- * @param after The set of modifier types to come before the new modifier
- */
- void addModifierAfter(DamageModifier damageModifier, DoubleUnaryOperator function, Set after);
+public interface DamageEntityEvent extends DamageCalculationEvent {
/**
- * Gets a list of simple {@link Tuple}s of {@link DamageModifier} keyed to
- * their representative {@link DamageFunction}s. All {@link DamageModifier}s are
- * applicable to the entity based on the {@link DamageSource} and any
- * possible invulnerabilities due to the {@link DamageSource}.
- *
- * @return A list of damage modifiers to functions
+ * Fires before the damage steps and their side effects are applied.
+ * The final damage is still unknown.
*/
- @PropertySettings(requiredParameter = false, generateMethods = false)
- List modifiers();
+ interface Pre extends DamageEntityEvent, DamageCalculationEvent.Pre {
+ }
/**
- * Returns whether or not this event will cause the entity to die if the
- * event is not cancelled. Only supported for living entities, returns false
- * if {@link #entity()} is not a living entity.
- *
- * @return Whether the entity will die
+ * Fires after the damage steps and their side effects have been applied.
*/
- @PropertySettings(requiredParameter = false, generateMethods = false)
- boolean willCauseDeath();
+ interface Post extends DamageEntityEvent, DamageCalculationEvent.Post {
+ /**
+ * Returns whether this event will cause the entity to die if the event is not cancelled.
+ * Only supported for living entities, returns false if {@link #entity()} is not a living entity.
+ *
+ * @return Whether the entity will die
+ */
+ default boolean willCauseDeath() {
+ final Optional health = this.entity().get(Keys.HEALTH);
+ return health.isPresent() && health.get() - this.finalDamage() <= 0;
+ }
+ }
}
diff --git a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractAttackEntityEvent.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractAttackEntityEvent.java
deleted file mode 100644
index 6d8531e060a..00000000000
--- a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractAttackEntityEvent.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event.impl.entity;
-
-import org.spongepowered.api.event.cause.entity.damage.DamageFunction;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierType;
-import org.spongepowered.api.event.cause.entity.damage.ModifierFunction;
-import org.spongepowered.api.event.entity.AttackEntityEvent;
-import org.spongepowered.api.util.Tuple;
-import org.spongepowered.api.util.annotation.eventgen.UseField;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.DoubleUnaryOperator;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-public abstract class AbstractAttackEntityEvent extends AbstractModifierEvent implements AttackEntityEvent {
-
- @UseField protected double originalDamage;
- @UseField protected List originalFunctions;
-
- @UseField protected double baseDamage;
-
- @Override
- protected final void init() {
- this.originalFunctions = this.init(this.originalDamage, this.originalFunctions);
- this.baseDamage = this.originalDamage;
- }
-
- @Override
- public final Tuple originalModifierDamage(final DamageModifier damageModifier) {
- Objects.requireNonNull(damageModifier, "Damage modifier cannot be null!");
- for (final var tuple : this.originalModifiers) {
- if (tuple.first().equals(damageModifier)) {
- return tuple.second();
- }
- }
- throw new IllegalArgumentException("The provided damage modifier is not applicable: " + damageModifier.toString());
- }
-
- @Override
- public final double originalFinalDamage() {
- return this.originalFinalAmount;
- }
-
- @Override
- public final Map> originalDamages() {
-
- return this.originalModifierMap;
- }
-
- @Override
- public final double finalOutputDamage() {
- return this.finalAmount(this.baseDamage);
- }
-
- @Override
- public final boolean isModifierApplicable(final DamageModifier damageModifier) {
- return this.modifiers.containsKey(Objects.requireNonNull(damageModifier));
- }
-
- @Override
- public final Tuple outputDamage(final DamageModifier damageModifier) {
- if (!this.modifiers.containsKey(Objects.requireNonNull(damageModifier, "Damage Modifier cannot be null!"))) {
- throw new IllegalArgumentException("The provided damage modifier is not applicable: " + damageModifier.toString());
- }
- return this.modifiers.get(Objects.requireNonNull(damageModifier));
- }
-
- @Override
- public final void setOutputDamage(final DamageModifier damageModifier, final DoubleUnaryOperator function) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddTo = 0;
- boolean addAtEnd = true;
- for (final Iterator iterator = this.modifierFunctions.iterator(); iterator.hasNext(); ) {
- final ModifierFunction tuple = iterator.next();
- if (tuple.modifier().equals(damageModifier)) {
- iterator.remove();
- addAtEnd = false;
- break;
- }
- indexToAddTo++;
- }
- if (addAtEnd) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddTo, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public void addDamageModifierBefore(final DamageModifier damageModifier, final DoubleUnaryOperator function, final Set before) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddBefore = -1;
- int index = 0;
- for (final ModifierFunction tuple : this.modifierFunctions) {
- if (tuple.modifier().equals(damageModifier)) {
- throw new IllegalArgumentException("Cannot add a duplicate modifier");
- }
- if (before.contains(tuple.modifier().type())) {
- indexToAddBefore = index;
- }
- index++;
-
- }
- if (indexToAddBefore == -1) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddBefore, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public void addDamageModifierAfter(final DamageModifier damageModifier, final DoubleUnaryOperator function, final Set after) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddAfter = -1;
- int index = 0;
- for (final ModifierFunction tuple : this.modifierFunctions) {
- if (tuple.modifier().equals(damageModifier)) {
- throw new IllegalArgumentException("Cannot add a duplicate modifier");
- }
- if (after.contains(tuple.modifier().type())) {
- indexToAddAfter = index;
- }
- index++;
-
- }
- if (indexToAddAfter == -1) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddAfter + 1, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public double baseOutputDamage() {
- return this.baseDamage;
- }
-
- @Override
- public final void setBaseOutputDamage(final double baseDamage) {
- this.baseDamage = baseDamage;
- this.recalculate(this.baseDamage);
- }
-
- @Override
- protected DamageFunction convertTuple(final DamageModifier obj, final DoubleUnaryOperator function) {
- return new DamageFunction(obj, function);
- }
-
- @Override
- public List modifiers() {
- return this.modifierFunctions.stream().map((Function, DamageFunction>) entry -> {
- if (entry instanceof DamageFunction) {
- return (DamageFunction) entry;
- } else {
- return new DamageFunction(entry.modifier(), entry.function());
- }
- }).collect(Collectors.toUnmodifiableList());
- }
-}
diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageCalculationEventPre.java
similarity index 53%
rename from src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java
rename to src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageCalculationEventPre.java
index a13e4dfaecf..28ccbe5dda7 100644
--- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java
+++ b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageCalculationEventPre.java
@@ -22,31 +22,29 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package org.spongepowered.api.event.cause.entity.damage;
+package org.spongepowered.api.event.impl.entity;
-import java.util.function.DoubleUnaryOperator;
+import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
+import org.spongepowered.api.event.cause.entity.damage.DamageStepType;
+import org.spongepowered.api.event.entity.DamageCalculationEvent;
+import org.spongepowered.api.event.impl.AbstractEvent;
-/**
- * A function associating a
- * {@link DamageModifier} with a {@link DoubleUnaryOperator} of the resultant
- * effect.
- *
- * @param The modifier type
- */
-public interface ModifierFunction {
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
- /**
- * Gets the modifier used by this modifier function.
- *
- * @return The modifier
- */
- M modifier();
+public abstract class AbstractDamageCalculationEventPre extends AbstractEvent implements DamageCalculationEvent.Pre {
+ private final Map> modifiersBeforeMap = new HashMap<>();
+ private final Map> modifiersAfterMap = new HashMap<>();
- /**
- * Gets the double unary operator used by this function.
- *
- * @return The unary operator
- */
- DoubleUnaryOperator function();
+ @Override
+ public List modifiersBefore(DamageStepType type) {
+ return this.modifiersBeforeMap.computeIfAbsent(type, k -> new LinkedList<>());
+ }
+ @Override
+ public List modifiersAfter(DamageStepType type) {
+ return this.modifiersAfterMap.computeIfAbsent(type, k -> new LinkedList<>());
+ }
}
diff --git a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageEntityEvent.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageEntityEvent.java
deleted file mode 100644
index 598d34e222e..00000000000
--- a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageEntityEvent.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event.impl.entity;
-
-import org.spongepowered.api.data.Keys;
-import org.spongepowered.api.event.cause.entity.damage.DamageFunction;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierType;
-import org.spongepowered.api.event.cause.entity.damage.ModifierFunction;
-import org.spongepowered.api.event.entity.DamageEntityEvent;
-import org.spongepowered.api.util.Tuple;
-import org.spongepowered.api.util.annotation.eventgen.UseField;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.DoubleUnaryOperator;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-public abstract class AbstractDamageEntityEvent extends AbstractModifierEvent implements DamageEntityEvent {
-
- @UseField protected double originalDamage;
- @UseField protected List originalFunctions;
- @UseField protected double baseDamage;
-
- @Override
- protected final void init() {
- this.originalFunctions = this.init(this.originalDamage, this.originalFunctions);
- this.baseDamage = this.originalDamage;
- }
-
- @Override
- public final Tuple originalModifierDamage(DamageModifier damageModifier) {
- Objects.requireNonNull(damageModifier, "The damage modifier cannot be null!");
- for (var tuple : this.originalModifiers) {
- if (tuple.first().equals(damageModifier)) {
- return tuple.second();
- }
- }
- throw new IllegalArgumentException("The provided damage modifier is not applicable: " + damageModifier.toString());
- }
-
- @Override
- public final double originalFinalDamage() {
- return this.originalFinalAmount;
- }
-
- @Override
- public final Map> originalDamages() {
-
- return this.originalModifierMap;
- }
-
- @Override
- public final double finalDamage() {
- return this.finalAmount(this.baseDamage);
- }
-
- @Override
- public final boolean isModifierApplicable(DamageModifier damageModifier) {
- return this.modifiers.containsKey(Objects.requireNonNull(damageModifier));
- }
-
- @Override
- public final Tuple damage(DamageModifier damageModifier) {
- if (!this.modifiers.containsKey(Objects.requireNonNull(damageModifier, "Damage Modifier cannot be null!"))) {
- throw new IllegalArgumentException("The provided damage modifier is not applicable: " + damageModifier);
- }
- return this.modifiers.get(Objects.requireNonNull(damageModifier));
- }
-
- @Override
- public final void setDamage(DamageModifier damageModifier, DoubleUnaryOperator function) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddTo = 0;
- boolean addAtEnd = true;
- for (Iterator iterator = this.modifierFunctions.iterator(); iterator.hasNext(); ) {
- final ModifierFunction tuple = iterator.next();
- if (tuple.modifier().equals(damageModifier)) {
- iterator.remove();
- addAtEnd = false;
- break;
- }
- indexToAddTo++;
- }
- if (addAtEnd) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddTo, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public void addDamageModifierBefore(DamageModifier damageModifier, DoubleUnaryOperator function, Set before) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddBefore = -1;
- int index = 0;
- for (ModifierFunction tuple : this.modifierFunctions) {
- if (tuple.modifier().equals(damageModifier)) {
- throw new IllegalArgumentException("Cannot add a duplicate modifier");
- }
- if (before.contains(tuple.modifier().type())) {
- indexToAddBefore = index;
- }
- index++;
-
- }
- if (indexToAddBefore == -1) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddBefore, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public void addModifierAfter(DamageModifier damageModifier, DoubleUnaryOperator function, Set after) {
- Objects.requireNonNull(damageModifier, "Damage modifier was null!");
- Objects.requireNonNull(function, "Function was null!");
- int indexToAddAfter = -1;
- int index = 0;
- for (ModifierFunction tuple : this.modifierFunctions) {
- if (tuple.modifier().equals(damageModifier)) {
- throw new IllegalArgumentException("Cannot add a duplicate modifier");
- }
- if (after.contains(tuple.modifier().type())) {
- indexToAddAfter = index;
- }
- index++;
-
- }
- if (indexToAddAfter == -1) {
- this.modifierFunctions.add(new DamageFunction(damageModifier, function));
- } else {
- this.modifierFunctions.add(indexToAddAfter + 1, new DamageFunction(damageModifier, function));
- }
- this.recalculate(this.baseDamage);
- }
-
- @Override
- protected DamageFunction convertTuple(DamageModifier obj, DoubleUnaryOperator function) {
- return new DamageFunction(obj, function);
- }
-
- @Override
- public List modifiers() {
- return this.modifierFunctions.stream().map((Function, DamageFunction>) entry -> {
- if (entry instanceof DamageFunction) {
- return (DamageFunction) entry;
- } else {
- return new DamageFunction(entry.modifier(), entry.function());
- }
- }).collect(Collectors.toUnmodifiableList());
- }
-
- @Override
- public double baseDamage() {
- return this.baseDamage;
- }
-
- @Override
- public final void setBaseDamage(double baseDamage) {
- this.baseDamage = baseDamage;
- this.recalculate(this.baseDamage);
- }
-
- @Override
- public boolean willCauseDeath() {
- final Optional health = this.entity().get(Keys.HEALTH);
- return health.isPresent() && health.get() - this.finalDamage() <= 0;
- }
-
-}
diff --git a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractModifierEvent.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractModifierEvent.java
deleted file mode 100644
index f9b99168c97..00000000000
--- a/src/main/java/org/spongepowered/api/event/impl/entity/AbstractModifierEvent.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event.impl.entity;
-
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.cause.entity.damage.ModifierFunction;
-import org.spongepowered.api.event.entity.DamageEntityEvent;
-import org.spongepowered.api.event.impl.AbstractEvent;
-import org.spongepowered.api.util.Tuple;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.DoubleUnaryOperator;
-
-/**
- * An abstract base class for implementations of {@link DamageEntityEvent}.
- *
- * @param The modifier type to use
- */
-public abstract class AbstractModifierEvent, M> extends AbstractEvent {
-
- protected double originalFinalAmount;
- protected List>> originalModifiers;
- protected Map> originalModifierMap;
- protected final LinkedHashMap> modifiers = new LinkedHashMap<>();
- protected final List modifierFunctions = new ArrayList<>();
-
- protected List init(double baseAmount, List functions) {
- functions.stream().map(entry -> this.convertTuple(entry.modifier(), entry.function())).forEach(this.modifierFunctions::add);
- this.originalFinalAmount = this.recalculate(baseAmount);
- this.originalModifiers = this.modifiers.entrySet().stream().map(e -> new Tuple<>(e.getKey(), e.getValue())).toList();
- this.originalModifierMap = Map.copyOf(this.modifiers);
- return functions.stream().map(entry -> this.convertTuple(entry.modifier(), entry.function())).toList();
- }
-
- protected abstract T convertTuple(M obj, DoubleUnaryOperator function);
-
- protected double recalculate(final double baseAmount) {
- final var amounts = AbstractModifierEvent.recalculate(this.modifierFunctions, baseAmount, this.modifiers);
- return amounts.values().stream().mapToDouble(Double::doubleValue).sum();
- }
-
- private static , M> Map recalculate(final List functions, final double baseAmount, final Map> into) {
- into.clear();
- final var defaultGroup = "default";
- final Map amounts = new HashMap<>();
- for (T func : functions) {
- var group = defaultGroup;
- if (func.modifier() instanceof DamageModifier damageModifier) {
- group = damageModifier.group();
- }
- final var oldAmount = amounts.getOrDefault(group, baseAmount);
- final var newAmount = func.function().applyAsDouble(oldAmount);
- amounts.put(group, newAmount);
- into.put(func.modifier(), new Tuple<>(oldAmount, newAmount));
- }
- if (amounts.isEmpty()) {
- amounts.put(defaultGroup, baseAmount);
- }
- return amounts;
- }
-
- protected double finalAmount(final double baseAmount) {
- final var amounts = AbstractModifierEvent.finalAmounts(baseAmount, this.modifierFunctions);
- return amounts.values().stream().mapToDouble(Double::doubleValue).sum();
- }
-
- public static , M> Map finalAmounts(final double baseAmount, final List modifiers) {
- return AbstractModifierEvent.recalculate(modifiers, baseAmount, new LinkedHashMap<>());
- }
-
- /**
- * Gets the modifiers affecting this event.
- *
- * @return The list of modifiers
- */
- public List modifiers() {
- return List.copyOf(this.modifierFunctions);
- }
-}
diff --git a/src/main/java/org/spongepowered/api/registry/RegistryTypes.java b/src/main/java/org/spongepowered/api/registry/RegistryTypes.java
index 4b1c9a87670..454889f18e6 100644
--- a/src/main/java/org/spongepowered/api/registry/RegistryTypes.java
+++ b/src/main/java/org/spongepowered/api/registry/RegistryTypes.java
@@ -116,8 +116,8 @@
import org.spongepowered.api.event.cause.entity.MovementType;
import org.spongepowered.api.event.cause.entity.SpawnType;
import org.spongepowered.api.event.cause.entity.damage.DamageEffect;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifierType;
import org.spongepowered.api.event.cause.entity.damage.DamageScaling;
+import org.spongepowered.api.event.cause.entity.damage.DamageStepType;
import org.spongepowered.api.event.cause.entity.damage.DamageType;
import org.spongepowered.api.fluid.FluidType;
import org.spongepowered.api.item.FireworkShape;
@@ -332,7 +332,7 @@ public final class RegistryTypes {
public static final DefaultedRegistryType CURRENCY = RegistryTypes.spongeKeyInGame("currency");
- public static final DefaultedRegistryType DAMAGE_MODIFIER_TYPE = RegistryTypes.spongeKeyInGame("damage_modifier_type");
+ public static final DefaultedRegistryType DAMAGE_STEP_TYPE = RegistryTypes.spongeKeyInGame("damage_step_type");
public static final DefaultedRegistryType DAMAGE_TYPE = RegistryTypes.minecraftKeyInServer("damage_type");
public static final DefaultedRegistryType DAMAGE_SCALING = RegistryTypes.spongeKeyInGame("damage_scaling");
diff --git a/src/test/java/org/spongepowered/api/event/SpongeAbstractDamageEntityEventTest.java b/src/test/java/org/spongepowered/api/event/SpongeAbstractDamageEntityEventTest.java
deleted file mode 100644
index 38ad45d342a..00000000000
--- a/src/test/java/org/spongepowered/api/event/SpongeAbstractDamageEntityEventTest.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * This file is part of SpongeAPI, licensed under the MIT License (MIT).
- *
- * Copyright (c) SpongePowered
- * Copyright (c) contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package org.spongepowered.api.event;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.spongepowered.api.entity.Entity;
-import org.spongepowered.api.event.cause.entity.damage.DamageFunction;
-import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
-import org.spongepowered.api.event.entity.DamageEntityEvent;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.DoubleUnaryOperator;
-
-class SpongeAbstractDamageEntityEventTest {
-
- private static final double ERROR = 0.03;
-
- @Test
- void testParams() {
- final Entity targetEntity = this.mockParam(Entity.class);
- final int originalDamage = 5;
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"),
- targetEntity, new ArrayList<>(), originalDamage);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.finalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.baseDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- }
-
- @Test
- void testSetBaseDamage() {
- final Entity targetEntity = this.mockParam(Entity.class);
- final int originalDamage = 5;
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"),
- targetEntity, new ArrayList<>(), originalDamage);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- event.setBaseDamage(20);
-
- Assertions.assertEquals(event.baseDamage(), 20, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.finalDamage(), 20, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- }
-
- @Test
- void testUseModifiers() {
- final Entity targetEntity = this.mockParam(Entity.class);
-
- final int originalDamage = 1;
- final int originalFinalDamage = 18;
-
- final int firstModifierDamage = 3;
- final int secondModifierDamage = 18;
-
- final DamageModifier firstModifer = this.mockParam(DamageModifier.class);
- final DamageModifier secondModifier = this.mockParam(DamageModifier.class);
-
- final var firstDamageFunction = DamageFunction.of(firstModifer, p -> p + p * 2);
- final var secondDamageFunction = DamageFunction.of(secondModifier, p -> p + p * 5);
-
- final List originalFunctions = Arrays.asList(firstDamageFunction, secondDamageFunction);
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"),
- targetEntity, originalFunctions, originalDamage);
-
- final List originalFunctions1 = event.originalFunctions();
- Assertions.assertEquals(originalFunctions1, originalFunctions);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalFinalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- final var originalDamages = event.originalDamages();
-
- Assertions.assertEquals(originalDamages.size(), originalFunctions.size());
-
- Assertions.assertEquals(originalDamages.get(firstModifer).second(), firstModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(originalDamages.get(secondModifier).second(), secondModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalModifierDamage(firstModifer).second(), firstModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalModifierDamage(secondModifier).second(), secondModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalFunctions(), originalFunctions);
- }
-
- @Test
- void testSetModifiers() {
- final Entity targetEntity = this.mockParam(Entity.class);
-
- final int originalDamage = 1;
- final int originalFinalDamage = 18;
-
- final int firstModifierDamage = 3;
- final int secondModifierDamage = 18;
-
- final int firstChangedDamage = 1;
- final int secondChangedDamage = 6;
-
- final int modifiedFinalDamage = 6;
-
- final DamageModifier firstModifer = this.mockParam(DamageModifier.class);
- final DamageModifier secondModifier = this.mockParam(DamageModifier.class);
-
-
- final var firstDamageFunction = DamageFunction.of(firstModifer, p -> p + p * 2);
- final DoubleUnaryOperator newFirstDamageFunction = p -> p;
- final var secondDamageFunction = DamageFunction.of(secondModifier, p -> p + p * 5);
- final List originalFunctions = Arrays.asList(firstDamageFunction, secondDamageFunction);
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"),
- targetEntity, originalFunctions, originalDamage);
-
- Assertions.assertEquals(event.originalFunctions(), originalFunctions);
-
- event.setDamage(firstModifer, newFirstDamageFunction);
-
- Assertions.assertEquals(event.damage(firstModifer).second(), firstChangedDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.damage(secondModifier).second(), secondChangedDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalModifierDamage(firstModifer).second(), firstModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalModifierDamage(secondModifier).second(), secondModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalFinalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.finalDamage(), modifiedFinalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalFunctions(), originalFunctions);
-
- Assertions.assertEquals(event.modifiers(), Arrays.asList(DamageFunction.of(firstModifer, newFirstDamageFunction), originalFunctions.get(1)));
- }
-
- @Test
- void testAddModifier() {
- final Entity targetEntity = this.mockParam(Entity.class);
-
- final int originalDamage = 1;
- final int originalFinalDamage = 18;
-
- final int firstModifierDamage = 3;
- final int secondModifierDamage = 18;
-
- final int modifiedFinalDamage = 36;
-
- final int thirdDamage = 36;
-
- final DamageModifier firstModifier = this.mockParam(DamageModifier.class);
- final DamageModifier secondModifier = this.mockParam(DamageModifier.class);
- final DamageModifier thirdModifier = this.mockParam(DamageModifier.class);
-
- final var firstDamageFunction = DamageFunction.of(firstModifier, p -> p + p * 2);
- final var secondDamageFunction = DamageFunction.of(secondModifier, p -> p + p * 5);
- final DoubleUnaryOperator thirdDamageFunction = p -> p + p;
-
- final List originalFunctions = Arrays.asList(firstDamageFunction, secondDamageFunction);
- final List newFunctions = new ArrayList<>(originalFunctions);
- newFunctions.add(DamageFunction.of(thirdModifier, thirdDamageFunction));
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"), targetEntity,
- originalFunctions, originalDamage);
-
- Assertions.assertEquals(event.originalFunctions(), originalFunctions);
-
- Assertions.assertFalse(event.isModifierApplicable(thirdModifier));
-
- event.setDamage(thirdModifier, thirdDamageFunction);
-
- Assertions.assertEquals(event.damage(firstModifier).second(), firstModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.damage(secondModifier).second(), secondModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.damage(thirdModifier).second(), thirdDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalModifierDamage(firstModifier).second(), firstModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalModifierDamage(secondModifier).second(), secondModifierDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalDamage(), originalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.originalFinalDamage(), originalFinalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
- Assertions.assertEquals(event.finalDamage(), modifiedFinalDamage, SpongeAbstractDamageEntityEventTest.ERROR);
-
- Assertions.assertEquals(event.originalFunctions(), originalFunctions);
-
- Assertions.assertEquals(event.modifiers(), newFunctions);
- }
-
- @Test
- void testModifiersApplicable() {
- final Entity targetEntity = this.mockParam(Entity.class);
-
- final DamageModifier firstModifer = this.mockParam(DamageModifier.class);
- final DamageModifier secondModifier = this.mockParam(DamageModifier.class);
-
- final List
- originalFunctions = Arrays.asList(DamageFunction.of(firstModifer, p -> p), DamageFunction.of(secondModifier, p -> p));
-
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"), targetEntity,
- originalFunctions, 0);
-
- Assertions.assertTrue(event.isModifierApplicable(firstModifer));
- Assertions.assertTrue(event.isModifierApplicable(secondModifier));
- Assertions.assertFalse(event.isModifierApplicable(this.mockParam(DamageModifier.class)));
- }
-
- @Test
- void testNotApplicableModifer() {
- final DamageEntityEvent event = SpongeEventFactory.createDamageEntityEvent(Cause.of(EventContext.empty(), "none"), this.mockParam(Entity.class),
- new ArrayList<>(), 0);
-
- final DamageModifier modifier = this.mockParam(DamageModifier.class);
-
- Assertions.assertFalse(event.isModifierApplicable(modifier));
-
- Assertions.assertThrows(IllegalArgumentException.class, () -> event.originalModifierDamage(modifier));
- }
-
- @SuppressWarnings("unchecked")
- private T mockParam(Class clazz) {
- return (T) Objects.requireNonNull(SpongeEventFactoryTest.mockParam(clazz));
- }
-
-}