Chat messages when player dies and cleaner damage types

This commit is contained in:
jglrxavpok 2020-04-27 21:12:42 +02:00
parent 6b77627d60
commit 7e3bc22bc4
6 changed files with 194 additions and 6 deletions

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity;
import club.thectm.minecraft.text.TextBuilder;
import club.thectm.minecraft.text.TextObject;
import com.google.gson.JsonObject;
import net.minestom.server.MinecraftServer;
@ -76,6 +77,11 @@ public class Player extends LivingEntity {
private Team team;
private BelowNameScoreboard belowNameScoreboard;
/**
* Last damage source to hit this player, used to display the death message.
*/
private DamageType lastDamageSource;
// Abilities
private boolean invulnerable;
private boolean flying;
@ -109,6 +115,14 @@ public class Player extends LivingEntity {
setCanPickupItem(true); // By default
}
@Override
public void damage(DamageType type, float value) {
if(!isImmune(type)) {
lastDamageSource = type;
}
super.damage(type, value);
}
@Override
public void update() {
@ -229,6 +243,33 @@ public class Player extends LivingEntity {
}
@Override
public void kill() {
if(!isDead()) {
// send death message to player
TextObject deathMessage;
if(lastDamageSource != null) {
deathMessage = lastDamageSource.buildDeathMessage();
} else { // may happen if killed by the server without applying damage
deathMessage = TextBuilder.of("Killed by poor programming.").build();
}
CombatEventPacket deathPacket = CombatEventPacket.death(this, Optional.empty(), deathMessage);
playerConnection.sendPacket(deathPacket);
// send death message to chat
TextObject chatMessage;
if(lastDamageSource != null) {
chatMessage = lastDamageSource.buildChatMessage(this);
} else { // may happen if killed by the server without applying damage
chatMessage = TextBuilder.of(getUsername()+" was killed by poor programming.").build();
}
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player -> {
player.sendMessage(chatMessage);
});
}
super.kill();
}
@Override
public void spawn() {

View File

@ -1,5 +1,8 @@
package net.minestom.server.entity.damage;
import club.thectm.minecraft.text.TextBuilder;
import club.thectm.minecraft.text.TextObject;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
/**
@ -7,13 +10,31 @@ import net.minestom.server.entity.Player;
*/
public class DamageType {
// TODO
public static final DamageType VOID = new DamageType("void");
public static final DamageType GRAVITY = new DamageType("gravity");
private final String identifier;
public static final DamageType VOID = new DamageType();
public static final DamageType PLAYER = new DamageType();
public DamageType(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
public TextObject buildChatMessage(Player killed) {
return TextBuilder.of(killed.getUsername()+" was killed by damage of type "+identifier).build();
}
public TextObject buildDeathMessage() {
return TextBuilder.of("Killed by damage of type "+identifier).build();
}
public static DamageType fromPlayer(Player player) {
// TODO
return PLAYER;
return new EntityDamage(player);
}
public static DamageType fromProjectile(Entity shooter, Entity projectile) {
return new EntityProjectileDamage(shooter, projectile);
}
}

View File

@ -0,0 +1,20 @@
package net.minestom.server.entity.damage;
import net.minestom.server.entity.Entity;
/**
* Represents damage inflicted by an entity
*/
public class EntityDamage extends DamageType {
private final Entity source;
public EntityDamage(Entity source) {
super("entity_source");
this.source = source;
}
public Entity getSource() {
return source;
}
}

View File

@ -0,0 +1,26 @@
package net.minestom.server.entity.damage;
import net.minestom.server.entity.Entity;
/**
* Represents damage inflicted by an entity, via a projectile
*/
public class EntityProjectileDamage extends DamageType {
private Entity shooter;
private final Entity projectile;
public EntityProjectileDamage(Entity shooter, Entity projectile) {
super("projectile_source");
this.shooter = shooter;
this.projectile = projectile;
}
public Entity getProjectile() {
return projectile;
}
public Entity getShooter() {
return shooter;
}
}

View File

@ -53,7 +53,7 @@ public class ServerPacketIdentifier {
public static final int OPEN_SIGN_EDITOR = 0x30;
public static final int CRAFT_RECIPE_RESPONSE = 0x31;
public static final int PLAYER_ABILITIES = 0x32;
public static final int COMBAT_EVENT = 0x33; // Do not seem to be used by the client
public static final int COMBAT_EVENT = 0x33;
public static final int PLAYER_INFO = 0x34;
public static final int FACE_PLAYER = 0x35;
public static final int PLAYER_POSITION_AND_LOOK = 0x36;

View File

@ -0,0 +1,80 @@
package net.minestom.server.network.packet.server.play;
import club.thectm.minecraft.text.TextObject;
import net.minestom.server.chat.Chat;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import java.util.Optional;
/**
* Packet sent during combat to a player.
* Only death is supported for the moment (other events are ignored anyway as of 1.15.2)
*/
public class CombatEventPacket implements ServerPacket {
private EventType type;
private int duration;
private int opponent;
private int playerID;
private TextObject deathMessage;
private CombatEventPacket() {}
public static CombatEventPacket enter() {
CombatEventPacket packet = new CombatEventPacket();
packet.type = EventType.ENTER_COMBAT;
return packet;
}
public static CombatEventPacket end(int durationInTicks, Optional<Entity> opponent) {
CombatEventPacket packet = new CombatEventPacket();
packet.type = EventType.END_COMBAT;
packet.duration = durationInTicks;
packet.opponent = opponent.map(Entity::getEntityId).orElse(-1);
return packet;
}
public static CombatEventPacket death(Player player, Optional<Entity> killer, TextObject message) {
CombatEventPacket packet = new CombatEventPacket();
packet.type = EventType.DEATH;
packet.playerID = player.getEntityId();
packet.opponent = killer.map(Entity::getEntityId).orElse(-1);
packet.deathMessage = message;
return packet;
}
@Override
public void write(PacketWriter writer) {
writer.writeVarInt(type.ordinal());
switch (type) {
case ENTER_COMBAT:
// nothing to add
break;
case END_COMBAT:
writer.writeVarInt(duration);
writer.writeInt(opponent);
break;
case DEATH:
writer.writeVarInt(playerID);
writer.writeInt(opponent);
writer.writeSizedString(deathMessage.toJson().toString());
break;
}
}
@Override
public int getId() {
return ServerPacketIdentifier.COMBAT_EVENT;
}
public enum EventType {
ENTER_COMBAT, END_COMBAT, // both ignored by Notchian client
DEATH,
}
}