mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-02 14:38:26 +01:00
chore: port DamageType cleanup change from MelonHell 1.19.4 PR
(cherry picked from commit 9eab3d4f8b
)
This commit is contained in:
parent
d0ace48220
commit
9439b62ff0
@ -33,6 +33,7 @@ public class Generators {
|
||||
generator.generate(resource("particles.json"), "net.minestom.server.particle", "Particle", "ParticleImpl", "Particles");
|
||||
generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "SoundEventImpl", "SoundEvents");
|
||||
generator.generate(resource("custom_statistics.json"), "net.minestom.server.statistic", "StatisticType", "StatisticTypeImpl", "StatisticTypes");
|
||||
generator.generate(resource("damage_types.json"), "net.minestom.server.entity.damage", "DamageType", "DamageTypeImpl", "DamageTypes");
|
||||
|
||||
// Generate fluids
|
||||
new FluidGenerator(resource("fluids.json"), outputFolder).generate();
|
||||
|
@ -10,7 +10,7 @@ import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.entity.ItemEntity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.entity.damage.Damage;
|
||||
import net.minestom.server.event.Event;
|
||||
import net.minestom.server.event.EventNode;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
@ -28,13 +28,11 @@ import net.minestom.server.item.metadata.BundleMeta;
|
||||
import net.minestom.server.monitoring.BenchmarkManager;
|
||||
import net.minestom.server.monitoring.TickMonitor;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@ -51,7 +49,7 @@ public class PlayerInit {
|
||||
|
||||
if (entity instanceof Player) {
|
||||
Player target = (Player) entity;
|
||||
target.damage(DamageType.fromEntity(source), 5);
|
||||
target.damage(Damage.fromEntity(source, 5));
|
||||
}
|
||||
|
||||
if (source instanceof Player) {
|
||||
|
@ -0,0 +1,95 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
/**
|
||||
* Code autogenerated, do not edit!
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
interface DamageTypes {
|
||||
DamageType WITHER = DamageTypeImpl.get("minecraft:wither");
|
||||
|
||||
DamageType SONIC_BOOM = DamageTypeImpl.get("minecraft:sonic_boom");
|
||||
|
||||
DamageType WITHER_SKULL = DamageTypeImpl.get("minecraft:wither_skull");
|
||||
|
||||
DamageType DRY_OUT = DamageTypeImpl.get("minecraft:dry_out");
|
||||
|
||||
DamageType TRIDENT = DamageTypeImpl.get("minecraft:trident");
|
||||
|
||||
DamageType ON_FIRE = DamageTypeImpl.get("minecraft:on_fire");
|
||||
|
||||
DamageType FALL = DamageTypeImpl.get("minecraft:fall");
|
||||
|
||||
DamageType MOB_ATTACK = DamageTypeImpl.get("minecraft:mob_attack");
|
||||
|
||||
DamageType MOB_PROJECTILE = DamageTypeImpl.get("minecraft:mob_projectile");
|
||||
|
||||
DamageType THROWN = DamageTypeImpl.get("minecraft:thrown");
|
||||
|
||||
DamageType FALLING_STALACTITE = DamageTypeImpl.get("minecraft:falling_stalactite");
|
||||
|
||||
DamageType FIREBALL = DamageTypeImpl.get("minecraft:fireball");
|
||||
|
||||
DamageType FALLING_BLOCK = DamageTypeImpl.get("minecraft:falling_block");
|
||||
|
||||
DamageType PLAYER_EXPLOSION = DamageTypeImpl.get("minecraft:player_explosion");
|
||||
|
||||
DamageType STING = DamageTypeImpl.get("minecraft:sting");
|
||||
|
||||
DamageType UNATTRIBUTED_FIREBALL = DamageTypeImpl.get("minecraft:unattributed_fireball");
|
||||
|
||||
DamageType IN_WALL = DamageTypeImpl.get("minecraft:in_wall");
|
||||
|
||||
DamageType IN_FIRE = DamageTypeImpl.get("minecraft:in_fire");
|
||||
|
||||
DamageType ARROW = DamageTypeImpl.get("minecraft:arrow");
|
||||
|
||||
DamageType HOT_FLOOR = DamageTypeImpl.get("minecraft:hot_floor");
|
||||
|
||||
DamageType DROWN = DamageTypeImpl.get("minecraft:drown");
|
||||
|
||||
DamageType STARVE = DamageTypeImpl.get("minecraft:starve");
|
||||
|
||||
DamageType GENERIC_KILL = DamageTypeImpl.get("minecraft:generic_kill");
|
||||
|
||||
DamageType DRAGON_BREATH = DamageTypeImpl.get("minecraft:dragon_breath");
|
||||
|
||||
DamageType MOB_ATTACK_NO_AGGRO = DamageTypeImpl.get("minecraft:mob_attack_no_aggro");
|
||||
|
||||
DamageType LAVA = DamageTypeImpl.get("minecraft:lava");
|
||||
|
||||
DamageType OUTSIDE_BORDER = DamageTypeImpl.get("minecraft:outside_border");
|
||||
|
||||
DamageType FLY_INTO_WALL = DamageTypeImpl.get("minecraft:fly_into_wall");
|
||||
|
||||
DamageType LIGHTNING_BOLT = DamageTypeImpl.get("minecraft:lightning_bolt");
|
||||
|
||||
DamageType PLAYER_ATTACK = DamageTypeImpl.get("minecraft:player_attack");
|
||||
|
||||
DamageType FREEZE = DamageTypeImpl.get("minecraft:freeze");
|
||||
|
||||
DamageType FALLING_ANVIL = DamageTypeImpl.get("minecraft:falling_anvil");
|
||||
|
||||
DamageType OUT_OF_WORLD = DamageTypeImpl.get("minecraft:out_of_world");
|
||||
|
||||
DamageType MAGIC = DamageTypeImpl.get("minecraft:magic");
|
||||
|
||||
DamageType SWEET_BERRY_BUSH = DamageTypeImpl.get("minecraft:sweet_berry_bush");
|
||||
|
||||
DamageType FIREWORKS = DamageTypeImpl.get("minecraft:fireworks");
|
||||
|
||||
DamageType EXPLOSION = DamageTypeImpl.get("minecraft:explosion");
|
||||
|
||||
DamageType BAD_RESPAWN_POINT = DamageTypeImpl.get("minecraft:bad_respawn_point");
|
||||
|
||||
DamageType STALAGMITE = DamageTypeImpl.get("minecraft:stalagmite");
|
||||
|
||||
DamageType THORNS = DamageTypeImpl.get("minecraft:thorns");
|
||||
|
||||
DamageType INDIRECT_MAGIC = DamageTypeImpl.get("minecraft:indirect_magic");
|
||||
|
||||
DamageType CRAMMING = DamageTypeImpl.get("minecraft:cramming");
|
||||
|
||||
DamageType CACTUS = DamageTypeImpl.get("minecraft:cactus");
|
||||
|
||||
DamageType GENERIC = DamageTypeImpl.get("minecraft:generic");
|
||||
}
|
@ -6,6 +6,7 @@ import net.minestom.server.attribute.AttributeInstance;
|
||||
import net.minestom.server.collision.BoundingBox;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.damage.Damage;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.entity.metadata.LivingEntityMeta;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
@ -48,7 +49,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
||||
|
||||
protected boolean isDead;
|
||||
|
||||
protected DamageType lastDamageSource;
|
||||
protected Damage lastDamage;
|
||||
|
||||
// Bounding box used for items' pickup (see LivingEntity#setBoundingBox)
|
||||
protected BoundingBox expandedBoundingBox;
|
||||
@ -310,26 +311,29 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean damage(@NotNull DamageType type, float amount) {
|
||||
return damage(new Damage(type, null, null, null, amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Damages the entity by a value, the type of the damage also has to be specified.
|
||||
*
|
||||
* @param type the damage type
|
||||
* @param value the amount of damage
|
||||
* @param damage the damage to be applied
|
||||
* @return true if damage has been applied, false if it didn't
|
||||
*/
|
||||
public boolean damage(@NotNull DamageType type, float value) {
|
||||
public boolean damage(@NotNull Damage damage) {
|
||||
if (isDead())
|
||||
return false;
|
||||
if (isInvulnerable() || isImmune(type)) {
|
||||
if (isInvulnerable() || isImmune(damage.getType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value, type.getSound(this));
|
||||
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, damage, damage.getSound(this));
|
||||
EventDispatcher.callCancellable(entityDamageEvent, () -> {
|
||||
// Set the last damage type since the event is not cancelled
|
||||
this.lastDamageSource = entityDamageEvent.getDamageType();
|
||||
this.lastDamage = entityDamageEvent.getDamage();
|
||||
|
||||
float remainingDamage = entityDamageEvent.getDamage();
|
||||
float remainingDamage = entityDamageEvent.getDamage().getAmount();
|
||||
|
||||
if (entityDamageEvent.shouldAnimate()) {
|
||||
sendPacketToViewersAndSelf(new EntityAnimationPacket(getEntityId(), EntityAnimationPacket.Animation.TAKE_DAMAGE));
|
||||
@ -410,8 +414,8 @@ public class LivingEntity extends Entity implements EquipmentHandler {
|
||||
*
|
||||
* @return the last damage source, null if not any
|
||||
*/
|
||||
public @Nullable DamageType getLastDamageSource() {
|
||||
return lastDamageSource;
|
||||
public @Nullable Damage getLastDamageSource() {
|
||||
return lastDamage;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,7 +69,6 @@ import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.resourcepack.ResourcePack;
|
||||
import net.minestom.server.scoreboard.BelowNameTag;
|
||||
import net.minestom.server.scoreboard.Team;
|
||||
@ -98,8 +97,6 @@ import org.jctools.queues.MpscUnboundedXaddArrayQueue;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
@ -415,8 +412,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
|
||||
// get death screen text to the killed player
|
||||
{
|
||||
if (lastDamageSource != null) {
|
||||
deathText = lastDamageSource.buildDeathScreenText(this);
|
||||
if (lastDamage != null) {
|
||||
deathText = lastDamage.buildDeathScreenText(this);
|
||||
} else { // may happen if killed by the server without applying damage
|
||||
deathText = Component.text("Killed by poor programming.");
|
||||
}
|
||||
@ -424,8 +421,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
|
||||
// get death message to chat
|
||||
{
|
||||
if (lastDamageSource != null) {
|
||||
chatMessage = lastDamageSource.buildDeathMessage(this);
|
||||
if (lastDamage != null) {
|
||||
chatMessage = lastDamage.buildDeathMessage(this);
|
||||
} else { // may happen if killed by the server without applying damage
|
||||
chatMessage = Component.text(getUsername() + " was killed by poor programming.");
|
||||
}
|
||||
@ -920,7 +917,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
@Override
|
||||
public boolean isImmune(@NotNull DamageType type) {
|
||||
if (!getGameMode().canTakeDamage()) {
|
||||
return type != DamageType.VOID;
|
||||
return type != DamageType.OUT_OF_WORLD;
|
||||
}
|
||||
return super.isImmune(type);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.minestom.server.entity.ai.target;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
import net.minestom.server.entity.ai.TargetSelector;
|
||||
import net.minestom.server.entity.damage.Damage;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.entity.damage.EntityDamage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -21,8 +22,8 @@ public class LastEntityDamagerTarget extends TargetSelector {
|
||||
|
||||
@Override
|
||||
public Entity findTarget() {
|
||||
final DamageType damageType = entityCreature.getLastDamageSource();
|
||||
if (!(damageType instanceof EntityDamage entityDamage)) {
|
||||
final Damage damage = entityCreature.getLastDamageSource();
|
||||
if (!(damage instanceof EntityDamage entityDamage)) {
|
||||
// No damager recorded, return null
|
||||
return null;
|
||||
}
|
||||
|
179
src/main/java/net/minestom/server/entity/damage/Damage.java
Normal file
179
src/main/java/net/minestom/server/entity/damage/Damage.java
Normal file
@ -0,0 +1,179 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.Taggable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a type of damage, required when calling {@link LivingEntity#damage(Damage)}
|
||||
* and retrieved in {@link net.minestom.server.event.entity.EntityDamageEvent}.
|
||||
* <p>
|
||||
* This class can be extended if you need to include custom fields and/or methods.
|
||||
*/
|
||||
public class Damage implements Taggable {
|
||||
|
||||
private final DamageType type;
|
||||
private final Entity source;
|
||||
private final Entity attacker;
|
||||
private final Point sourcePosition;
|
||||
private final TagHandler tagHandler = TagHandler.newHandler();
|
||||
|
||||
private float amount;
|
||||
|
||||
/**
|
||||
* Creates a new damage type.
|
||||
*
|
||||
* @param type the type of this damage
|
||||
* @param amount amount of damage
|
||||
*/
|
||||
public Damage(@NotNull DamageType type, @Nullable Entity source, @Nullable Entity attacker, @Nullable Point sourcePosition, float amount) {
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
this.attacker = attacker;
|
||||
this.sourcePosition = sourcePosition;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this damage.
|
||||
* <p>
|
||||
* It does not have to be unique to this object.o
|
||||
*
|
||||
* @return the damage type
|
||||
*/
|
||||
public @NotNull DamageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "attacker" of the damage.
|
||||
* This is the indirect cause of the damage, like the shooter of a projectile, or null if there was none.
|
||||
*
|
||||
* @return the attacker
|
||||
*/
|
||||
public @Nullable Entity getAttacker() {
|
||||
return attacker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the direct source of the damage.
|
||||
* This is the entity that directly causes the damage, like a projectile, or null if there was none.
|
||||
*
|
||||
* @return the source
|
||||
*/
|
||||
public @Nullable Entity getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of the source of the damage, or null if there is none.
|
||||
* This may differ from the source entity's position.
|
||||
*
|
||||
* @return The source position
|
||||
*/
|
||||
public @Nullable Point getSourcePosition() {
|
||||
return sourcePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the death message linked to this damage type.
|
||||
* <p>
|
||||
* Used in {@link Player#kill()} to broadcast the proper message.
|
||||
*
|
||||
* @param killed the player who has been killed
|
||||
* @return the death message, null to do not send anything
|
||||
*/
|
||||
public @Nullable Component buildDeathMessage(@NotNull Player killed) {
|
||||
return Component.translatable("death.attack." + type.messageId(), Component.text(killed.getUsername()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityProjectileDamage}.
|
||||
*
|
||||
* @param shooter the shooter
|
||||
* @param projectile the actual projectile
|
||||
* @param amount amount of damage
|
||||
* @return a new {@link EntityProjectileDamage}
|
||||
*/
|
||||
public static @NotNull Damage fromProjectile(@Nullable Entity shooter, @NotNull Entity projectile, float amount) {
|
||||
return new EntityProjectileDamage(shooter, projectile, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityDamage}.
|
||||
*
|
||||
* @param player the player damager
|
||||
* @param amount amount of damage
|
||||
* @return a new {@link EntityDamage}
|
||||
*/
|
||||
public static @NotNull EntityDamage fromPlayer(@NotNull Player player, float amount) {
|
||||
return new EntityDamage(player, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityDamage}.
|
||||
*
|
||||
* @param entity the entity damager
|
||||
* @param amount amount of damage
|
||||
* @return a new {@link EntityDamage}
|
||||
*/
|
||||
public static @NotNull EntityDamage fromEntity(@NotNull Entity entity, float amount) {
|
||||
return new EntityDamage(entity, amount);
|
||||
}
|
||||
|
||||
public static @NotNull PositionalDamage fromPosition(@NotNull DamageType type, @NotNull Point sourcePosition, float amount) {
|
||||
return new PositionalDamage(type, sourcePosition, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the text sent to a player in his death screen.
|
||||
*
|
||||
* @param killed the player who has been killed
|
||||
* @return the death screen text, null to do not send anything
|
||||
*/
|
||||
public @Nullable Component buildDeathScreenText(@NotNull Player killed) {
|
||||
return Component.translatable("death.attack." + type.messageId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sound event to play when the given entity is hit by this damage. Possible to return null if no sound should be played
|
||||
*
|
||||
* @param entity the entity hit by this damage
|
||||
* @return the sound to play when the given entity is hurt by this damage type. Can be null if no sound should play
|
||||
*/
|
||||
public @Nullable SoundEvent getSound(@NotNull LivingEntity entity) {
|
||||
if (entity instanceof Player) {
|
||||
return getPlayerSound((Player) entity);
|
||||
}
|
||||
return getGenericSound(entity);
|
||||
}
|
||||
|
||||
protected SoundEvent getGenericSound(@NotNull LivingEntity entity) {
|
||||
return SoundEvent.ENTITY_GENERIC_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getPlayerSound(@NotNull Player player) {
|
||||
if (type == DamageType.ON_FIRE) return SoundEvent.ENTITY_PLAYER_HURT_ON_FIRE;
|
||||
return SoundEvent.ENTITY_PLAYER_HURT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TagHandler tagHandler() {
|
||||
return tagHandler;
|
||||
}
|
||||
|
||||
public float getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(float amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
@ -1,131 +1,60 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.Taggable;
|
||||
import net.minestom.server.registry.ProtocolObject;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
/**
|
||||
* Represents a type of damage, required when calling {@link LivingEntity#damage(DamageType, float)}
|
||||
* and retrieved in {@link net.minestom.server.event.entity.EntityDamageEvent}.
|
||||
* <p>
|
||||
* This class can be extended if you need to include custom fields and/or methods.
|
||||
*/
|
||||
public class DamageType implements Taggable {
|
||||
|
||||
public static final DamageType VOID = new DamageType("attack.outOfWorld");
|
||||
public static final DamageType GRAVITY = new DamageType("attack.fall");
|
||||
public static final DamageType ON_FIRE = new DamageType("attack.onFire") {
|
||||
@Override
|
||||
protected SoundEvent getPlayerSound(@NotNull Player player) {
|
||||
return SoundEvent.ENTITY_PLAYER_HURT_ON_FIRE;
|
||||
}
|
||||
};
|
||||
private final String identifier;
|
||||
private final TagHandler tagHandler = TagHandler.newHandler();
|
||||
import java.util.Collection;
|
||||
|
||||
public sealed interface DamageType extends ProtocolObject, DamageTypes permits DamageTypeImpl {
|
||||
/**
|
||||
* Creates a new damage type.
|
||||
* Returns the damage type registry.
|
||||
*
|
||||
* @param identifier the identifier of this damage type,
|
||||
* does not need to be unique
|
||||
* @return the damage type registry
|
||||
*/
|
||||
public DamageType(@NotNull String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of this damage type.
|
||||
* <p>
|
||||
* It does not have to be unique to this object.o
|
||||
*
|
||||
* @return the damage type identifier
|
||||
*/
|
||||
public @NotNull String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the death message linked to this damage type.
|
||||
* <p>
|
||||
* Used in {@link Player#kill()} to broadcast the proper message.
|
||||
*
|
||||
* @param killed the player who has been killed
|
||||
* @return the death message, null to do not send anything
|
||||
*/
|
||||
public @Nullable Component buildDeathMessage(@NotNull Player killed) {
|
||||
return Component.translatable("death." + identifier, Component.text(killed.getUsername()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityProjectileDamage}.
|
||||
*
|
||||
* @param shooter the shooter
|
||||
* @param projectile the actual projectile
|
||||
* @return a new {@link EntityProjectileDamage}
|
||||
*/
|
||||
public static @NotNull DamageType fromProjectile(@Nullable Entity shooter, @NotNull Entity projectile) {
|
||||
return new EntityProjectileDamage(shooter, projectile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityDamage}.
|
||||
*
|
||||
* @param player the player damager
|
||||
* @return a new {@link EntityDamage}
|
||||
*/
|
||||
public static @NotNull EntityDamage fromPlayer(@NotNull Player player) {
|
||||
return new EntityDamage(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create an {@link EntityDamage}.
|
||||
*
|
||||
* @param entity the entity damager
|
||||
* @return a new {@link EntityDamage}
|
||||
*/
|
||||
public static @NotNull EntityDamage fromEntity(@NotNull Entity entity) {
|
||||
return new EntityDamage(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the text sent to a player in his death screen.
|
||||
*
|
||||
* @param killed the player who has been killed
|
||||
* @return the death screen text, null to do not send anything
|
||||
*/
|
||||
public @Nullable Component buildDeathScreenText(@NotNull Player killed) {
|
||||
return Component.translatable("death." + identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sound event to play when the given entity is hit by this damage. Possible to return null if no sound should be played
|
||||
*
|
||||
* @param entity the entity hit by this damage
|
||||
* @return the sound to play when the given entity is hurt by this damage type. Can be null if no sound should play
|
||||
*/
|
||||
public @Nullable SoundEvent getSound(@NotNull LivingEntity entity) {
|
||||
if (entity instanceof Player) {
|
||||
return getPlayerSound((Player) entity);
|
||||
}
|
||||
return getGenericSound(entity);
|
||||
}
|
||||
|
||||
protected SoundEvent getGenericSound(@NotNull LivingEntity entity) {
|
||||
return SoundEvent.ENTITY_GENERIC_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getPlayerSound(@NotNull Player player) {
|
||||
return SoundEvent.ENTITY_PLAYER_HURT;
|
||||
}
|
||||
@Contract(pure = true)
|
||||
@NotNull Registry.DamageTypeEntry registry();
|
||||
|
||||
@Override
|
||||
public @NotNull TagHandler tagHandler() {
|
||||
return tagHandler;
|
||||
default @NotNull NamespaceID namespace() {
|
||||
return registry().namespace();
|
||||
}
|
||||
}
|
||||
|
||||
default double exhaustion() {
|
||||
return registry().exhaustion();
|
||||
}
|
||||
|
||||
default String messageId() {
|
||||
return registry().messageId();
|
||||
}
|
||||
|
||||
default String scaling() {
|
||||
return registry().scaling();
|
||||
}
|
||||
|
||||
NBTCompound asNBT();
|
||||
|
||||
static @NotNull Collection<@NotNull DamageType> values() {
|
||||
return DamageTypeImpl.values();
|
||||
}
|
||||
|
||||
static DamageType fromNamespaceId(@NotNull String namespaceID) {
|
||||
return DamageTypeImpl.getSafe(namespaceID);
|
||||
}
|
||||
|
||||
static DamageType fromNamespaceId(@NotNull NamespaceID namespaceID) {
|
||||
return fromNamespaceId(namespaceID.asString());
|
||||
}
|
||||
|
||||
static @Nullable DamageType fromId(int id) {
|
||||
return DamageTypeImpl.getId(id);
|
||||
}
|
||||
|
||||
static NBTCompound getNBT() {
|
||||
return DamageTypeImpl.getNBT();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.minestom.server.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements DamageType {
|
||||
private static final Registry.Container<DamageType> CONTAINER;
|
||||
|
||||
static {
|
||||
AtomicInteger i = new AtomicInteger();
|
||||
CONTAINER = Registry.createContainer(Registry.Resource.DAMAGE_TYPES,
|
||||
(namespace, properties) -> new DamageTypeImpl(Registry.damageType(namespace, properties), i.getAndIncrement()));
|
||||
}
|
||||
|
||||
static DamageType get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
}
|
||||
|
||||
static DamageType getSafe(@NotNull String namespace) {
|
||||
return CONTAINER.getSafe(namespace);
|
||||
}
|
||||
|
||||
static DamageType getId(int id) {
|
||||
return CONTAINER.getId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTCompound asNBT() {
|
||||
var elem = new HashMap<String, NBT>();
|
||||
elem.put("exhaustion", NBT.Float(registry.exhaustion()));
|
||||
elem.put("message_id", NBT.String(registry.messageId()));
|
||||
elem.put("scaling", NBT.String(registry.scaling()));
|
||||
return NBT.Compound(elem);
|
||||
}
|
||||
|
||||
static Collection<DamageType> values() {
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static NBTCompound lazyNbt = null;
|
||||
|
||||
static NBTCompound getNBT() {
|
||||
if (lazyNbt == null) {
|
||||
var damageTypes = values().stream()
|
||||
.map((damageType) -> NBT.Compound(Map.of(
|
||||
"id", NBT.Int(damageType.id()),
|
||||
"name", NBT.String(damageType.name()),
|
||||
"element", damageType.asNBT()
|
||||
)))
|
||||
.toList();
|
||||
|
||||
lazyNbt = NBT.Compound(Map.of(
|
||||
"type", NBT.String("minecraft:damage_type"),
|
||||
"value", NBT.List(NBTType.TAG_Compound, damageTypes)
|
||||
));
|
||||
}
|
||||
return lazyNbt;
|
||||
}
|
||||
}
|
@ -6,13 +6,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* Represents damage inflicted by an {@link Entity}.
|
||||
*/
|
||||
public class EntityDamage extends DamageType {
|
||||
public class EntityDamage extends Damage {
|
||||
|
||||
private final Entity source;
|
||||
|
||||
public EntityDamage(@NotNull Entity source) {
|
||||
super("entity_source");
|
||||
this.source = source;
|
||||
public EntityDamage(@NotNull Entity source, float amount) {
|
||||
super(DamageType.MOB_ATTACK, source, source, null, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,8 +17,13 @@ public class EntityDamage extends DamageType {
|
||||
*
|
||||
* @return the source
|
||||
*/
|
||||
@NotNull
|
||||
public Entity getSource() {
|
||||
return source;
|
||||
@Override
|
||||
public @NotNull Entity getSource() {
|
||||
return super.getSource();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Entity getAttacker() {
|
||||
return getSource();
|
||||
}
|
||||
}
|
@ -7,15 +7,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* Represents damage inflicted by an entity, via a projectile.
|
||||
*/
|
||||
public class EntityProjectileDamage extends DamageType {
|
||||
public class EntityProjectileDamage extends Damage {
|
||||
|
||||
private final Entity shooter;
|
||||
private final Entity projectile;
|
||||
|
||||
public EntityProjectileDamage(@Nullable Entity shooter, @NotNull Entity projectile) {
|
||||
super("projectile_source");
|
||||
this.shooter = shooter;
|
||||
this.projectile = projectile;
|
||||
public EntityProjectileDamage(@Nullable Entity shooter, @NotNull Entity projectile, float amount) {
|
||||
super(DamageType.MOB_PROJECTILE, projectile, shooter, null, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,7 +20,7 @@ public class EntityProjectileDamage extends DamageType {
|
||||
*/
|
||||
@NotNull
|
||||
public Entity getProjectile() {
|
||||
return projectile;
|
||||
return getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,6 +30,11 @@ public class EntityProjectileDamage extends DamageType {
|
||||
*/
|
||||
@Nullable
|
||||
public Entity getShooter() {
|
||||
return shooter;
|
||||
return getAttacker();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Entity getSource() {
|
||||
return super.getSource();
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents damage that is associated with a certain position.
|
||||
*/
|
||||
public class PositionalDamage extends Damage {
|
||||
|
||||
public PositionalDamage(@NotNull DamageType type, @NotNull Point sourcePosition, float amount) {
|
||||
super(type, null, null, sourcePosition, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Point getSourcePosition() {
|
||||
return super.getSourcePosition();
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package net.minestom.server.event.entity;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.LivingEntity;
|
||||
import net.minestom.server.entity.damage.Damage;
|
||||
import net.minestom.server.entity.damage.DamageType;
|
||||
import net.minestom.server.event.trait.CancellableEvent;
|
||||
import net.minestom.server.event.trait.EntityInstanceEvent;
|
||||
@ -15,17 +16,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class EntityDamageEvent implements EntityInstanceEvent, CancellableEvent {
|
||||
|
||||
private final Entity entity;
|
||||
private final DamageType damageType;
|
||||
private float damage;
|
||||
private final Damage damage;
|
||||
private SoundEvent sound;
|
||||
private boolean animation = true;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
public EntityDamageEvent(@NotNull LivingEntity entity, @NotNull DamageType damageType,
|
||||
float damage, @Nullable SoundEvent sound) {
|
||||
public EntityDamageEvent(@NotNull LivingEntity entity, @NotNull Damage damage, @Nullable SoundEvent sound) {
|
||||
this.entity = entity;
|
||||
this.damageType = damageType;
|
||||
this.damage = damage;
|
||||
this.sound = sound;
|
||||
}
|
||||
@ -42,28 +40,10 @@ public class EntityDamageEvent implements EntityInstanceEvent, CancellableEvent
|
||||
* @return the damage type
|
||||
*/
|
||||
@NotNull
|
||||
public DamageType getDamageType() {
|
||||
return damageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the damage amount.
|
||||
*
|
||||
* @return the damage amount
|
||||
*/
|
||||
public float getDamage() {
|
||||
public Damage getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the damage amount.
|
||||
*
|
||||
* @param damage the new damage amount
|
||||
*/
|
||||
public void setDamage(float damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the damage sound.
|
||||
*
|
||||
|
@ -53,6 +53,11 @@ public final class Registry {
|
||||
return new PotionEffectEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static DamageTypeEntry damageType(String namespace, @NotNull Properties main) {
|
||||
return new DamageTypeEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static Map<String, Map<String, Object>> load(Resource resource) {
|
||||
Map<String, Map<String, Object>> map = new HashMap<>();
|
||||
@ -409,6 +414,23 @@ public final class Registry {
|
||||
}
|
||||
}
|
||||
|
||||
public record DamageTypeEntry(NamespaceID namespace, float exhaustion,
|
||||
String messageId,
|
||||
String scaling,
|
||||
@Nullable String effects,
|
||||
@Nullable String deathMessageType,
|
||||
Properties custom) implements Entry {
|
||||
public DamageTypeEntry(String namespace, Properties main, Properties custom) {
|
||||
this(NamespaceID.from(namespace),
|
||||
(float) main.getDouble("exhaustion"),
|
||||
main.getString("message_id"),
|
||||
main.getString("scaling"),
|
||||
main.getString("effects"),
|
||||
main.getString("death_message_type"),
|
||||
custom);
|
||||
}
|
||||
}
|
||||
|
||||
public record EnchantmentEntry(NamespaceID namespace, int id,
|
||||
String translationKey,
|
||||
double maxLevel,
|
||||
|
Loading…
Reference in New Issue
Block a user