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.
* <p>
* 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 <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
*/

View File

@ -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}
*/

View File

@ -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())

View File

@ -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}.
* <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 {
@ -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.
* <p>
* 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.
* <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) {
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 + "}");
}

View File

@ -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 {

View File

@ -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}.
* <p>
* Called using {@link EventHandler#callEvent(Class, Event)}.
*/
public class Event {
}