diff --git a/scripts/npc_text.js b/scripts/npc_text.js index c1758c0..e07fcea 100644 --- a/scripts/npc_text.js +++ b/scripts/npc_text.js @@ -32,6 +32,23 @@ const text = [ // Join all lines with newline for the display var fullDisplayText = text.join("\n"); +// Helper to convert legacy colors (& and §) to MiniMessage tags +function convertLegacyToMiniMessage(text) { + if (!text) return text; + var legacyMap = { + '0': 'black', '1': 'dark_blue', '2': 'dark_green', '3': 'dark_aqua', + '4': 'dark_red', '5': 'dark_purple', '6': 'gold', '7': 'gray', + '8': 'dark_gray', '9': 'blue', 'a': 'green', 'b': 'aqua', + 'c': 'red', 'd': 'light_purple', 'e': 'yellow', 'f': 'white', + 'l': 'bold', 'm': 'strikethrough', 'n': 'underlined', 'o': 'italic', + 'r': 'reset' + }; + return text.replace(/[&§]([0-9a-fk-orA-FK-OR])/g, function(match, code) { + var tag = legacyMap[code.toLowerCase()]; + return tag ? "<" + tag + ">" : match; + }); +} + // Run sequentially to prevent race conditions function spawnNext(index) { if (index >= pos.length) { @@ -63,24 +80,30 @@ function spawnNext(index) { // 1. Create the "NPC" (Host) var npc = new Entity(HUSK); npc.setNoGravity(true); + server.track(npc); // 2. Create the TextDisplay (Passenger) var textDisplay = new Entity(TEXT_DISPLAY); textDisplay.setNoGravity(true); // Ensure text doesn't fall + server.track(textDisplay); var meta = textDisplay.getEntityMeta(); - meta.setText(MiniMessage.miniMessage().deserialize(displayString)); + // Parse both MiniMessage and Legacy + var processedText = convertLegacyToMiniMessage(displayString); + meta.setText(MiniMessage.miniMessage().deserialize(processedText)); + meta.setBillboardRenderConstraints(BillboardConstraints.CENTER); meta.setScale(new Vec(1.0, 1.0, 1.0)); meta.setBackgroundColor(0); + meta.setShadow(true); // 3. Spawn entities server.log("Spawning NPC " + (index + 1) + "/" + pos.length + " at " + x + "," + y + "," + z + "..."); npc.setInstance(instance, position).thenAccept(function() { - textDisplay.setInstance(instance, position.add(0, 2.5, 0)).thenAccept(function() { + textDisplay.setInstance(instance, position.add(0, 3.0, 0)).thenAccept(function() { try { - npc.addPassenger(textDisplay); + // npc.addPassenger(textDisplay); server.log("Successfully spawned NPC + Text at " + x + "," + y + "," + z); } catch (e) { server.log("Error adding passenger: " + e); diff --git a/src/main/java/net/jstom/script/ScriptApi.java b/src/main/java/net/jstom/script/ScriptApi.java index 7067531..64d32ba 100644 --- a/src/main/java/net/jstom/script/ScriptApi.java +++ b/src/main/java/net/jstom/script/ScriptApi.java @@ -4,6 +4,7 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.event.Event; import net.minestom.server.event.EventNode; import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.Entity; import org.graalvm.polyglot.Value; import java.util.ArrayList; @@ -15,6 +16,7 @@ import java.lang.reflect.Modifier; public class ScriptApi { private final List> registeredNodes = new ArrayList<>(); + private final List trackedEntities = new ArrayList<>(); private static final Map entityTypes = new HashMap<>(); static { @@ -71,12 +73,28 @@ public class ScriptApi { } } + public void track(Entity entity) { + if (entity != null) { + synchronized (trackedEntities) { + trackedEntities.add(entity); + } + } + } + public void cleanup() { System.out.println("[JStom] Cleaning up " + registeredNodes.size() + " event nodes..."); for (var node : registeredNodes) { MinecraftServer.getGlobalEventHandler().removeChild(node); } registeredNodes.clear(); + + System.out.println("[JStom] Removing " + trackedEntities.size() + " tracked entities..."); + synchronized (trackedEntities) { + for (Entity entity : trackedEntities) { + entity.remove(); + } + trackedEntities.clear(); + } } public void log(String message) {