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 65e99fa592a..69b2b482034 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,255 +24,87 @@ */ 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 org.spongepowered.api.Sponge; +import org.spongepowered.api.event.CauseStackManager; -import java.util.Objects; import java.util.Optional; -import java.util.StringJoiner; -import java.util.function.DoubleUnaryOperator; -import java.util.function.Supplier; +import java.util.function.Consumer; /** - * 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 create a {@link DamageStep}. */ public interface DamageModifier { /** - * Creates a new {@link Builder} for constructing a {@link DamageModifier}. + * Gets the {@link DamageStepType} of this modifier. * - * @return A new builder + * @return the step type */ - static Builder builder() { - return new Builder(); - } + DamageStepType type(); /** - * Gets the {@link DamageModifierType} for this {@link DamageModifier}. + * Gets the consumer that will modify the cause frame. * - * @return The damage modifier type + * @return The cause frame modifier */ - DamageModifierType type(); + Optional> frame(); /** - * Returns the damage modifier group. - *

Grouped modifiers calculate their damage independently from each other

+ * Gets the function that will modify the damage. + * The function may be absent if the sole purpose of this modifier is to apply children steps. * - * @return The damage modifier group + * @return the damage modifier */ - String group(); + Optional damage(); - /** - * Gets the cause of this {@link DamageModifier}. - * - * @return The cause of this damage modifier - */ - Cause cause(); + @FunctionalInterface + interface Function { + /** + * Modifies the damage. + * + * @param step The damage step this modifier is associated with. + * @param damage The current damage value. + * @return The next damage value + */ + double modify(DamageStep step, double damage); + } /** - * 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. + * Creates a new {@link Builder} to create {@link DamageModifier}s. * - * @return The contributing item, if available + * @return The new builder */ - Optional contributingItem(); + static Builder builder() { + return Sponge.game().builderProvider().provide(Builder.class); + } /** - * A builder that creates {@link DamageModifier}s, for use in both plugin and - * implementation requirements. + * A builder to create {@link DamageModifier}s. */ - 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 damageModifierType) { - return this.type(damageModifierType.get()); - } + interface Builder extends org.spongepowered.api.util.Builder { /** - * Sets the {@link DamageModifierType} for the {@link DamageModifier} to - * build. + * Sets the {@link DamageStepType} for this modifier. * - * @param damageModifierType The damage modifier type - * @return This builder, for chaining + * @param type The damage step type + * @return this builder for chaining */ - public Builder type(final DamageModifierType damageModifierType) { - this.type = java.util.Objects.requireNonNull(damageModifierType); - return this; - } + Builder type(DamageStepType type); /** - * The main attack damage calculated for an {@link org.spongepowered.api.event.entity.AttackEntityEvent} + * Sets the cause frame modifier. * - * @return This builder, for chaining + * @param frameModifier The frame modifier + * @return this builder for chaining */ - public Builder attackDamageGroup() { - return this.group("minecraft:attack_damage"); - } + Builder frame(Consumer frameModifier); /** - * The enchantment attack damage calculated for an {@link org.spongepowered.api.event.entity.AttackEntityEvent} + * Sets the {@link Function} for this modifier. * - * @return This builder, for chaining + * @param function The damage function + * @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; - } - - 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(); - } - } - + Builder damage(Function function); } } 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..a60381bf4de --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStep.java @@ -0,0 +1,156 @@ +/* + * 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; +import java.util.Optional; +import java.util.OptionalDouble; + +/** + * A step represent an operation made by the platform (vanilla and mods) or modifiers added by plugins. + * Steps are structured as trees where children modify the input or output of the parent step. + * A damage calculation is made of multiple trees of steps. + */ +public interface DamageStep { + + /** + * Gets the {@link DamageStepType} of this step. + * + * @return the step type + */ + DamageStepType type(); + + /** + * Gets the {@link Cause} of this step. + * + * @return The cause of this step + */ + Cause cause(); + + /** + * Gets whether this step is skipped. + * When skipped, only the step itself and its side effects are ignored, children are still applied. + * A modifier willing to ignore every previous children should revert the damage to {@link #damageBeforeChildren()}, + * or call {@link #skip} on each child. + * + * @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 children of this step. + * Returns empty if the value is not known yet. + * + * @return The damage before the children of this step + */ + OptionalDouble damageBeforeChildren(); + + /** + * The damage just before this step. + * Returns empty if the value is not known yet. + * + * @return The damage before this step + */ + OptionalDouble damageBeforeSelf(); + + /** + * The damage just after this step. + * Returns empty if the value is not known yet. + * + * @return The damage after this step + */ + OptionalDouble damageAfterSelf(); + + /** + * The damage just after the children of this step. + * Returns empty if the value is not known yet. + * + * @return The damage after this step + */ + OptionalDouble damageAfterChildren(); + + /** + * Gets the {@link DamageStepHistory} this step belongs to. + * + * @return The history containing this step. + */ + DamageStepHistory history(); + + /** + * Gets the parent of this step. + * Returns empty if this step is the root of its tree. + * + * @return The parent of this step + */ + Optional parent(); + + /** + * Gets the root of this step. + * + * @return The root of this step + */ + default DamageStep root() { + DamageStep step = this; + Optional parent; + while ((parent = step.parent()).isPresent()) { + step = parent.get(); + } + return step; + } + + /** + * Gets an immutable list of all children steps that applies just before this step. + * + * @return The list of children steps + */ + List childrenBefore(); + + /** + * Gets an immutable list of all children steps that applies just after this step. + * + * @return The list of children steps + */ + List childrenAfter(); +} diff --git a/src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepHistory.java similarity index 71% rename from src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java rename to src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepHistory.java index a13e4dfaecf..cd2d3958fa3 100644 --- a/src/main/java/org/spongepowered/api/event/cause/entity/damage/ModifierFunction.java +++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepHistory.java @@ -24,29 +24,20 @@ */ package org.spongepowered.api.event.cause.entity.damage; -import java.util.function.DoubleUnaryOperator; +import java.util.List; /** - * A function associating a - * {@link DamageModifier} with a {@link DoubleUnaryOperator} of the resultant - * effect. - * - * @param The modifier type + * Captures the root steps occurring during a damage calculation. */ -public interface ModifierFunction { - - /** - * Gets the modifier used by this modifier function. - * - * @return The modifier - */ - M modifier(); +public interface DamageStepHistory { /** - * Gets the double unary operator used by this function. + * Gets the list of the captured root 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. + * The list is unmodifiable and will gradually grow during the damage calculation. * - * @return The unary operator + * @return The root steps. */ - DoubleUnaryOperator function(); - + List rootSteps(); } 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 68% 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..ca74abeadd7 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 @@ -24,18 +24,35 @@ */ package org.spongepowered.api.event.cause.entity.damage; -import org.spongepowered.api.event.Cause; +import org.spongepowered.api.Sponge; import org.spongepowered.api.registry.DefaultedRegistryValue; import org.spongepowered.api.util.annotation.CatalogedBy; /** - * A type of {@link DamageModifier} 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} - * without digging through the {@link Cause} provided by - * {@link DamageModifier#cause()}. + * Represents a type of {@link DamageStep}. */ -@CatalogedBy(DamageModifierTypes.class) -public interface DamageModifierType extends DefaultedRegistryValue { +@CatalogedBy(DamageStepTypes.class) +public interface DamageStepType extends DefaultedRegistryValue { + /** + * Creates a new {@link DamageStepType}. + * + * @return the new step type + */ + static DamageStepType create() { + return Sponge.game().factoryProvider().provide(Factory.class).create(); + } + + /** + * A factory to create {@link DamageStepType}s. + */ + interface Factory { + + /** + * Creates a new {@link DamageStepType}. + * + * @return the new step type + */ + DamageStepType create(); + } } 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..4b8893f7872 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/cause/entity/damage/DamageStepTypes.java @@ -0,0 +1,204 @@ +/* + * 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 the last {@link DamageStep} applied during a damage calculation. + * This step happens just before the {@link org.spongepowered.api.event.entity.DamageCalculationEvent.Post}. + * This step does nothing but can be used to add modifiers to the final damage. + */ + public static final DefaultedRegistryReference END = DamageStepTypes.key(ResourceKey.sponge("end")); + + /** + * 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 the first {@link DamageStep} applied during a damage calculation. + * This step happens just after the {@link org.spongepowered.api.event.entity.DamageCalculationEvent.Pre}. + * This step does nothing but can be used to add modifiers to the base damage. + */ + public static final DefaultedRegistryReference START = DamageStepTypes.key(ResourceKey.sponge("start")); + + /** + * 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 730037117d8..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,37 +25,18 @@ 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.world.World; import org.spongepowered.api.world.difficulty.Difficulties; import org.spongepowered.api.world.difficulty.Difficulty; -import org.spongepowered.eventgen.annotations.ImplementedBy; -import org.spongepowered.eventgen.annotations.PropertySettings; - -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". @@ -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..0f8752a1296 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/entity/DamageCalculationEvent.java @@ -0,0 +1,184 @@ +/* + * 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.DamageStepHistory; +import org.spongepowered.api.event.cause.entity.damage.DamageStepType; +import org.spongepowered.api.event.cause.entity.damage.DamageStepTypes; +import org.spongepowered.api.event.impl.entity.AbstractDamageCalculationEventPre; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.world.difficulty.Difficulty; +import org.spongepowered.eventgen.annotations.ImplementedBy; + +import java.util.List; +import java.util.function.Supplier; + +/** + * 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 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 base damage to deal to the targeted {@link Entity}. + * The base damage is the value before the calculation and its {@link DamageStep}s. + * To modify the base damage, add a modifier to the step associated to {@link DamageStepTypes#START}. + * + * @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 { + + /** + * Gets an unmodifiable list of all modifiers that applies just before the step. + * + * @param type The step type + * @return The list of modifiers + */ + default List modifiersBefore(Supplier type) { + return this.modifiersBefore(type.get()); + } + + /** + * Gets an unmodifiable list of all modifiers that applies just before the step. + * + * @param type The step type + * @return The list of modifiers + */ + List modifiersBefore(DamageStepType type); + + /** + * Adds a modifier that applies just before the step. + * + * @param type The step type + * @param modifier The modifier + */ + default void addModifierBefore(Supplier type, DamageModifier modifier) { + this.addModifierBefore(type.get(), modifier); + } + + /** + * Adds a modifier that applies just before the step. + * + * @param type The step type + * @param modifier The modifier + */ + void addModifierBefore(DamageStepType type, DamageModifier modifier); + + /** + * Gets an unmodifiable list of all modifiers that applies just after the step. + * + * @param type The step type + * @return The list of modifiers + */ + default List modifiersAfter(Supplier type) { + return this.modifiersAfter(type.get()); + } + + /** + * Gets an unmodifiable list of all modifiers that applies just after the step. + * + * @param type The step type + * @return The list of modifiers + */ + List modifiersAfter(DamageStepType type); + + /** + * Adds a modifier that applies just after the step. + * + * @param type The step type + * @param modifier The modifier + */ + default void addModifierAfter(Supplier type, DamageModifier modifier) { + this.addModifierAfter(type.get(), modifier); + } + + /** + * Adds a modifier that applies just after the step. + * + * @param type The step type + * @param modifier The modifier + */ + void addModifierAfter(DamageStepType type, DamageModifier modifier); + } + + /** + * 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 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. + * To modify the final damage, add a modifier to the step associated to {@link DamageStepTypes#END}. + * + * @return The final damage + */ + double finalDamage(); + + /** + * Gets the {@link DamageStepHistory} of this damage calculation. + * + * @return The history. + */ + DamageStepHistory history(); + } +} 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 5854bdcc909..a4cab3e9138 100644 --- a/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java +++ b/src/main/java/org/spongepowered/api/event/entity/DamageEntityEvent.java @@ -29,32 +29,20 @@ 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.event.impl.entity.AbstractDamageEntityEventPost; import org.spongepowered.api.item.ItemTypes; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.util.Tuple; import org.spongepowered.api.world.World; import org.spongepowered.api.world.difficulty.Difficulties; import org.spongepowered.api.world.difficulty.Difficulty; import org.spongepowered.eventgen.annotations.ImplementedBy; import org.spongepowered.eventgen.annotations.PropertySettings; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.DoubleUnaryOperator; - /** - * 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,29 @@ * 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(); + @ImplementedBy(AbstractDamageEntityEventPost.class) + 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 + */ + @PropertySettings(requiredParameter = false, generateMethods = false) + boolean willCauseDeath(); + } } 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 d8f63462257..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.eventgen.annotations.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/impl/entity/AbstractDamageCalculationEventPre.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageCalculationEventPre.java new file mode 100644 index 00000000000..45509339073 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageCalculationEventPre.java @@ -0,0 +1,69 @@ +/* + * 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.DamageStepType; +import org.spongepowered.api.event.entity.DamageCalculationEvent; +import org.spongepowered.api.event.impl.AbstractEvent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public abstract class AbstractDamageCalculationEventPre extends AbstractEvent implements DamageCalculationEvent.Pre { + private final Map> modifiersBeforeMap = new HashMap<>(); + private final Map> modifiersAfterMap = new HashMap<>(); + + private List getModifiersBefore(DamageStepType type) { + return this.modifiersBeforeMap.computeIfAbsent(type, k -> new LinkedList<>()); + } + + private List getModifiersAfter(DamageStepType type) { + return this.modifiersAfterMap.computeIfAbsent(type, k -> new LinkedList<>()); + } + + @Override + public List modifiersBefore(DamageStepType type) { + return Collections.unmodifiableList(this.getModifiersBefore(type)); + } + + @Override + public List modifiersAfter(DamageStepType type) { + return Collections.unmodifiableList(this.getModifiersAfter(type)); + } + + @Override + public void addModifierBefore(DamageStepType type, DamageModifier modifier) { + this.getModifiersBefore(type).addFirst(modifier); + } + + @Override + public void addModifierAfter(DamageStepType type, DamageModifier modifier) { + this.getModifiersAfter(type).addLast(modifier); + } +} 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 55377efb27b..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.eventgen.annotations.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/AbstractDamageEntityEventPost.java b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageEntityEventPost.java new file mode 100644 index 00000000000..8dfbaffb345 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/impl/entity/AbstractDamageEntityEventPost.java @@ -0,0 +1,40 @@ +/* + * 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.entity.DamageEntityEvent; +import org.spongepowered.api.event.impl.AbstractEvent; + +import java.util.Optional; + +public abstract class AbstractDamageEntityEventPost extends AbstractEvent implements DamageEntityEvent.Post { + + @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 4abe9b9cd95..3d191288c93 100644 --- a/src/main/java/org/spongepowered/api/registry/RegistryTypes.java +++ b/src/main/java/org/spongepowered/api/registry/RegistryTypes.java @@ -120,8 +120,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; @@ -345,7 +345,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)); - } - -}