Improvement for the DamageType code

This commit is contained in:
themode 2020-10-22 12:21:50 +02:00
parent c7f8ae7536
commit 47677766ca
6 changed files with 114 additions and 46 deletions

View File

@ -567,6 +567,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
/** /**
* Each entity has an unique id which will change after a restart. * Each entity has an unique id which will change after a restart.
* <p>
* All entities can be retrieved by calling {@link Entity#getEntity(int)}. * All entities can be retrieved by calling {@link Entity#getEntity(int)}.
* *
* @return the unique entity id * @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() { public EntityType getEntityType() {
return entityType; return entityType;
} }
/** /**
* Gets the entity UUID. * Gets the entity {@link UUID}.
* *
* @return the entity UUID * @return the entity unique id
*/ */
public UUID getUuid() { public UUID getUuid() {
return uuid; 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 * @return the entity chunk
*/ */
@ -810,7 +811,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Entity statuses can be find <a href="https://wiki.vg/Entity_statuses">here</a>. * Entity statuses can be found <a href="https://wiki.vg/Entity_statuses">here</a>.
* *
* @param status the status to trigger * @param status the status to trigger
*/ */

View File

@ -20,6 +20,7 @@ import net.minestom.server.sound.SoundCategory;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.validate.Check;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -228,6 +229,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
* *
* @param duration duration of the effect * @param duration duration of the effect
* @param unit unit used to express the duration * @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) { public void setFireForDuration(int duration, TimeUnit unit) {
EntityFireEvent entityFireEvent = new EntityFireEvent(this, duration, 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) // Do not start fire event if the fire needs to be removed (< 0 duration)
if (duration > 0) { if (duration > 0) {
callCancellableEvent(EntityFireEvent.class, entityFireEvent, () -> { callCancellableEvent(EntityFireEvent.class, entityFireEvent, () -> {
long fireTime = entityFireEvent.getFireTime(TimeUnit.MILLISECOND); final long fireTime = entityFireEvent.getFireTime(TimeUnit.MILLISECOND);
setOnFire(true); setOnFire(true);
fireExtinguishTime = System.currentTimeMillis() + fireTime; 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 type the damage type
* @param value the amount of damage * @param value the amount of damage
* @return true if damage has been applied, false if it didn't * @return true if damage has been applied, false if it didn't
*/ */
public boolean damage(DamageType type, float value) { public boolean damage(DamageType type, float value) {
Check.notNull(type, "The damage type cannot be null!o");
if (isDead()) if (isDead())
return false; return false;
if (isInvulnerable() || isImmune(type)) { if (isInvulnerable() || isImmune(type)) {
@ -260,7 +263,10 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value); EntityDamageEvent entityDamageEvent = new EntityDamageEvent(this, type, value);
callCancellableEvent(EntityDamageEvent.class, entityDamageEvent, () -> { 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 entityAnimationPacket = new EntityAnimationPacket();
entityAnimationPacket.entityId = getEntityId(); entityAnimationPacket.entityId = getEntityId();
@ -272,18 +278,18 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
final Player player = (Player) this; final Player player = (Player) this;
final float additionalHearts = player.getAdditionalHearts(); final float additionalHearts = player.getAdditionalHearts();
if (additionalHearts > 0) { if (additionalHearts > 0) {
if (damage > additionalHearts) { if (remainingDamage > additionalHearts) {
damage -= additionalHearts; remainingDamage -= additionalHearts;
player.setAdditionalHearts(0); player.setAdditionalHearts(0);
} else { } else {
player.setAdditionalHearts(additionalHearts - damage); player.setAdditionalHearts(additionalHearts - remainingDamage);
damage = 0; remainingDamage = 0;
} }
} }
} }
// Set the final entity health // Set the final entity health
setHealth(getHealth() - damage); setHealth(getHealth() - remainingDamage);
// play damage sound // play damage sound
final Sound sound = type.getSound(this); 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); SoundEffectPacket damageSoundPacket = SoundEffectPacket.create(soundCategory, sound, getPosition().getX(), getPosition().getY(), getPosition().getZ(), 1.0f, 1.0f);
sendPacketToViewersAndSelf(damageSoundPacket); sendPacketToViewersAndSelf(damageSoundPacket);
} }
// Set the last damage type since the event is not cancelled
this.lastDamageSource = entityDamageEvent.getDamageType();
}); });
return !entityDamageEvent.isCancelled(); 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. * Gets the time in ms between two fire damage applications.
* *
* @return the time in ms * @return the time in ms
* @see #setFireDamagePeriod(long, TimeUnit)
*/ */
public long getFireDamagePeriod() { public long getFireDamagePeriod() {
return fireDamagePeriod; 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} * @return the {@link Team}
*/ */

View File

@ -454,34 +454,43 @@ public class Player extends LivingEntity implements CommandSender {
@Override @Override
public void kill() { public void kill() {
if (!isDead()) { if (!isDead()) {
// send death message to player // send death screen text to the killed player
ColoredText deathMessage; {
if (lastDamageSource != null) { ColoredText deathText;
deathMessage = lastDamageSource.buildDeathScreenMessage(this); if (lastDamageSource != null) {
} else { // may happen if killed by the server without applying damage deathText = lastDamageSource.buildDeathScreenText(this);
deathMessage = ColoredText.of("Killed by poor programming."); } 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 // send death message to chat
RichMessage chatMessage; {
if (lastDamageSource != null) { JsonMessage chatMessage;
chatMessage = lastDamageSource.buildChatMessage(this); if (lastDamageSource != null) {
} else { // may happen if killed by the server without applying damage chatMessage = lastDamageSource.buildDeathMessage(this);
ColoredText coloredChatMessage = } else { // may happen if killed by the server without applying damage
ColoredText.of(getUsername() + " was killed by poor programming."); chatMessage = ColoredText.of(getUsername() + " was killed by poor programming.");
chatMessage = RichMessage.of(coloredChatMessage); }
// #buildDeathMessage can return null, check here
if (chatMessage != null) {
MinecraftServer.getConnectionManager().broadcastMessage(chatMessage);
}
} }
MinecraftServer.getConnectionManager().getOnlinePlayers()
.forEach(player -> player.sendMessage(chatMessage));
} }
super.kill(); super.kill();
} }
/** /**
* Respawn the player by sending a {@link RespawnPacket} to the player and teleporting him * Respawns the player by sending a {@link RespawnPacket} to the player and teleporting him
* to {@link #getRespawnPoint()}. It also reset fire and his health * to {@link #getRespawnPoint()}. It also resetso fire and his health
*/ */
public void respawn() { public void respawn() {
if (!isDead()) if (!isDead())

View File

@ -1,6 +1,7 @@
package net.minestom.server.entity.damage; package net.minestom.server.entity.damage;
import net.minestom.server.chat.ColoredText; import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.chat.RichMessage; import net.minestom.server.chat.RichMessage;
import net.minestom.server.data.Data; import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer; import net.minestom.server.data.DataContainer;
@ -10,7 +11,12 @@ import net.minestom.server.entity.Player;
import net.minestom.server.sound.Sound; 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}.
* <p>
* 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 { public class DamageType implements DataContainer {
@ -25,32 +31,78 @@ public class DamageType implements DataContainer {
private final String identifier; private final String identifier;
private Data data; 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) { public DamageType(String identifier) {
this.identifier = 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 String getIdentifier() { public String getIdentifier() {
return identifier; 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.
* 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) { public static DamageType fromProjectile(Entity shooter, Entity projectile) {
return new EntityProjectileDamage(shooter, projectile); return new EntityProjectileDamage(shooter, projectile);
} }
public RichMessage buildChatMessage(Player killed) { /**
RichMessage richMessage = RichMessage.of(ColoredText.of("{@death." + identifier + "," + killed.getUsername() + "}")); * Convenient method to create an {@link EntityDamage}.
return richMessage; *
} * @param player the player damager
* @return a new {@link EntityDamage}
*/
public static EntityDamage fromPlayer(Player player) { public static EntityDamage fromPlayer(Player player) {
return new EntityDamage(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) { public static EntityDamage fromEntity(Entity entity) {
return new EntityDamage(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 + "}"); return ColoredText.of("{@death." + identifier + "}");
} }

View File

@ -3,7 +3,7 @@ package net.minestom.server.entity.damage;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
/** /**
* Represents damage inflicted by an entity. * Represents damage inflicted by an {@link Entity}.
*/ */
public class EntityDamage extends DamageType { public class EntityDamage extends DamageType {

View File

@ -3,7 +3,9 @@ package net.minestom.server.event;
import net.minestom.server.event.handler.EventHandler; 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}.
* <p>
* Called using {@link EventHandler#callEvent(Class, Event)}.
*/ */
public class Event { public class Event {
} }