4343@ Getter
4444public class TextDisplayEntity extends DisplayBaseEntity {
4545
46+ /**
47+ * The height offset per line of text in a text display entity when rendered
48+ * as an armor stand nametag on Bedrock Edition.
49+ * <p>
50+ * This value was empirically adjusted to match Java Edition's multi-line text
51+ * centering behavior. Note that this differs from the 0.1414f multiplier used
52+ * in {@link org.geysermc.geyser.util.EntityUtils} for mount offset calculations.
53+ */
54+ private static final float LINE_HEIGHT_OFFSET = 0.12f ;
55+
4656 private int lineCount ;
4757
4858 public TextDisplayEntity (GeyserSession session , int entityId , long geyserId , UUID uuid , EntityDefinition <?> definition , Vector3f position , Vector3f motion , float yaw , float pitch , float headYaw ) {
@@ -54,9 +64,27 @@ public void moveRelative(double relX, double relY, double relZ, float yaw, float
5464 super .moveRelative (relX , relY + definition .offset (), relZ , yaw , pitch , isOnGround );
5565 }
5666
67+ /**
68+ * Calculates the Y offset needed to match Java Edition's text centering
69+ * behavior for multi-line text displays.
70+ * <p>
71+ * In Java Edition, multi-line text displays are centered vertically.
72+ * This value differs from the 0.1414f multiplier used in {@link org.geysermc.geyser.util.EntityUtils}
73+ * for text displays mounted on players, as this handles the base positioning
74+ * rather than mount offset calculations.
75+ *
76+ * @return the Y offset to apply based on the number of lines
77+ */
78+ private float calculateLineOffset () {
79+ if (lineCount == 0 ) {
80+ return 0 ;
81+ }
82+ return LINE_HEIGHT_OFFSET * lineCount ;
83+ }
84+
5785 @ Override
5886 public void moveAbsolute (Vector3f position , float yaw , float pitch , float headYaw , boolean isOnGround , boolean teleported ) {
59- super .moveAbsolute (position .add (Vector3f . from ( 0 , definition . offset (), 0 ) ), yaw , pitch , headYaw , isOnGround , teleported );
87+ super .moveAbsolute (position .add (0 , calculateLineOffset (), 0 ), yaw , pitch , headYaw , isOnGround , teleported );
6088 }
6189
6290 @ Override
@@ -70,7 +98,14 @@ protected void initializeMetadata() {
7098
7199 public void setText (EntityMetadata <Component , ?> entityMetadata ) {
72100 this .dirtyMetadata .put (EntityDataTypes .NAME , MessageTranslator .convertMessage (entityMetadata .getValue (), session .locale ()));
101+
102+ int previousLineCount = lineCount ;
73103 calculateLineCount (entityMetadata .getValue ());
104+
105+ // If the line count changed, update the position to account for the new offset
106+ if (previousLineCount != lineCount ) {
107+ moveAbsolute (position , yaw , pitch , headYaw , onGround , false );
108+ }
74109 }
75110
76111 private void calculateLineCount (@ Nullable Component text ) {
0 commit comments