diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
index dbee49c..72b0b1a 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/LegacyHologram.java
@@ -162,6 +162,7 @@ public void teleport(Location location) {
Location l = new Location(location.getX(), y, location.getZ(), location.getYaw(), location.getPitch());
line.teleport(l, false);
}
+
}
@Override
diff --git a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
index a0a34d2..3cb27d7 100644
--- a/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
+++ b/api/src/main/java/me/tofaa/entitylib/wrapper/hologram/ModernHologram.java
@@ -50,20 +50,21 @@ public void hide() {
spawned = false;
}
+ private static final float LINE_SPACING = 0.28f;
+
@Override
public void teleport(Location location) {
this.location = location;
if (lines.isEmpty()) return;
-
+
if (parent != null) {
return;
}
-
- WrapperEntity first = lines.get(0);
- first.teleport(location);
- for (WrapperEntity e : lines) {
- if (e.getUuid().equals(first.getUuid())) continue;
- first.addPassenger(e);
+
+ for (int i = 0; i < lines.size(); i++) {
+ double y = location.getY() + (lines.size() - 1 - i) * LINE_SPACING;
+ Location lineLoc = new Location(location.getX(), y, location.getZ(), location.getYaw(), location.getPitch());
+ lines.get(i).teleport(lineLoc);
}
}
diff --git a/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPC.java b/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPC.java
index ee59e47..055c4b6 100644
--- a/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPC.java
+++ b/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPC.java
@@ -29,6 +29,7 @@
import me.tofaa.entitylib.wrapper.WrapperPlayer;
import me.tofaa.entitylib.wrapper.hologram.Hologram;
import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
@@ -319,9 +320,32 @@ public void remove() {
NPCRegistry.unregister(this);
}
+ /**
+ * Splits a Component into multiple lines on {@code
} tags.
+ * MiniMessage keeps {@code
} as a tag token through serialize/deserialize round-trips,
+ * so we serialize back to a MiniMessage string and split on the literal {@code
} token
+ * before re-deserializing each fragment into its own Component. This allows multi-line NPC
+ * name tags to be rendered as separate hologram line entities, since armor stands and text
+ * displays do not visually break a single component on newlines.
+ */
+ private List splitDisplayNameLines(Component component) {
+ MiniMessage mm = MiniMessage.miniMessage();
+ String serialized = mm.serialize(component);
+ // MiniMessage round-trips
as the literal tag string "
"
+ String[] parts = serialized.split("(?i)
", -1);
+ if (parts.length == 1) {
+ return Collections.singletonList(component);
+ }
+ List lines = new ArrayList<>(parts.length);
+ for (String part : parts) {
+ lines.add(mm.deserialize(part));
+ }
+ return lines;
+ }
+
private void createHologram() {
Location loc = getPosition();
- double yOffset = options.isSitting() ? 2.76 : 2.26;
+ double yOffset = options.isSitting() ? 1.1 : 1.0;
Location hologramLoc = new Location(
loc.getX(),
loc.getY() + yOffset,
@@ -330,24 +354,15 @@ private void createHologram() {
loc.getPitch()
);
- int protocolVersion = EntityLib.getApi()
- .getPacketEvents()
- .getServerManager()
- .getVersion()
- .getProtocolVersion();
+ Hologram.Legacy hologram = Hologram.legacy(hologramLoc);
+ hologram.setLineOffset(-0.28f);
- Hologram hologram;
- if (protocolVersion >= 760) {
- hologram = Hologram.modern(hologramLoc);
- } else {
- hologram = Hologram.legacy(hologramLoc);
+ Component displayName = options.getDisplayName() != null
+ ? options.getDisplayName()
+ : Component.text(name);
+ for (Component line : splitDisplayNameLines(displayName)) {
+ hologram.addLine(line);
}
-
- hologram.addLine(
- options.getDisplayName() != null
- ? options.getDisplayName()
- : Component.text(name)
- );
hologram.show();
// if (hologram.getEntity().getEntityMeta() instanceof AbstractDisplayMeta displayMeta) {
//// displayMeta.setTranslation(new Vector3f(0, 0.5f, 0));
@@ -358,12 +373,10 @@ private void createHologram() {
private void updateHologram() {
if (hologram != null) {
- hologram.setLine(
- 0,
- options.getDisplayName() != null
- ? options.getDisplayName()
- : Component.text(name)
- );
+ Component displayName = options.getDisplayName() != null
+ ? options.getDisplayName()
+ : Component.text(name);
+ hologram.setLines(splitDisplayNameLines(displayName));
}
}
diff --git a/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPCMovement.java b/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPCMovement.java
index 8a77c6e..f020d89 100644
--- a/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPCMovement.java
+++ b/spaceNPC/src/main/java/me/tofaa/entitylib/npc/NPCMovement.java
@@ -94,7 +94,10 @@ private static void processViewerSync() {
Location npcLocation = entity.getLocation();
npc.getHologram().ifPresent(hologram -> {
- hologram.setParent(npc.getEntity().get());
+ boolean isSittingNow = npc.getOptions().isSitting();
+ double yOff = isSittingNow ? 1.1 : 1.0;
+ Location npcLoc = npc.getEntity().get().getLocation();
+ hologram.teleport(new Location(npcLoc.getX(), npcLoc.getY() + yOff, npcLoc.getZ(), npcLoc.getYaw(), npcLoc.getPitch()));
});
boolean permanentlyVisible = npc.getOptions().isPermanentlyVisible();