Credits to Owen1212055 for their NMS guide, please read it as this is just a simple port!
public class NametagEntity extends Entity {
public static final Tag<NametagEntity> NAMETAG_TAG = Tag.Transient("nametag"); // for deleting the entity on leave
public NametagEntity(Player player) {
super(EntityType.INTERACTION);
InteractionMeta meta = (InteractionMeta) this.getEntityMeta();
meta.setCustomNameVisible(true);
if (player.getDisplayName() != null) {
meta.setCustomName(player.getDisplayName());
} else {
meta.setCustomName(Component.text("you should probably set this to something..."));
}
// this isn't perfect, hopefully one day when we can get the offsets it'll be.
meta.setHeight(0.1F);
meta.setWidth(0.1F);
// set the pose to update the height.
meta.setPose(Pose.SNIFFING);
player.setTag(NAMETAG_TAG, this);
player.addPassenger(this);
}
@Override
public void updateNewViewer(Player player) {
super.updateNewViewer(player);
// a tick after the initial meta is sent, send a new meta packet with a large height to stop it from disappearing, you can read why in Owen1212055's gist.
this.scheduler().scheduleNextTick(() -> {
if (player.isDead()) return;
player.sendPacket(new EntityMetaDataPacket(this.getEntityId(), Map.of(9, Metadata.Float(99999999))));
});
}
}
I've removed some of the basic stuff just so you can see the important parts
GlobalEventHandler globalHandler = MinecraftServer.getGlobalEventHandler();
globalHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> {
final Player player = event.getPlayer();
[...]
player.setDisplayName(
Component.text("Minestom", TextColor.color(0xff6c33))
.appendSpace()
.append(
Component.text(event.getPlayer().getUsername(), TextColor.color(0xff76ad))
)
);
});
globalHandler.addListener(PlayerSpawnEvent.class, event -> {
final Player player = event.getPlayer();
new NametagEntity(player);
});
globalHandler.addListener(PlayerDisconnectEvent.class, event -> {
final Player player = event.getPlayer();
if (player.hasTag(NametagEntity.NAMETAG_TAG)) {
NametagEntity nametag = player.getTag(NametagEntity.NAMETAG_TAG);
nametag.remove();
}
});