From 47677766ca6f32e5230da223611f8a7af4dd4450 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 22 Oct 2020 12:21:50 +0200 Subject: [PATCH] Improvement for the DamageType code --- .../net/minestom/server/entity/Entity.java | 13 ++-- .../minestom/server/entity/LivingEntity.java | 28 ++++---- .../net/minestom/server/entity/Player.java | 47 +++++++------ .../server/entity/damage/DamageType.java | 66 +++++++++++++++++-- .../server/entity/damage/EntityDamage.java | 2 +- .../java/net/minestom/server/event/Event.java | 4 +- 6 files changed, 114 insertions(+), 46 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 1e89ed313..40e8f9d9f 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -567,6 +567,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer { /** * Each entity has an unique id which will change after a restart. + *

* All entities can be retrieved by calling {@link Entity#getEntity(int)}. * * @return the unique entity id @@ -576,18 +577,18 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer { } /** - * Returns the entity type id, can convert using {@link EntityType#fromId(int)}. + * Returns the entity type. * - * @return the entity type id + * @return the entity type */ public EntityType getEntityType() { return entityType; } /** - * Gets the entity UUID. + * Gets the entity {@link UUID}. * - * @return the entity UUID + * @return the entity unique id */ public UUID getUuid() { return uuid; @@ -634,7 +635,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer { } /** - * Convenience method to get the entity current chunk + * Convenient method to get the entity current chunk. * * @return the entity chunk */ @@ -810,7 +811,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer { } /** - * Entity statuses can be find here. + * Entity statuses can be found here. * * @param status the status to trigger */ diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index a73e9b56d..aef6af25d 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -20,6 +20,7 @@ import net.minestom.server.sound.SoundCategory; import net.minestom.server.utils.Position; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.time.TimeUnit; +import net.minestom.server.utils.validate.Check; import java.util.Set; import java.util.function.Consumer; @@ -228,6 +229,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { * * @param duration duration of the effect * @param unit unit used to express the duration + * @see #setOnFire(boolean) if you want it to be permanent without any event callback */ public void setFireForDuration(int duration, TimeUnit unit) { EntityFireEvent entityFireEvent = new EntityFireEvent(this, duration, unit); @@ -235,7 +237,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { // Do not start fire event if the fire needs to be removed (< 0 duration) if (duration > 0) { callCancellableEvent(EntityFireEvent.class, entityFireEvent, () -> { - long fireTime = entityFireEvent.getFireTime(TimeUnit.MILLISECOND); + final long fireTime = entityFireEvent.getFireTime(TimeUnit.MILLISECOND); setOnFire(true); fireExtinguishTime = System.currentTimeMillis() + fireTime; }); @@ -245,13 +247,14 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { } /** - * Damage the entity by a value, the type of the damage also has to be specified + * 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 * @return true if damage has been applied, false if it didn't */ public boolean damage(DamageType type, float value) { + Check.notNull(type, "The damage type cannot be null!o"); if (isDead()) return false; if (isInvulnerable() || isImmune(type)) { @@ -260,7 +263,10 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value); callCancellableEvent(EntityDamageEvent.class, entityDamageEvent, () -> { - float damage = entityDamageEvent.getDamage(); + // Set the last damage type since the event is not cancelled + this.lastDamageSource = entityDamageEvent.getDamageType(); + + float remainingDamage = entityDamageEvent.getDamage(); EntityAnimationPacket entityAnimationPacket = new EntityAnimationPacket(); entityAnimationPacket.entityId = getEntityId(); @@ -272,18 +278,18 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { final Player player = (Player) this; final float additionalHearts = player.getAdditionalHearts(); if (additionalHearts > 0) { - if (damage > additionalHearts) { - damage -= additionalHearts; + if (remainingDamage > additionalHearts) { + remainingDamage -= additionalHearts; player.setAdditionalHearts(0); } else { - player.setAdditionalHearts(additionalHearts - damage); - damage = 0; + player.setAdditionalHearts(additionalHearts - remainingDamage); + remainingDamage = 0; } } } // Set the final entity health - setHealth(getHealth() - damage); + setHealth(getHealth() - remainingDamage); // play damage sound final Sound sound = type.getSound(this); @@ -299,9 +305,6 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { SoundEffectPacket damageSoundPacket = SoundEffectPacket.create(soundCategory, sound, getPosition().getX(), getPosition().getY(), getPosition().getZ(), 1.0f, 1.0f); sendPacketToViewersAndSelf(damageSoundPacket); } - - // Set the last damage type since the event is not cancelled - this.lastDamageSource = entityDamageEvent.getDamageType(); }); return !entityDamageEvent.isCancelled(); @@ -508,6 +511,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { * Gets the time in ms between two fire damage applications. * * @return the time in ms + * @see #setFireDamagePeriod(long, TimeUnit) */ public long getFireDamagePeriod() { return fireDamagePeriod; @@ -552,7 +556,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler { } /** - * Gets the {@link Team} of the entity.¬ + * Gets the {@link Team} of the entity. * * @return the {@link Team} */ diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8440c8078..35add4349 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -454,34 +454,43 @@ public class Player extends LivingEntity implements CommandSender { @Override public void kill() { if (!isDead()) { - // send death message to player - ColoredText deathMessage; - if (lastDamageSource != null) { - deathMessage = lastDamageSource.buildDeathScreenMessage(this); - } else { // may happen if killed by the server without applying damage - deathMessage = ColoredText.of("Killed by poor programming."); + // send death screen text to the killed player + { + ColoredText deathText; + if (lastDamageSource != null) { + deathText = lastDamageSource.buildDeathScreenText(this); + } else { // may happen if killed by the server without applying damage + deathText = ColoredText.of("Killed by poor programming."); + } + + // #buildDeathScreenText can return null, check here + if (deathText != null) { + CombatEventPacket deathPacket = CombatEventPacket.death(this, Optional.empty(), deathText); + playerConnection.sendPacket(deathPacket); + } } - CombatEventPacket deathPacket = CombatEventPacket.death(this, Optional.empty(), deathMessage); - playerConnection.sendPacket(deathPacket); // send death message to chat - RichMessage chatMessage; - if (lastDamageSource != null) { - chatMessage = lastDamageSource.buildChatMessage(this); - } else { // may happen if killed by the server without applying damage - ColoredText coloredChatMessage = - ColoredText.of(getUsername() + " was killed by poor programming."); - chatMessage = RichMessage.of(coloredChatMessage); + { + JsonMessage chatMessage; + if (lastDamageSource != null) { + chatMessage = lastDamageSource.buildDeathMessage(this); + } else { // may happen if killed by the server without applying damage + chatMessage = ColoredText.of(getUsername() + " was killed by poor programming."); + } + + // #buildDeathMessage can return null, check here + if (chatMessage != null) { + MinecraftServer.getConnectionManager().broadcastMessage(chatMessage); + } } - MinecraftServer.getConnectionManager().getOnlinePlayers() - .forEach(player -> player.sendMessage(chatMessage)); } super.kill(); } /** - * Respawn the player by sending a {@link RespawnPacket} to the player and teleporting him - * to {@link #getRespawnPoint()}. It also reset fire and his health + * Respawns the player by sending a {@link RespawnPacket} to the player and teleporting him + * to {@link #getRespawnPoint()}. It also resetso fire and his health */ public void respawn() { if (!isDead()) diff --git a/src/main/java/net/minestom/server/entity/damage/DamageType.java b/src/main/java/net/minestom/server/entity/damage/DamageType.java index f767473e6..f46ef2616 100644 --- a/src/main/java/net/minestom/server/entity/damage/DamageType.java +++ b/src/main/java/net/minestom/server/entity/damage/DamageType.java @@ -1,6 +1,7 @@ package net.minestom.server.entity.damage; import net.minestom.server.chat.ColoredText; +import net.minestom.server.chat.JsonMessage; import net.minestom.server.chat.RichMessage; import net.minestom.server.data.Data; import net.minestom.server.data.DataContainer; @@ -10,7 +11,12 @@ import net.minestom.server.entity.Player; import net.minestom.server.sound.Sound; /** - * Represents a type of damage + * Represents a type of damage, required when calling {@link LivingEntity#damage(DamageType, float)} + * and retrieved in {@link net.minestom.server.event.entity.EntityDamageEvent}. + *

+ * This class can be extended if you need to include custom fields and/or methods. + * Be aware that this class implements {@link DataContainer} + * so you can add your own data to an already existing damage type without any wrapper. */ public class DamageType implements DataContainer { @@ -25,32 +31,78 @@ public class DamageType implements DataContainer { private final String identifier; private Data data; + /** + * Creates a new damage type. + * + * @param identifier the identifier of this damage type, + * does not need to be unique + */ public DamageType(String identifier) { this.identifier = identifier; } + /** + * Gets the identifier of this damage type. + *

+ * It does not have to be unique to this object.o + * + * @return the damage type identifier + */ public String getIdentifier() { return identifier; } + /** + * Builds the death message linked to this damage type. + *

+ * 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. + * Can be for instance, of type {@link ColoredText} or {@link RichMessage}. + */ + public JsonMessage buildDeathMessage(Player killed) { + return ColoredText.of("{@death." + identifier + "," + 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 DamageType fromProjectile(Entity shooter, Entity projectile) { return new EntityProjectileDamage(shooter, projectile); } - public RichMessage buildChatMessage(Player killed) { - RichMessage richMessage = RichMessage.of(ColoredText.of("{@death." + identifier + "," + killed.getUsername() + "}")); - return richMessage; - } - + /** + * Convenient method to create an {@link EntityDamage}. + * + * @param player the player damager + * @return a new {@link EntityDamage} + */ public static EntityDamage fromPlayer(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 EntityDamage fromEntity(Entity entity) { return new EntityDamage(entity); } - public ColoredText buildDeathScreenMessage(Player killed) { + /** + * 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 ColoredText buildDeathScreenText(Player killed) { return ColoredText.of("{@death." + identifier + "}"); } diff --git a/src/main/java/net/minestom/server/entity/damage/EntityDamage.java b/src/main/java/net/minestom/server/entity/damage/EntityDamage.java index 00d208767..4e00d0521 100644 --- a/src/main/java/net/minestom/server/entity/damage/EntityDamage.java +++ b/src/main/java/net/minestom/server/entity/damage/EntityDamage.java @@ -3,7 +3,7 @@ package net.minestom.server.entity.damage; import net.minestom.server.entity.Entity; /** - * Represents damage inflicted by an entity. + * Represents damage inflicted by an {@link Entity}. */ public class EntityDamage extends DamageType { diff --git a/src/main/java/net/minestom/server/event/Event.java b/src/main/java/net/minestom/server/event/Event.java index 45ec83b1f..047a6980e 100644 --- a/src/main/java/net/minestom/server/event/Event.java +++ b/src/main/java/net/minestom/server/event/Event.java @@ -3,7 +3,9 @@ package net.minestom.server.event; import net.minestom.server.event.handler.EventHandler; /** - * Object which can be listened to by an {@link EventHandler} + * Object which can be listened to by an {@link EventHandler}. + *

+ * Called using {@link EventHandler#callEvent(Class, Event)}. */ public class Event { }