Skip to content

Commit

Permalink
SPIGOT-7300, #829: Add new DamageSource API providing enhanced inform…
Browse files Browse the repository at this point in the history
…ation about entity damage

Co-authored-by: 2008Choco <hawkeboyz2@hotmail.com>
  • Loading branch information
2 people authored and md-5 committed Feb 10, 2024
1 parent b252cf0 commit be72314
Show file tree
Hide file tree
Showing 13 changed files with 467 additions and 27 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

<properties>
<skipTests>true</skipTests>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/bukkit/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.bukkit.block.Biome;
import org.bukkit.block.banner.PatternType;
import org.bukkit.boss.KeyedBossBar;
import org.bukkit.damage.DamageType;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Cat;
import org.bukkit.entity.EntityType;
Expand Down Expand Up @@ -207,6 +208,13 @@ public Iterator<KeyedBossBar> iterator() {
*/
@ApiStatus.Experimental
Registry<TrimPattern> TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class);
/**
* Damage types.
*
* @see DamageType
*/
@ApiStatus.Experimental
Registry<DamageType> DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug.");
/**
* Villager profession.
*
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/org/bukkit/UnsafeValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.block.data.BlockData;
import org.bukkit.damage.DamageEffect;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.CreativeCategory;
import org.bukkit.inventory.EquipmentSlot;
Expand All @@ -13,6 +16,7 @@
import org.bukkit.plugin.InvalidPluginException;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.potion.PotionType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -100,4 +104,18 @@ public interface UnsafeValues {
* @return an internal potion data
*/
PotionType.InternalPotionData getInternalPotionData(NamespacedKey key);

@ApiStatus.Internal
@Nullable
DamageEffect getDamageEffect(@NotNull String key);

/**
* Create a new {@link DamageSource.Builder}.
*
* @param damageType the {@link DamageType} to use
* @return a {@link DamageSource.Builder}
*/
@ApiStatus.Internal
@NotNull
DamageSource.Builder createDamageSourceBuilder(@NotNull DamageType damageType);
}
53 changes: 53 additions & 0 deletions src/main/java/org/bukkit/damage/DamageEffect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.bukkit.damage;

import com.google.common.base.Preconditions;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

/**
* Represents a type of effect that occurs when damage is inflicted. Currently,
* effects only determine the sound that plays.
*/
@ApiStatus.Experimental
public interface DamageEffect {

/**
* The default damage effect.
*/
public static final DamageEffect HURT = getDamageEffect("hurt");
/**
* Thorns.
*/
public static final DamageEffect THORNS = getDamageEffect("thorns");
/**
* Drowning.
*/
public static final DamageEffect DROWNING = getDamageEffect("drowning");
/**
* A single burn tick (fire, lava, etc.).
*/
public static final DamageEffect BURNING = getDamageEffect("burning");
/**
* Poked by a berry bush.
*/
public static final DamageEffect POKING = getDamageEffect("poking");
/**
* Freeze tick (powder snow).
*/
public static final DamageEffect FREEZING = getDamageEffect("freezing");

@NotNull
private static DamageEffect getDamageEffect(@NotNull String key) {
return Preconditions.checkNotNull(Bukkit.getUnsafe().getDamageEffect(key), "No DamageEffect found for %s. This is a bug.", key);
}

/**
* Get the {@link Sound} played for this {@link DamageEffect}.
*
* @return the sound
*/
@NotNull
public Sound getSound();
}
26 changes: 26 additions & 0 deletions src/main/java/org/bukkit/damage/DamageScaling.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.bukkit.damage;

import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;

/**
* A means of damage scaling with respect to the server's difficulty.
*/
@ApiStatus.Experimental
public enum DamageScaling {

/**
* Damage is not scaled.
*/
NEVER,
/**
* Damage is scaled only when the
* {@link DamageSource#getCausingEntity() causing entity} is not a
* {@link Player}.
*/
WHEN_CAUSED_BY_LIVING_NON_PLAYER,
/**
* Damage is always scaled.
*/
ALWAYS;
}
155 changes: 155 additions & 0 deletions src/main/java/org/bukkit/damage/DamageSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package org.bukkit.damage;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Represents a source of damage.
*/
@ApiStatus.Experimental
public interface DamageSource {

/**
* Get the {@link DamageType}.
*
* @return the damage type
*/
@NotNull
public DamageType getDamageType();

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

/**
* Get the {@link Entity} that directly caused the damage.
* <p>
* Not to be confused with {@link #getCausingEntity()}, the direct entity is
* the entity that actually inflicted the damage. If, for example, the
* receiver was damaged by a projectile, the projectile would be returned.
*
* @return an Entity or null
*/
@Nullable
public Entity getDirectEntity();

/**
* Get the {@link Location} from where the damage originated. This will only
* be present if an entity did not cause the damage.
*
* @return the location, or null if none
*/
@Nullable
public Location getDamageLocation();

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

/**
* Get if this damage is indirect.
* <p>
* Damage is considered indirect if {@link #getCausingEntity()} is not equal
* to {@link #getDirectEntity()}. This will be the case, for example, if a
* skeleton shot an arrow or a player threw a potion.
*
* @return {@code true} if is indirect, {@code false} otherwise.
*/
public boolean isIndirect();

/**
* Get the amount of hunger exhaustion caused by this damage.
*
* @return the amount of hunger exhaustion caused.
*/
public float getFoodExhaustion();

/**
* Gets if this source of damage scales with difficulty.
*
* @return {@code True} if scales.
*/
public boolean scalesWithDifficulty();

/**
* Create a new {@link DamageSource.Builder}.
*
* @param damageType the {@link DamageType} to use
* @return a {@link DamageSource.Builder}
*/
@NotNull
@SuppressWarnings("deprecation")
public static Builder builder(@NotNull DamageType damageType) {
return Bukkit.getUnsafe().createDamageSourceBuilder(damageType);
}

/**
* Utility class to make building a {@link DamageSource} easier. Only a
* {@link DamageType} is required.
*/
public static interface Builder {

/**
* Set the {@link Entity} that caused the damage.
*
* @param entity the entity
* @return this instance. Allows for chained method calls
* @see DamageSource#getCausingEntity()
*/
@NotNull
public Builder withCausingEntity(@NotNull Entity entity);

/**
* Set the {@link Entity} that directly inflicted the damage.
*
* @param entity the entity
* @return this instance. Allows for chained method calls
* @see DamageSource#getDirectEntity()
*/
@NotNull
public Builder withDirectEntity(@NotNull Entity entity);

/**
* Set the {@link Location} of the source of damage.
*
* @param location the location where the damage occurred
* @return this instance. Allows for chained method calls
* @see DamageSource#getSourceLocation()
*/
@NotNull
public Builder withDamageLocation(@NotNull Location location);

/**
* Create a new {@link DamageSource} instance using the supplied
* parameters.
*
* @return the damage source instance
*/
@NotNull
public DamageSource build();
}
}
Loading

0 comments on commit be72314

Please sign in to comment.