From 3da731dad3b21d6439a03df5defcc297de20794f Mon Sep 17 00:00:00 2001 From: PetteriM1 <26197131+PetteriM1@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:41:03 +0300 Subject: [PATCH] Update FloatingTextParticle (#2191) - Fixed name tag always visible - Fixed set invisible not sending update - Using armor stand instead of player entity for better performance --- .../level/particle/FloatingTextParticle.java | 141 +++++++++--------- 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java b/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java index b9b6d849f57..a940e2a783a 100644 --- a/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java +++ b/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java @@ -2,36 +2,25 @@ import cn.nukkit.entity.Entity; import cn.nukkit.entity.data.EntityMetadata; -import cn.nukkit.entity.data.Skin; -import cn.nukkit.item.Item; import cn.nukkit.level.Level; import cn.nukkit.level.Location; import cn.nukkit.math.Vector3; import cn.nukkit.network.protocol.*; -import cn.nukkit.utils.SerializedImage; import com.google.common.base.Strings; import java.util.ArrayList; -import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; /** * Created on 2015/11/21 by xtypr. * Package cn.nukkit.level.particle in project Nukkit . */ public class FloatingTextParticle extends Particle { - private static final Skin EMPTY_SKIN = new Skin(); - private static final SerializedImage SKIN_DATA = SerializedImage.fromLegacy(new byte[8192]); - static { - EMPTY_SKIN.setSkinData(SKIN_DATA); - EMPTY_SKIN.generateSkinId("FloatingText"); - } - - protected UUID uuid = UUID.randomUUID(); protected final Level level; protected long entityId = -1; protected boolean invisible = false; + protected String title; + protected String text; protected EntityMetadata metadata = new EntityMetadata(); public FloatingTextParticle(Location location, String title) { @@ -53,64 +42,92 @@ public FloatingTextParticle(Vector3 pos, String title, String text) { private FloatingTextParticle(Level level, Vector3 pos, String title, String text) { super(pos.x, pos.y, pos.z); this.level = level; + this.title = title; + this.text = text; + + long flags = 0; + flags ^= 1 << Entity.DATA_FLAG_NO_AI; + flags ^= 1 << Entity.DATA_FLAG_CAN_SHOW_NAMETAG; - long flags = ( - 1L << Entity.DATA_FLAG_NO_AI - ); - metadata.putLong(Entity.DATA_FLAGS, flags) - .putLong(Entity.DATA_LEAD_HOLDER_EID,-1) - .putFloat(Entity.DATA_SCALE, 0.01f) //zero causes problems on debug builds? + this.metadata.putLong(Entity.DATA_FLAGS, flags) + .putLong(Entity.DATA_LEAD_HOLDER_EID, -1) + .putByte(Entity.DATA_ALWAYS_SHOW_NAMETAG, 1) + .putFloat(Entity.DATA_SCALE, 0.01f) // Zero causes problems on debug builds? .putFloat(Entity.DATA_BOUNDING_BOX_HEIGHT, 0.01f) .putFloat(Entity.DATA_BOUNDING_BOX_WIDTH, 0.01f); - if (!Strings.isNullOrEmpty(title)) { - metadata.putString(Entity.DATA_NAMETAG, title); - } - if (!Strings.isNullOrEmpty(text)) { - metadata.putString(Entity.DATA_SCORE_TAG, text); - } + + updateNameTag(); } public String getText() { - return metadata.getString(Entity.DATA_SCORE_TAG); + return this.text == null ? "" : this.text; } public void setText(String text) { - this.metadata.putString(Entity.DATA_SCORE_TAG, text); + this.text = text; + updateNameTag(); sendMetadata(); } public String getTitle() { - return metadata.getString(Entity.DATA_NAMETAG); + return this.title == null ? "" : this.title; } public void setTitle(String title) { - this.metadata.putString(Entity.DATA_NAMETAG, title); + this.title = title; + updateNameTag(); sendMetadata(); } + private void updateNameTag() { + // Score tag only works on player + boolean hasTitle = !Strings.isNullOrEmpty(this.title); + boolean hasText = !Strings.isNullOrEmpty(this.text); + String tag = ""; + if (hasTitle) { + tag += this.title; + if (hasText) { + tag += "\n"; + } + } + if (hasText) { + tag += this.text; + } + this.metadata.putString(Entity.DATA_NAMETAG, tag); + } + private void sendMetadata() { - if (level != null) { + if (this.level != null) { SetEntityDataPacket packet = new SetEntityDataPacket(); packet.eid = entityId; - packet.metadata = metadata; - level.addChunkPacket(getChunkX(), getChunkZ(), packet); + packet.metadata = this.metadata; + + this.level.addChunkPacket(getChunkX(), getChunkZ(), packet); } } public boolean isInvisible() { - return invisible; + return this.invisible; } public void setInvisible(boolean invisible) { this.invisible = invisible; + + if (this.level != null) { + if (invisible) { + this.level.addChunkPacket(getChunkX(), getChunkZ(), getRemovePacket()); + } else { + this.level.addChunkPacket(getChunkX(), getChunkZ(), getAddPacket()); + } + } } public void setInvisible() { this.setInvisible(true); } - + public long getEntityId() { - return entityId; + return this.entityId; } @Override @@ -118,45 +135,33 @@ public DataPacket[] encode() { ArrayList packets = new ArrayList<>(); if (this.entityId == -1) { - this.entityId = 1095216660480L + ThreadLocalRandom.current().nextLong(0, 0x7fffffffL); + this.entityId = Entity.entityCount++; } else { - RemoveEntityPacket pk = new RemoveEntityPacket(); - pk.eid = this.entityId; - - packets.add(pk); + packets.add(getRemovePacket()); } if (!this.invisible) { - PlayerListPacket.Entry[] entry = {new PlayerListPacket.Entry(uuid, entityId, - metadata.getString(Entity.DATA_NAMETAG), EMPTY_SKIN)}; - PlayerListPacket playerAdd = new PlayerListPacket(); - playerAdd.entries = entry; - playerAdd.type = PlayerListPacket.TYPE_ADD; - packets.add(playerAdd); - - AddPlayerPacket pk = new AddPlayerPacket(); - pk.uuid = uuid; - pk.username = ""; - pk.entityUniqueId = this.entityId; - pk.entityRuntimeId = this.entityId; - pk.x = (float) this.x; - pk.y = (float) (this.y - 0.75); - pk.z = (float) this.z; - pk.speedX = 0; - pk.speedY = 0; - pk.speedZ = 0; - pk.yaw = 0; - pk.pitch = 0; - pk.metadata = this.metadata; - pk.item = Item.get(Item.AIR); - packets.add(pk); - - PlayerListPacket playerRemove = new PlayerListPacket(); - playerRemove.entries = entry; - playerRemove.type = PlayerListPacket.TYPE_REMOVE; - packets.add(playerRemove); + packets.add(getAddPacket()); } return packets.toArray(new DataPacket[0]); } + + private AddEntityPacket getAddPacket() { + AddEntityPacket pk = new AddEntityPacket(); + pk.id = "minecraft:armor_stand"; + pk.entityUniqueId = this.entityId; + pk.entityRuntimeId = this.entityId; + pk.x = (float) this.x; + pk.y = (float) this.y - 0.75f; + pk.z = (float) this.z; + pk.metadata = this.metadata; + return pk; + } + + private RemoveEntityPacket getRemovePacket() { + RemoveEntityPacket pk = new RemoveEntityPacket(); + pk.eid = this.entityId; + return pk; + } }