diff --git a/dist/pom.xml b/dist/pom.xml index 25100bb2e5..fdaa7fc6bc 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -172,6 +172,9 @@ net.kyori.adventure.nbt com.denizenscript.shaded.net.adventure.nbt + + net.kyori.adventure.nbt.api.* + diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java index 58ff60ed66..a7c00dd7e7 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/PaperModule.java @@ -9,15 +9,16 @@ import com.denizenscript.denizen.paper.events.*; import com.denizenscript.denizen.paper.properties.*; import com.denizenscript.denizen.paper.tags.PaperTagBase; +import com.denizenscript.denizen.paper.tags.TextFormattingTags; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizen.paper.utilities.PaperAPIToolsImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.events.ScriptEvent; import com.denizenscript.denizencore.objects.properties.PropertyParser; import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.denizenscript.denizencore.utilities.debugging.DebugInternals; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; public class PaperModule { @@ -135,33 +136,15 @@ public static void init() { PaperWorldExtensions.register(); // Paper Tags new PaperTagBase(); + new TextFormattingTags(); // Other helpers Bukkit.getPluginManager().registerEvents(new PaperEventHelpers(), Denizen.getInstance()); + DebugInternals.alternateTrimLogic = FormattedTextHelper::bukkitSafeDebugTrimming; PaperAPITools.instance = new PaperAPIToolsImpl(); PacketOutChat.convertComponentToJsonString = (o) -> componentToJson((Component) o); } - public static Component parseFormattedText(String text, ChatColor baseColor) { - if (text == null) { - return null; - } - try { - return jsonToComponent(FormattedTextHelper.componentToJson(FormattedTextHelper.parse(text, baseColor))); - } - catch (Exception ex) { - Debug.verboseLog("Failed to parse formatted text: " + text.replace(ChatColor.COLOR_CHAR, '&')); - throw ex; - } - } - - public static String stringifyComponent(Component component) { - if (component == null) { - return null; - } - return FormattedTextHelper.stringify(FormattedTextHelper.parseJson(componentToJson(component))); - } - public static Component jsonToComponent(String json) { if (json == null) { return null; diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerCompletesAdvancementScriptEventPaperImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerCompletesAdvancementScriptEventPaperImpl.java index 58d0daf4d3..f341f1f171 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerCompletesAdvancementScriptEventPaperImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerCompletesAdvancementScriptEventPaperImpl.java @@ -1,18 +1,18 @@ package com.denizenscript.denizen.paper.events; import com.denizenscript.denizen.events.player.PlayerCompletesAdvancementScriptEvent; -import com.denizenscript.denizen.paper.PaperModule; -import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.utilities.CoreUtilities; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; public class PlayerCompletesAdvancementScriptEventPaperImpl extends PlayerCompletesAdvancementScriptEvent { @Override public ObjectTag getContext(String name) { switch (name) { - case "message": return new ElementTag(PaperModule.stringifyComponent(event.message())); + case "message": return new ElementTag(FormattedTextHelper.stringify(event.message()), true); } return super.getContext(name); } @@ -26,7 +26,7 @@ public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { event.message(null); return true; } - event.message(PaperModule.parseFormattedText(determination, ChatColor.WHITE)); + event.message(FormattedTextHelper.parse(determination, NamedTextColor.WHITE)); return true; } else { diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java index 41d421bd78..83a93394a5 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerNameEntityScriptEvent.java @@ -2,14 +2,14 @@ import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.EntityTag; -import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import io.papermc.paper.event.player.PlayerNameEntityEvent; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -53,7 +53,7 @@ public PlayerNameEntityScriptEvent() { return false; }); this.registerDetermination("name", ElementTag.class, (evt, context, determination) -> { - evt.event.setName(PaperModule.parseFormattedText(determination.toString(), ChatColor.WHITE)); + evt.event.setName(FormattedTextHelper.parse(determination.asString(), NamedTextColor.WHITE)); }); } @@ -81,7 +81,7 @@ public ScriptEntryData getScriptEntryData() { public ObjectTag getContext(String name) { return switch (name) { case "entity" -> entity.getDenizenObject(); - case "name" -> new ElementTag(PaperModule.stringifyComponent(event.getName()), true); + case "name" -> new ElementTag(FormattedTextHelper.stringify(event.getName()), true); case "old_name" -> oldName; case "persistent" -> new ElementTag(event.isPersistent()); default -> super.getContext(name); diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerQuitsScriptEventPaperImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerQuitsScriptEventPaperImpl.java index a899af3781..224e93ed28 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerQuitsScriptEventPaperImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerQuitsScriptEventPaperImpl.java @@ -1,10 +1,10 @@ package com.denizenscript.denizen.paper.events; import com.denizenscript.denizen.events.player.PlayerQuitsScriptEvent; -import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; public class PlayerQuitsScriptEventPaperImpl extends PlayerQuitsScriptEvent { @@ -15,7 +15,7 @@ public PlayerQuitsScriptEventPaperImpl() { event.quitMessage(null); }); this.registerDetermination(null, ElementTag.class, (evt, context, determination) -> { - event.quitMessage(PaperModule.parseFormattedText(determination.toString(), ChatColor.WHITE)); + event.quitMessage(FormattedTextHelper.parse(determination.asString(), NamedTextColor.WHITE)); }); } @@ -30,7 +30,7 @@ public boolean matches(ScriptPath path) { @Override public ObjectTag getContext(String name) { return switch (name) { - case "message" -> new ElementTag(PaperModule.stringifyComponent(event.quitMessage())); + case "message" -> new ElementTag(FormattedTextHelper.stringify(event.quitMessage()), true); case "cause" -> new ElementTag(event.getReason()); default -> super.getContext(name); }; diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerSetSpawnScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerSetSpawnScriptEvent.java index 7f68012369..54f73a07a9 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerSetSpawnScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/PlayerSetSpawnScriptEvent.java @@ -2,13 +2,13 @@ import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.LocationTag; -import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import com.destroystokyo.paper.event.player.PlayerSetSpawnEvent; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -58,7 +58,7 @@ public PlayerSetSpawnScriptEvent() { return false; }); this.registerDetermination("message", ElementTag.class, (evt, context, message) -> { - evt.event.setNotification(PaperModule.parseFormattedText(message.toString(), ChatColor.WHITE)); + evt.event.setNotification(FormattedTextHelper.parse(message.asString(), NamedTextColor.WHITE)); }); this.registerOptionalDetermination("notify", ElementTag.class, (evt, context, value) -> { if (value.isBoolean()) { @@ -97,7 +97,7 @@ public ObjectTag getContext(String name) { case "cause" -> new ElementTag(event.getCause()); case "forced" -> new ElementTag(event.isForced()); case "location" -> event.getLocation() != null ? new LocationTag(event.getLocation()) : null; - case "message" -> event.getNotification() != null ? new ElementTag(PaperModule.stringifyComponent(event.getNotification()), true) : null; + case "message" -> event.getNotification() != null ? new ElementTag(FormattedTextHelper.stringify(event.getNotification()), true) : null; case "notify" -> new ElementTag(event.willNotifyPlayer()); default -> super.getContext(name); }; diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java index 6ea097a13d..84a2f17f30 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/ServerListPingScriptEventPaperImpl.java @@ -5,7 +5,7 @@ import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.nms.abstracts.ProfileEditor; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; @@ -14,7 +14,7 @@ import com.destroystokyo.paper.event.server.PaperServerListPingEvent; import com.destroystokyo.paper.profile.PlayerProfile; import com.destroystokyo.paper.profile.ProfileProperty; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.profile.PlayerTextures; @@ -124,13 +124,13 @@ public static class FakeProfile implements PlayerProfile { @Override public void setMotd(String text) { - event.motd(PaperModule.parseFormattedText(text, ChatColor.WHITE)); + event.motd(FormattedTextHelper.parse(text, NamedTextColor.WHITE)); } @Override public ObjectTag getContext(String name) { return switch (name) { - case "motd" -> new ElementTag(PaperModule.stringifyComponent(event.motd()), true); + case "motd" -> new ElementTag(FormattedTextHelper.stringify(event.motd()), true); case "protocol_version" -> new ElementTag(getEvent().getProtocolVersion()); case "version_name" -> new ElementTag(getEvent().getVersion(), true); case "client_protocol_version" -> new ElementTag(getEvent().getClient().getProtocolVersion()); diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/events/UnknownCommandScriptEvent.java b/paper/src/main/java/com/denizenscript/denizen/paper/events/UnknownCommandScriptEvent.java index c800cf62e0..09d8c2c2fb 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/events/UnknownCommandScriptEvent.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/events/UnknownCommandScriptEvent.java @@ -4,14 +4,14 @@ import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.ArgumentHelper; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; -import net.md_5.bungee.api.ChatColor; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.BlockCommandSender; import org.bukkit.entity.Player; import org.bukkit.entity.minecart.CommandMinecart; @@ -55,7 +55,7 @@ public class UnknownCommandScriptEvent extends BukkitScriptEvent implements List public UnknownCommandScriptEvent() { registerCouldMatcher("command unknown"); this.registerDetermination(null, ElementTag.class, (evt, context, text) -> { - evt.event.message(PaperModule.parseFormattedText(text.toString(), ChatColor.WHITE)); + evt.event.message(FormattedTextHelper.parse(text.asString(), NamedTextColor.WHITE)); }); this.registerTextDetermination("none", (evt) -> { evt.event.message(null); @@ -82,7 +82,7 @@ public ObjectTag getContext(String name) { case "source_type" -> new ElementTag(sourceType, true); case "command_block_location" -> sourceType.equals("command_block") ? new LocationTag(((BlockCommandSender) event.getSender()).getBlock().getLocation()) : null; case "command_minecart" -> sourceType.equals("command_minecart") ? new EntityTag((CommandMinecart) event.getSender()) : null; - case "message" -> new ElementTag(PaperModule.stringifyComponent(event.message()), true); + case "message" -> new ElementTag(FormattedTextHelper.stringify(event.message()), true); default -> super.getContext(name); }; } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java index 090124e434..95603e891a 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/properties/PaperElementExtensions.java @@ -2,15 +2,569 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.paper.PaperModule; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper.LegacyColor; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper.LegacyFormatting; +import com.denizenscript.denizen.paper.utilities.HoverFormatHelper; +import com.denizenscript.denizen.tags.core.CustomColorTagBase; +import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizen.utilities.PaperAPITools; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.tags.TagManager; +import com.denizenscript.denizencore.utilities.AsciiMatcher; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; public class PaperElementExtensions { public static void register() { + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Returns the element with all color encoding stripped. + // This will remove any/all colors, formats (bold/italic/etc), advanced formats (fonts/clickables/etc), and translate any translatables (&translate, &score, etc). + // This will automatically translate translatable sections + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "strip_color", (attribute, object) -> { + return new ElementTag(PlainTextComponentSerializer.plainText().serialize(FormattedTextHelper.parse(object.asString(), NamedTextColor.WHITE)), true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group conversion + // @description + // Converts normal colored text to Minecraft-style "raw JSON" format. + // Inverts <@link tag ElementTag.from_raw_json>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "to_raw_json", (attribute, object) -> { + return new ElementTag(PaperModule.componentToJson(FormattedTextHelper.parse(object.asString(), NamedTextColor.WHITE)), true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group conversion + // @description + // Un-hides the element's text from invisible color codes back to normal text. + // Inverts <@link tag ElementTag.to_raw_json>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "from_raw_json", (attribute, object) -> { + return new ElementTag(FormattedTextHelper.stringify(PaperModule.jsonToComponent(object.asString()))); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group conversion + // @description + // Tells the formatted text parser to try to produce mininalist JSON text. + // This is useful in particular for very long text or where text is being sent rapidly/repeatedly. + // It is not needed in most normal messages. + // It will produce incompatibility issues if used in items or other locations where raw JSON matching is required. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "optimize_json", (attribute, object) -> { + String opti = FormattedTextHelper.LEGACY_SECTION + "[optimize=true]"; + if (object.asString().contains(opti)) { + return object; + } + return new ElementTag(opti + object.asString(), true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a hover message to the element, which makes the element display the input ItemTag when the mouse is left over it. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // @example + // - narrate "You can ]> to see what you held!" + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ItemTag.class, "hover_item", (attribute, object, item) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[hover=SHOW_ITEM;" + FormattedTextHelper.escape(item.identify()) + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/hover]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a hover message to the element, which makes the element display the input hover text when the mouse is left over it. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerTag(ElementTag.class, ObjectTag.class, "on_hover", (attribute, object, hover) -> { // non-static due to hacked sub-tag + HoverEvent.Action type = HoverEvent.Action.SHOW_TEXT; + + // <--[tag] + // @attribute ].type[]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a hover message to the element, which makes the element display the input hover text when the mouse is left over it. + // Available hover types: SHOW_TEXT, SHOW_ITEM, or SHOW_ENTITY. + // Note: for "SHOW_ITEM", replace the text with a valid ItemTag. For "SHOW_ENTITY", replace the text with a valid spawned EntityTag (requires F3+H to see entities). + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // For show_text, prefer <@link tag ElementTag.on_hover> + // For show_item, prefer <@link tag ElementTag.hover_item> + // --> + if (attribute.startsWith("type", 2)) { + attribute.fulfill(1); + if (!attribute.hasParam()) { + attribute.echoError("Must specify an hover type."); + return null; + } + type = HoverEvent.Action.NAMES.value(CoreUtilities.toLowerCase(attribute.getParam())); + if (type == null) { + attribute.echoError("Invalid hover type specified."); + return null; + } + } + String hoverData = HoverFormatHelper.parseObjectToHover(hover, type, attribute); + if (hoverData == null) { + return null; + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[hover=" + type + ';' + FormattedTextHelper.escape(hoverData) + ']' + + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/hover]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a click command to the element, which makes the element open the given URL when clicked. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // @example + // - narrate "You can to learn about Denizen!" + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "click_url", (attribute, object, url) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[click=OPEN_URL;" + FormattedTextHelper.escape(url.asString()) + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/click]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a click command to the element, which makes the element pseudo-chat the input message when clicked, for activating interact script chat triggers (<@link language Chat Triggers>). + // This internally uses the command "/denizenclickable chat SOME MESSAGE HERE" (requires players have permission "denizen.clickable") + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // @example + // - narrate "You can to say hello to an NPC's interact script!" + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "click_chat", (attribute, object, chat) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[click=RUN_COMMAND;/denizenclickable chat " + FormattedTextHelper.escape(chat.asString()) + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/click]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a click command to the element, which makes the element execute the input command when clicked. + // To execute a command "/" should be used at the start. Prior to 1.19, leaving off the "/" would display the text as chat. This feature was removed as part of the 1.19 secure chat system. + // For activating interact script chat triggers (<@link language Chat Triggers>), you can use the command "/denizenclickable chat SOME MESSAGE HERE" (requires players have permission "denizen.clickable") + // For that, instead prefer <@link tag ElementTag.click_chat> + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // @example + // - narrate "You can for help!" + // @example + // - narrate "You can to say hello to an NPC's interact script!" + // --> + ElementTag.tagProcessor.registerTag(ElementTag.class, ElementTag.class, "on_click", (attribute, object, command) -> { // non-static due to hacked sub-tag + String type = "RUN_COMMAND"; + + // <--[tag] + // @attribute ].type[]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds a click command to the element, which makes the element execute the input command when clicked. + // Available command types: OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, COPY_TO_CLIPBOARD, or CHANGE_PAGE. + // For example: - narrate "You can to learn about Denizen!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // For run_command, prefer <@link tag ElementTag.on_click> + // For chat, prefer <@link tag ElementTag.click_chat> + // For URLs, prefer <@link tag ElementTag.click_url> + // --> + if (attribute.startsWith("type", 2)) { + type = attribute.getContext(2); + attribute.fulfill(1); + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[click=" + type + ";" + FormattedTextHelper.escape(command.asString()) + "]" + + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/click]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Adds an insertion message to the element, which makes the element insert the input message to chat when shift-clicked. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "with_insertion", (attribute, object, insertion) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[insertion=" + FormattedTextHelper.escape(insertion.asString()) + "]" + + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[/insertion]", true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes a color code (&0123456789abcdef) not reset other formatting details. + // Use like '<&c.no_reset>' or ''. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "no_reset", (attribute, object) -> { + if (object.asString().length() == 2 && object.asString().charAt(0) == FormattedTextHelper.LEGACY_SECTION) { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=" + object.asString().charAt(1) + "]", true); + } + return null; + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes a chat format code (&klmno, or &[font=...]) be the end of a format, as opposed to the start. + // Use like '<&o.end_format>' or ''. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "end_format", (attribute, object) -> { + if (object.asString().length() == 2 && object.asString().charAt(0) == FormattedTextHelper.LEGACY_SECTION) { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[reset=" + object.asString().charAt(1) + "]", true); + } + else if (object.asString().startsWith(FormattedTextHelper.LEGACY_SECTION + "[font=") && object.asString().endsWith("]")) { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[reset=font]", true); + } + return null; + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text italic. Equivalent to "<&o><&o.end_format>" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "italicize", (attribute, object) -> { + return new ElementTag(LegacyFormatting.ITALIC + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=o]", true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text bold. Equivalent to "<&l><&l.end_format>" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "bold", (attribute, object) -> { + return new ElementTag(LegacyFormatting.BOLD + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=l]", true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text underlined. Equivalent to "<&n><&n.end_format>" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "underline", (attribute, object) -> { + return new ElementTag(LegacyFormatting.UNDERLINE + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=n]", true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text struck-through. Equivalent to "<&m><&m.end_format>" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "strikethrough", (attribute, object) -> { + return new ElementTag(LegacyFormatting.STRIKETHROUGH + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=m]", true); + }); + + // <--[tag] + // @attribute + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text obfuscated. Equivalent to "<&k><&k.end_format>" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "obfuscate", (attribute, object) -> { + return new ElementTag(LegacyFormatting.OBFUSCATED + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=k]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text colored by the custom color value based on the common base color names defined in the Denizen config file. + // If the color name is unrecognized, returns the value of color named 'default'. + // Default color names are 'base', 'emphasis', 'warning', 'error'. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "custom_color", (attribute, object, name) -> { + String color = CustomColorTagBase.getColor(name.asLowerString(), attribute.context); + if (color == null) { + return null; + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=f]" + color + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text colored by the input color. Equivalent to "" + // Color can be a color name, color code, hex, or ColorTag... that is: ".color[gold]", ".color[6]", and ".color[#AABB00]" are all valid. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "color", (attribute, object, colorElement) -> { + String colorName = colorElement.asString(); + String colorOut = null; + if (colorName.length() == 1) { + LegacyColor color = LegacyColor.legacyFromChar(colorName.charAt(0)); + if (color != null) { + colorOut = color.toString(); + } + } + else if (colorName.length() == 7 && colorName.startsWith("#")) { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=" + colorName + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + } + else if (colorName.length() == 14 && colorName.startsWith(FormattedTextHelper.LEGACY_SECTION + "x")) { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=#" + CoreUtilities.replace(colorName.substring(2), String.valueOf(FormattedTextHelper.LEGACY_SECTION), "") + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + } + else if (colorName.startsWith("co@")) { + ColorTag color = ColorTag.valueOf(colorName, attribute.context); + if (color == null && TagManager.isStaticParsing) { + return null; + } + StringBuilder hex = new StringBuilder(Integer.toHexString(color.asRGB())); + while (hex.length() < 6) { + hex.insert(0, "0"); + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=#" + hex + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + } + if (colorOut == null) { + NamedTextColor namedColor = NamedTextColor.NAMES.value(CoreUtilities.toLowerCase(colorName)); + if (namedColor == null) { + ColorTag color = ColorTag.valueOf(colorName, attribute.context); + if (color != null) { + StringBuilder hex = new StringBuilder(Integer.toHexString(color.asRGB())); + while (hex.length() < 6) { + hex.insert(0, "0"); + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[color=#" + hex + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + } + if (!TagManager.isStaticParsing) { + attribute.echoError("Color '" + colorName + "' doesn't exist (for ElementTag.color[...])."); + } + return null; + } + colorOut = FormattedTextHelper.LEGACY_SECTION + "[color=" + LegacyColor.fromModern(namedColor).colorChar + "]"; + + } + return new ElementTag(colorOut + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=color]", true); + }); + + // <--[tag] + // @attribute ]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Makes the input text display with the input font name. Equivalent to "<&font[new-font]><&font[new-font].end_format>" + // The default font is "minecraft:default". + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "font", (attribute, object, fontName) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[font=" + fontName + "]" + object.asString() + FormattedTextHelper.LEGACY_SECTION + "[reset=font]", true); + }); + + // <--[tag] + // @attribute )]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Returns the element with rainbow colors applied. + // Optionally, specify a color pattern to follow. By default, this is "4c6e2ab319d5". + // That is, a repeating color of: Red, Orange, Yellow, Green, Cyan, Blue, Purple. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "rainbow", (attribute, object) -> { + String str = object.asString(); + String pattern = "4c6e2ab319d5"; + if (attribute.hasParam()) { + pattern = attribute.getParam(); + } + StringBuilder output = new StringBuilder(str.length() * 3); + for (int i = 0; i < str.length(); i++) { + output.append(FormattedTextHelper.LEGACY_SECTION).append(pattern.charAt(i % pattern.length())).append(str.charAt(i)); + } + return new ElementTag(output.toString(), true); + }); + + // <--[tag] + // @attribute )]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Returns the element with RGB rainbow colors applied. + // Optionally, specify a length (how many characters before the colors repeat). If unspecified, will use the input element length. + // If the element starts with a hex color code, that will be used as the starting color of the rainbow. + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "hex_rainbow", (attribute, object) -> { + String str = object.asString(); + int[] HSB = new int[] { 0, 255, 255 }; + if (str.startsWith(FormattedTextHelper.LEGACY_SECTION + "x") && str.length() > 14) { + char[] colors = new char[6]; + for (int i = 0; i < 6; i++) { + colors[i] = str.charAt(3 + (i * 2)); + } + int rgb = Integer.parseInt(new String(colors), 16); + HSB = ColorTag.fromRGB(rgb).toHSB(); + str = str.substring(14); + } + float hue = HSB[0] / 255f; + int length = PlainTextComponentSerializer.plainText().serialize(FormattedTextHelper.parse(str, NamedTextColor.WHITE)).length(); + if (length == 0) { + return new ElementTag("", true); + } + if (attribute.hasParam()) { + length = attribute.getIntParam(); + } + float increment = 1.0f / length; + String addedFormat = ""; + StringBuilder output = new StringBuilder(str.length() * 8); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == FormattedTextHelper.LEGACY_SECTION && i + 1 < str.length()) { + char c2 = str.charAt(i + 1); + if (FORMAT_CODES_MATCHER.isMatch(c2)) { + addedFormat += String.valueOf(FormattedTextHelper.LEGACY_SECTION) + c2; + } + else { + addedFormat = ""; + } + i++; + continue; + } + String hex = Integer.toHexString(ColorTag.fromHSB(HSB).asRGB()); + output.append(FormattedTextHelper.stringifyRGBSpigot(hex)).append(addedFormat).append(c); + hue += increment; + HSB[0] = Math.round(hue * 255f); + } + return new ElementTag(output.toString(), true); + }); + + // <--[tag] + // @attribute ;to=;(style={RGB}/HSB)]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @description + // Returns the element with an RGB color gradient applied, with a unique color per character. + // Specify the input as a map with keys 'from' and 'to' both set to hex colors (or any valid ColorTag). + // You can also choose a style (defaults to RGB): + // "style=RGB" tends to produce smooth gradients, + // "style=HSB" tends to produce bright rainbow-like color patterns. + // @example + // - narrate "" + // @example + // - narrate "" + // @example + // - narrate "" + // @example + // - narrate "" + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, MapTag.class, "color_gradient", (attribute, object, inputMap) -> { + ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); + ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); + ElementTag style = inputMap.getElement("style", "RGB"); + if (fromColor == null || toColor == null) { + return null; + } + if (!style.matchesEnum(GradientStyle.class)) { + attribute.echoError("Invalid gradient style '" + style + "'"); + return null; + } + String res = doGradient(object.asString(), fromColor, toColor, style.asEnum(GradientStyle.class)); + if (res == null) { + return null; + } + return new ElementTag(res, true); + }); + + // <--[tag] + // @attribute ;to=]> + // @returns ElementTag + // @Plugin Paper + // @group text manipulation + // @deprecated use color_gradient[from=color;to=color;style=HSB] + // @description + // Deprecated in favor of using <@link tag ElementTag.color_gradient> with "style=hsb" + // --> + ElementTag.tagProcessor.registerStaticTag(ElementTag.class, MapTag.class, "hsb_color_gradient", (attribute, object, inputMap) -> { + BukkitImplDeprecations.hsbColorGradientTag.warn(attribute.context); + ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); + ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); + if (fromColor == null || toColor == null) { + return null; + } + String res = doGradient(object.asString(), fromColor, toColor, GradientStyle.HSB); + if (res == null) { + return null; + } + return new ElementTag(res, true); + }); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_18)) { // <--[tag] @@ -23,7 +577,7 @@ public static void register() { // This may be useful for reading data from external plugins, but should not be used in normal scripts. // --> ElementTag.tagProcessor.registerTag(ElementTag.class, "parse_minimessage", (attribute, object) -> { - return new ElementTag(PaperModule.stringifyComponent(MiniMessage.miniMessage().deserialize(object.asString()))); + return new ElementTag(FormattedTextHelper.stringify(MiniMessage.miniMessage().deserialize(object.asString()))); }); // <--[tag] @@ -40,4 +594,96 @@ public static void register() { }); } } + + public enum GradientStyle { RGB, HSB } + + public static String doGradient(String str, ColorTag fromColor, ColorTag toColor, GradientStyle style) { + int length = PlainTextComponentSerializer.plainText().serialize(FormattedTextHelper.parse(str, NamedTextColor.WHITE)).length(); + if (length == 0) { + return ""; + } + if (fromColor == null || toColor == null) { + return null; + } + float r, g, b, x = 0, rMove, gMove, bMove, xMove = 0, toR, toG, toB; + int[] hsbHelper = null; + if (style == GradientStyle.RGB) { + r = ColorTag.fromSRGB(fromColor.red); + g = ColorTag.fromSRGB(fromColor.green); + b = ColorTag.fromSRGB(fromColor.blue); + x = (float) Math.pow(r + g + b, 0.43); + toR = ColorTag.fromSRGB(toColor.red); + toG = ColorTag.fromSRGB(toColor.green); + toB = ColorTag.fromSRGB(toColor.blue); + float toBrightness = (float) Math.pow(toR + toG + toB, 0.43); + xMove = (toBrightness - x) / length; + } + else { + hsbHelper = fromColor.toHSB(); + int[] toHSB = toColor.toHSB(); + r = hsbHelper[0]; + g = hsbHelper[1]; + b = hsbHelper[2]; + toR = toHSB[0]; + toG = toHSB[1]; + toB = toHSB[2]; + } + rMove = (toR - r) / length; + gMove = (toG - g) / length; + bMove = (toB - b) / length; + String addedFormat = ""; + StringBuilder output = new StringBuilder(str.length() * 15); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == FormattedTextHelper.LEGACY_SECTION && i + 1 < str.length()) { + char c2 = str.charAt(i + 1); + if (FORMAT_CODES_MATCHER.isMatch(c2)) { + addedFormat += String.valueOf(FormattedTextHelper.LEGACY_SECTION) + c2; + } + else if (c2 == '[') { + int endBracket = str.indexOf(']', i); + if (endBracket != -1) { + addedFormat += str.substring(i, endBracket + 1); + i = endBracket - 1; + } + } + else { + addedFormat = ""; + } + i++; + continue; + } + String hex; + if (style == GradientStyle.RGB) { + // Based on https://stackoverflow.com/questions/22607043/color-gradient-algorithm/49321304#49321304 + float newRed = r, newGreen = g, newBlue = b; + float sum = newRed + newGreen + newBlue; + if (sum > 0) { + float multiplier = (float) Math.pow(x, 1f / 0.43f) / sum; + newRed *= multiplier; + newGreen *= multiplier; + newBlue *= multiplier; + } + newRed = ColorTag.toSRGB(newRed); + newGreen = ColorTag.toSRGB(newGreen); + newBlue = ColorTag.toSRGB(newBlue); + hex = Integer.toHexString((((int) newRed) << 16) | (((int) newGreen) << 8) | ((int) newBlue)); + x += xMove; + } + else { + hsbHelper[0] = (int)r; + hsbHelper[1] = (int)g; + hsbHelper[2] = (int)b; + ColorTag currentColor = ColorTag.fromHSB(hsbHelper); + hex = Integer.toHexString(currentColor.asRGB()); + } + output.append(FormattedTextHelper.stringifyRGBSpigot(hex)).append(addedFormat).append(str.charAt(i)); + r += rMove; + g += gMove; + b += bMove; + } + return output.toString(); + } + + public static AsciiMatcher FORMAT_CODES_MATCHER = new AsciiMatcher("klmnoKLMNO"); } diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/tags/TextFormattingTags.java b/paper/src/main/java/com/denizenscript/denizen/paper/tags/TextFormattingTags.java new file mode 100644 index 0000000000..0a2a1e6df4 --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/tags/TextFormattingTags.java @@ -0,0 +1,360 @@ +package com.denizenscript.denizen.paper.tags; + +import com.denizenscript.denizen.paper.properties.PaperElementExtensions; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper; +import com.denizenscript.denizen.paper.utilities.FormattedTextHelper.LegacyColor; +import com.denizenscript.denizen.paper.utilities.HoverFormatHelper; +import com.denizenscript.denizen.utilities.BukkitImplDeprecations; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.tags.TagManager; +import com.denizenscript.denizencore.tags.core.EscapeTagUtil; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; + +public class TextFormattingTags { + + public TextFormattingTags() { + + // <--[tag] + // @attribute <&hover[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that makes the following text display the input hover text when the mouse is left over it. + // This tag must be followed by an <&end_hover> tag. + // For example: - narrate "There is a <&hover[you found it!]>secret<&end_hover> in this message!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerTagHandler(ElementTag.class, ObjectTag.class, "&hover", (attribute, hover) -> { // Cannot be static due to hacked sub-tag + + // <--[tag] + // @attribute <&hover[].type[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that makes the following text display the input hover text when the mouse is left over it. + // This tag must be followed by an <&end_hover> tag. + // Available hover types: SHOW_TEXT, SHOW_ITEM, or SHOW_ENTITY. + // For example: - narrate "There is a <&hover[you found it!].type[SHOW_TEXT]>secret<&end_hover> in this message!" + // Note: for "SHOW_ITEM", replace the text with a valid ItemTag. For "SHOW_ENTITY", replace the text with a valid spawned EntityTag (requires F3+H to see entities). + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + HoverEvent.Action type = HoverEvent.Action.SHOW_TEXT; + if (attribute.startsWith("type", 2)) { + attribute.fulfill(1); + if (!attribute.hasParam()) { + attribute.echoError("Must specify an hover type."); + return null; + } + type = HoverEvent.Action.NAMES.value(CoreUtilities.toLowerCase(attribute.getParam())); + if (type == null) { + attribute.echoError("Invalid hover type specified."); + return null; + } + } + String hoverData = HoverFormatHelper.parseObjectToHover(hover, type, attribute); + if (hoverData == null) { + return null; + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[hover=" + type + ';' + FormattedTextHelper.escape(hoverData) + ']', true); + }); + + // <--[tag] + // @attribute <&click[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that makes the following text execute the input command line value when clicked. + // To execute a command "/" should be used at the start. Otherwise, it will display as chat. + // This tag must be followed by an <&end_click> tag. + // For example: - narrate "You can <&click[wow]>click here<&end_click> to say wow!" + // For example: - narrate "You can <&click[/help]>click here<&end_click> for help!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerTagHandler(ElementTag.class, "&click", (attribute) -> { // Cannot be static due to hacked sub-tag + if (!attribute.hasParam()) { + return null; + } + String clickText = attribute.getParam(); + + // <--[tag] + // @attribute <&click[].type[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that makes the following text execute the input command when clicked. + // This tag must be followed by an <&end_click> tag. + // Available command types: OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, COPY_TO_CLIPBOARD, or CHANGE_PAGE. + // For example: - narrate "You can <&click[https://denizenscript.com].type[OPEN_URL]>click here<&end_click> to learn about Denizen!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + String type = "RUN_COMMAND"; + if (attribute.startsWith("type", 2)) { + type = attribute.getContext(2); + attribute.fulfill(1); + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[click=" + type + ";" + FormattedTextHelper.escape(clickText) + "]", true); + }); + + // <--[tag] + // @attribute <&insertion[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that makes the following text insert the input message to chat when shift-clicked. + // This tag must be followed by an <&end_insertion> tag. + // For example: - narrate "You can <&insertion[wow]>click here<&end_insertion> to add 'wow' to your chat!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&insertion", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + String insertText = attribute.getParam(); + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[insertion=" + FormattedTextHelper.escape(insertText) + "]", true); + }); + + // <--[tag] + // @attribute <&end_click> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that ends a '&click' tag. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_click", (attribute) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[/click]", true); + }); + + // <--[tag] + // @attribute <&end_hover> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that ends a '&hover' tag. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_hover", (attribute) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[/hover]", true); + }); + + // <--[tag] + // @attribute <&end_insertion> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that ends an '&insertion' tag. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_insertion", (attribute) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[/insertion]", true); + }); + + // <--[tag] + // @attribute <&keybind[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that displays a keybind. + // For example: - narrate "Press your <&keybind[key.jump]> key!" + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&keybind", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + String keybindText = attribute.getParam(); + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[keybind=" + FormattedTextHelper.escape(keybindText) + "]", true); + }); + + // <--[tag] + // @attribute <&selector[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that displays a vanilla selector. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&selector", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + String selectorText = attribute.getParam(); + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[selector=" + FormattedTextHelper.escape(selectorText) + "]", true); + }); + + // <--[tag] + // @attribute <&translate[key=;(fallback=);(with=|...)]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that is read by the client to display an auto-translated message. + // "key" is the translation key. + // Optionally specify "fallback" as text to display when the client can't find a translation for the key. + // Optionally specify "with" as a list of input data for the translatable message (parts of the message that are dynamic). + // Be warned that language keys can change between Minecraft versions. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // You can use <@link tag ElementTag.strip_color> to convert the translated output to plain text (pre-translated). + // @example + // # Narrates a translatable of a diamond sword's name. + // - narrate "Reward: <&translate[key=item.minecraft.diamond_sword]>" + // @example + // # Narrates a translatable with some input data. + // - narrate <&translate[key=commands.give.success.single;with=32|<&translate[key=item.minecraft.diamond_sword]>|]> + // @example + // # Narrates a custom translatable (from something like a resource pack), with a fallback in case it can't be translated. + // - narrate <&translate[key=my.custom.translation;fallback=Please use the resource pack!]> + // --> + TagManager.registerTagHandler(ElementTag.class, ObjectTag.class, "&translate", (attribute, param) -> { // Cannot be static due to hacked sub-tag + MapTag translateMap = param.asType(MapTag.class, CoreUtilities.noDebugContext); + if (translateMap == null) { + BukkitImplDeprecations.translateLegacySyntax.warn(attribute.context); + translateMap = new MapTag(); + translateMap.putObject("key", param); + + // <--[tag] + // @attribute <&translate[].with[|...]> + // @returns ElementTag + // @Plugin Paper + // @deprecated Use '<&translate[key=;with=|...]>'. + // @description + // Deprecated in favor of <@link tag &translate>. + // --> + if (attribute.startsWith("with", 2)) { + translateMap.putObject("with", new ListTag(attribute.contextAsType(2, ListTag.class), with -> new ElementTag(EscapeTagUtil.unEscape(with), true))); + attribute.fulfill(1); + } + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[translate=" + FormattedTextHelper.escape(translateMap.savable()) + ']', true); + }); + + // <--[tag] + // @attribute <&score[|(|)]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a special chat code that displays a scoreboard entry. Input is an escaped list of: + // Name of the relevant entity, name of the objective, then optionally a value (if unspecified, will use current scoreboard value). + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&score", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + ListTag scoreList = attribute.paramAsType(ListTag.class); + if (scoreList.size() < 2) { + return null; + } + String name = FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(0))); + String objective = FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(1))); + String value = scoreList.size() >= 3 ? FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(2))) : ""; + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[score=" + name + ";" + objective + ";" + value + "]", true); + }); + + // <--[tag] + // @attribute <&color[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a chat code that makes the following text be the specified color. + // Color can be a color name, color code, hex, or ColorTag... that is: "&color[gold]", "&color[6]", and "&color[#AABB00]" are all valid. + // The ColorTag input option can be used for dynamic color effects, such as automatic rainbows. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&color", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + String colorName = attribute.getParam(); + String colorOut = null; + if (colorName.length() == 1) { + LegacyColor color = LegacyColor.legacyFromChar(colorName.charAt(0)); + if (color != null) { + colorOut = color.toString(); + } + } + else if (colorName.length() == 7 && colorName.startsWith("#")) { + colorOut = FormattedTextHelper.stringifyRGBSpigot(colorName.substring(1)); + } + else if (colorName.startsWith("co@") || colorName.lastIndexOf(',') > colorName.indexOf(',')) { + ColorTag color = ColorTag.valueOf(colorName, attribute.context); + if (color == null && TagManager.isStaticParsing) { + return null; + } + String hex = Integer.toHexString(color.asRGB()); + colorOut = FormattedTextHelper.stringifyRGBSpigot(hex); + } + if (colorOut == null) { + NamedTextColor color = NamedTextColor.NAMES.value(CoreUtilities.toLowerCase(colorName)); + if (color == null) { + attribute.echoError("Color '" + colorName + "' doesn't exist (for tag &color[...])."); + return null; + } + colorOut = LegacyColor.fromModern(color).toString(); + } + return new ElementTag(colorOut, true); + }); + + // <--[tag] + // @attribute <&gradient[from=;to=;(style={RGB}/HSB)]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a chat code that makes the following text be the specified color. + // Input works equivalently to <@link tag ElementTag.color_gradient>, return to that tag for more documentation detail and input examples. + // The gradient runs from whatever text is after this gradient, until the next color tag (0-9, a-f, 'r' reset, or an RGB code. Does not get stop at formatting codes, they will be included in the gradient). + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // @example + // - narrate "<&gradient[from=black;to=white]>these are the shades of gray that solidifies to pure white" + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, MapTag.class, "&gradient", (attribute, inputMap) -> { + ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); + ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); + ElementTag style = inputMap.getElement("style", "RGB"); + if (fromColor == null || toColor == null) { + return null; + } + if (!style.matchesEnum(PaperElementExtensions.GradientStyle.class)) { + attribute.echoError("Invalid gradient style '" + style + "'"); + return null; + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[gradient=" + fromColor + ";" + toColor + ";" + style + "]", true); + }); + + // <--[tag] + // @attribute <&font[]> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a chat code that makes the following text display with the specified font. + // The default font is "minecraft:default". + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&font", (attribute) -> { + if (!attribute.hasParam()) { + return null; + } + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[font=" + attribute.getParam() + "]", true); + }); + + // <--[tag] + // @attribute <&optimize> + // @returns ElementTag + // @Plugin Paper + // @description + // Returns a chat code that tells the formatted text parser to try to produce mininalist JSON text. + // This is useful in particular for very long text or where text is being sent rapidly/repeatedly. + // It is not needed in most normal messages. + // It will produce incompatibility issues if used in items or other locations where raw JSON matching is required. + // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. + // --> + TagManager.registerStaticTagBaseHandler(ElementTag.class, "&optimize", (attribute) -> { + return new ElementTag(FormattedTextHelper.LEGACY_SECTION + "[optimize=true]", true); + }); + } +} diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/FormattedTextHelper.java similarity index 52% rename from plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java rename to paper/src/main/java/com/denizenscript/denizen/paper/utilities/FormattedTextHelper.java index 67392b5fa9..02e17e626a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/FormattedTextHelper.java @@ -1,893 +1,954 @@ -package com.denizenscript.denizen.utilities; - -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.NMSVersion; -import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions; -import com.denizenscript.denizencore.objects.core.ColorTag; -import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.core.ListTag; -import com.denizenscript.denizencore.objects.core.MapTag; -import com.denizenscript.denizencore.utilities.AsciiMatcher; -import com.denizenscript.denizencore.utilities.CoreConfiguration; -import com.denizenscript.denizencore.utilities.CoreUtilities; -import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; -import com.google.gson.Gson; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.*; -import net.md_5.bungee.chat.ChatVersion; -import net.md_5.bungee.chat.ComponentSerializer; -import net.md_5.bungee.chat.VersionedComponentSerializer; - -import java.util.List; - -public class FormattedTextHelper { - - // <--[language] - // @name Denizen Text Formatting - // @group Denizen Magic - // @description - // Denizen provides a variety of special chat format options like "on_hover" and "on_click". - // These options exist within Denizen and do not appear in the historical Minecraft legacy chat format that most plugins and systems read. - // That legacy system has 16 colors (0-9, A-F) and a few toggleable formats (bold, italic, etc). It does not contain anything that needs more than just an on/off. - // - // Modern Minecraft, however, supports a JSON based "raw" message format that can do click events, hover events, full RGB colors, etc. - // - // Denizen therefore has its own internal system that works like the legacy format system, but also supports the new options normally only available as 'raw JSON'. - // - // Because it is entirely processed within Denizen, these options only work within Denizen, when performing actions that support raw JSON input. - // This magic tool exists to let you write messages without having to write the messy JSON. - // - // Be aware that many inputs do not support raw JSON, and as such are limited only the historical Minecraft legacy format. - // Also be aware that click events, hover events, etc. are exclusively limited to the chat bar and the pages of books, as you cannot mouse over anything else. - // - // Also note that RGB colors use a format that Spigot invented, meaning they will work in places that use Spigot's parser OR Denizen's version, but nowhere that uses the vanilla format still. - // - // Thanks to Paper's implementation of component APIs where Spigot was too lazy to, Paper servers have advanced text formatting available in more areas. - // --> - - public static AsciiMatcher needsEscapeMatcher = new AsciiMatcher("&;[]"); - - public static String escape(String input) { - if (needsEscapeMatcher.containsAnyMatch(input)) { - input = input.replace("&", "&").replace(";", "&sc").replace("[", "&lb").replace("]", "&rb").replace("\n", "&nl"); - } - return input.replace(String.valueOf(ChatColor.COLOR_CHAR), "&ss"); - } - - public static String unescape(String input) { - if (input.indexOf('&') != -1) { - return input.replace("&sc", ";").replace("&lb", "[").replace("&rb", "]").replace("&nl", "\n").replace("&ss", String.valueOf(ChatColor.COLOR_CHAR)).replace("&", "&"); - } - return input; - } - - public static boolean hasRootFormat(BaseComponent component) { - if (component == null) { - return false; - } - if (component.hasFormatting()) { - return true; - } - if (!(component instanceof TextComponent)) { - return false; - } - if (!((TextComponent) component).getText().isEmpty()) { - return false; - } - List extra = component.getExtra(); - if (extra == null || extra.isEmpty()) { - return false; - } - return hasRootFormat(extra.get(0)); - } - - public static String stringify(BaseComponent[] components) { - if (components == null) { - return null; - } - if (components.length == 0) { - return ""; - } - StringBuilder builder = new StringBuilder(128 * components.length); - if (hasRootFormat(components[0])) { - builder.append(RESET); - } - for (BaseComponent component : components) { - if (component != null) { - builder.append(stringify(component)); - } - } - String output = builder.toString(); - while (output.endsWith(RESET)) { - output = output.substring(0, output.length() - RESET.length()); - } - while (output.startsWith(POSSIBLE_RESET_PREFIX) && output.length() > 4 && colorCodeInvalidator.isMatch(output.charAt(3))) { - output = output.substring(2); - } - return cleanRedundantCodes(output); - } - - public static String stringifyRGBSpigot(String hex) { - StringBuilder hexBuilder = new StringBuilder(7); - hexBuilder.append('x'); - for (int i = hex.length(); i < 6; i++) { - hexBuilder.append('0'); - } - hexBuilder.append(hex); - hex = hexBuilder.toString(); - StringBuilder outColor = new StringBuilder(); - for (char c : hex.toCharArray()) { - outColor.append(org.bukkit.ChatColor.COLOR_CHAR).append(c); - } - return outColor.toString(); - } - - public static String stringify(BaseComponent component) { - return stringifySub(component, null); - } - - public static String stringifySub(BaseComponent component, ChatColor parentColor) { - if (component == null) { - return null; - } - StringBuilder builder = new StringBuilder(128); - ChatColor color = component.getColorRaw(); - if (color == null) { - color = parentColor; - } - if (color != null) { - builder.append(color); - } - if (component.isBold()) { - builder.append(ChatColor.BOLD); - } - if (component.isItalic()) { - builder.append(ChatColor.ITALIC); - } - if (component.isStrikethrough()) { - builder.append(ChatColor.STRIKETHROUGH); - } - if (component.isUnderlined()) { - builder.append(ChatColor.UNDERLINE); - } - if (component.isObfuscated()) { - builder.append(ChatColor.MAGIC); - } - boolean hasFont = component.getFontRaw() != null; - if (hasFont) { - builder.append(ChatColor.COLOR_CHAR).append("[font=").append(component.getFont()).append("]"); - } - boolean hasInsertion = component.getInsertion() != null; - if (hasInsertion) { - builder.append(ChatColor.COLOR_CHAR).append("[insertion=").append(escape(component.getInsertion())).append("]"); - } - boolean hasHover = component.getHoverEvent() != null; - if (hasHover) { - HoverEvent hover = component.getHoverEvent(); - builder.append(ChatColor.COLOR_CHAR).append("[hover=").append(hover.getAction().name()).append(";").append(escape(HoverFormatHelper.stringForHover(hover))).append("]"); - } - boolean hasClick = component.getClickEvent() != null; - if (hasClick) { - ClickEvent click = component.getClickEvent(); - builder.append(ChatColor.COLOR_CHAR).append("[click=").append(click.getAction().name()).append(";").append(escape(click.getValue())).append("]"); - } - if (component instanceof TextComponent) { - builder.append(((TextComponent) component).getText()); - } - else if (component instanceof TranslatableComponent translatableComponent) { - MapTag map = new MapTag(); - map.putObject("key", new ElementTag(translatableComponent.getTranslate(), true)); - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && translatableComponent.getFallback() != null) { - map.putObject("fallback", new ElementTag(translatableComponent.getFallback(), true)); - } - if (translatableComponent.getWith() != null) { - map.putObject("with", new ListTag(translatableComponent.getWith(), baseComponent -> new ElementTag(stringify(baseComponent), true))); - } - builder.append(ChatColor.COLOR_CHAR).append("[translate=").append(escape(map.savable())).append(']'); - } - else if (component instanceof SelectorComponent) { - builder.append(ChatColor.COLOR_CHAR).append("[selector=").append(escape(((SelectorComponent) component).getSelector())).append("]"); - } - else if (component instanceof KeybindComponent) { - builder.append(ChatColor.COLOR_CHAR).append("[keybind=").append(escape(((KeybindComponent) component).getKeybind())).append("]"); - } - else if (component instanceof ScoreComponent) { - builder.append(ChatColor.COLOR_CHAR).append("[score=").append(escape(((ScoreComponent) component).getName())) - .append(";").append(escape(((ScoreComponent) component).getObjective())) - .append(";").append(escape(((ScoreComponent) component).getValue())).append("]"); - } - List after = component.getExtra(); - if (after != null) { - for (BaseComponent afterComponent : after) { - builder.append(stringifySub(afterComponent, color)); - } - } - if (hasClick) { - builder.append(ChatColor.COLOR_CHAR + "[/click]"); - } - if (hasHover) { - builder.append(ChatColor.COLOR_CHAR + "[/hover]"); - } - if (hasInsertion) { - builder.append(ChatColor.COLOR_CHAR + "[/insertion]"); - } - if (hasFont) { - builder.append(ChatColor.COLOR_CHAR + "[reset=font]"); - } - builder.append(RESET); - String output = builder.toString(); - return cleanRedundantCodes(output); - } - - public static final String RESET = ChatColor.RESET.toString(), POSSIBLE_RESET_PREFIX = RESET + ChatColor.COLOR_CHAR; - - private static Boolean procBool(Boolean input, boolean optimize) { - if (input == null) { - return null; - } - if (optimize) { - return input ? true : null; - } - return input; - } - - public static TextComponent copyFormatToNewText(TextComponent last, boolean optimize) { - TextComponent toRet = new TextComponent(); - toRet.setObfuscated(procBool(last.isObfuscatedRaw(), optimize)); - toRet.setBold(procBool(last.isBoldRaw(), optimize)); - toRet.setStrikethrough(procBool(last.isStrikethroughRaw(), optimize)); - toRet.setUnderlined(procBool(last.isUnderlinedRaw(), optimize)); - toRet.setItalic(procBool(last.isItalicRaw(), optimize)); - toRet.setColor(last.getColorRaw()); - return toRet; - } - - public static BaseComponent[] parse(String str, ChatColor baseColor) { - if (str == null) { - return null; - } - return parse(str, baseColor, true); - } - - public static int findNextNormalColorSymbol(String base, int startAt) { - while (true) { - int next = base.indexOf(ChatColor.COLOR_CHAR, startAt); - if (next == -1 || next + 1 >= base.length()) { - return -1; - } - char after = base.charAt(next + 1); - if (colorCodeInvalidator.isMatch(after)) { - return next; - } - startAt = next + 1; - } - } - - public static int findEndIndexFor(String base, String startSymbol, String endSymbol, int startAt) { - int layers = 1; - while (true) { - int next = base.indexOf(ChatColor.COLOR_CHAR, startAt); - if (next == -1) { - return -1; - } - if (next + endSymbol.length() >= base.length()) { - return -1; - } - if (base.startsWith(startSymbol, next + 1)) { - layers++; - } - else if (base.startsWith(endSymbol, next + 1)) { - layers--; - if (layers == 0) { - return next; - } - } - startAt = next + 1; - } - } - - public static int findEndIndexFor(String base, String type, int startAt) { - return findEndIndexFor(base, "[" + type + "=", "[/" + type + "]", startAt); - } - - public static String HEX = "0123456789abcdefABCDEF"; - - public static AsciiMatcher allowedCharCodes = new AsciiMatcher(HEX + "klmnorxKLMNORX["); - - public static AsciiMatcher hexMatcher = new AsciiMatcher(HEX); - - public static AsciiMatcher colorCodesOrReset = new AsciiMatcher(HEX + "rR"); // Any color code that can be invalidated - - public static AsciiMatcher colorCodeInvalidator = new AsciiMatcher(HEX + "rRxX"); // Any code that can invalidate the colors above - - public static String cleanRedundantCodes(String str) { - int index = str.indexOf(ChatColor.COLOR_CHAR); - if (index == -1) { - return str; - } - int start = 0; - StringBuilder output = new StringBuilder(str.length()); - while (index != -1) { - output.append(str, start, index); - start = index; - if (index + 1 >= str.length()) { - break; - } - char symbol = str.charAt(index + 1); - if (allowedCharCodes.isMatch(symbol)) { - if (symbol == 'x' || symbol == 'X') { // Skip entire hex block - index = str.indexOf(ChatColor.COLOR_CHAR, index + 14); - continue; - } - int nextIndex = str.indexOf(ChatColor.COLOR_CHAR, index + 1); - if (colorCodesOrReset.isMatch(symbol) && nextIndex == index + 2 && nextIndex + 1 < str.length()) { - char nextSymbol = str.charAt(nextIndex + 1); - if (colorCodeInvalidator.isMatch(nextSymbol)) { - start = index + 2; // Exclude from output the initial (redundant) color code - index = nextIndex; - continue; - } - } - } - index = str.indexOf(ChatColor.COLOR_CHAR, index + 1); - } - output.append(str, start, str.length()); - return output.toString(); - } - - public static TextComponent getCleanRef() { - TextComponent reference = new TextComponent(); - reference.setBold(false); - reference.setItalic(false); - reference.setStrikethrough(false); - reference.setUnderlined(false); - reference.setObfuscated(false); - return reference; - } - - public static BaseComponent[] parseSimpleColorsOnly(String str) { - TextComponent root = new TextComponent(); - int firstChar = str.indexOf(ChatColor.COLOR_CHAR); - int lastStart = 0; - if (firstChar > 0) { - root.addExtra(new TextComponent(str.substring(0, firstChar))); - lastStart = firstChar; - } - TextComponent nextText = new TextComponent(); - while (firstChar != -1 && firstChar + 1 < str.length()) { - char c = str.charAt(firstChar + 1); - if (allowedCharCodes.isMatch(c)) { - if (c == 'r' || c == 'R') { - nextText.setText(str.substring(lastStart, firstChar)); - if (!nextText.getText().isEmpty()) { - root.addExtra(nextText); - } - nextText = getCleanRef(); - lastStart = firstChar + 2; - } - else if (c == 'X' || c == 'x' && firstChar + 13 < str.length()) { - StringBuilder color = new StringBuilder(12); - color.append("#"); - for (int i = 1; i <= 6; i++) { - if (str.charAt(firstChar + i * 2) != ChatColor.COLOR_CHAR) { - color = null; - break; - } - char hexChar = str.charAt(firstChar + 1 + i * 2); - if (!hexMatcher.isMatch(hexChar)) { - color = null; - break; - } - color.append(hexChar); - } - if (color != null) { - nextText.setText(str.substring(lastStart, firstChar)); - if (!nextText.getText().isEmpty()) { - root.addExtra(nextText); - } - nextText = getCleanRef(); - nextText.setColor(ChatColor.of(CoreUtilities.toUpperCase(color.toString()))); - firstChar += 12; - lastStart = firstChar + 2; - } - } - else if (colorCodesOrReset.isMatch(c)) { - nextText.setText(str.substring(lastStart, firstChar)); - if (!nextText.getText().isEmpty()) { - root.addExtra(nextText); - } - nextText = getCleanRef(); - nextText.setColor(ChatColor.getByChar(c)); - lastStart = firstChar + 2; - } - else { // format code - nextText.setText(str.substring(lastStart, firstChar)); - if (!nextText.getText().isEmpty()) { - root.addExtra(nextText); - } - nextText = copyFormatToNewText(nextText, false); - if (c == 'k' || c == 'K') { - nextText.setObfuscated(true); - } - else if (c == 'l' || c == 'L') { - nextText.setBold(true); - } - else if (c == 'm' || c == 'M') { - nextText.setStrikethrough(true); - } - else if (c == 'n' || c == 'N') { - nextText.setUnderlined(true); - } - else if (c == 'o' || c == 'O') { - nextText.setItalic(true); - } - lastStart = firstChar + 2; - } - } - firstChar = str.indexOf(ChatColor.COLOR_CHAR, firstChar + 1); - } - if (lastStart < str.length()) { - nextText.setText(str.substring(lastStart)); - root.addExtra(nextText); - } - return new BaseComponent[] { root }; - } - - public static BaseComponent[] parse(String str, ChatColor baseColor, boolean cleanBase) { - if (str == null) { - return null; - } - try { - return parseInternal(str, baseColor, cleanBase, false); - } - catch (Throwable ex) { - Debug.echoError(ex); - } - return new BaseComponent[]{new TextComponent(str)}; - } - - private static BaseComponent parseTranslatable(String str, ChatColor baseColor, boolean optimize) { - if (!str.startsWith("map@")) { - List innardParts = CoreUtilities.split(str, ';'); - TranslatableComponent component = new TranslatableComponent(unescape(innardParts.get(0))); - for (int i = 1; i < innardParts.size(); i++) { - for (BaseComponent subComponent : parseInternal(unescape(innardParts.get(i)), baseColor, false, optimize)) { - component.addWith(subComponent); - } - } - return component; - } - MapTag map = MapTag.valueOf(unescape(str), CoreUtilities.noDebugContext); - if (map == null) { - return new TextComponent(str); - } - ElementTag translationKey = map.getElement("key"); - if (translationKey == null) { - return new TextComponent(str); - } - TranslatableComponent component = new TranslatableComponent(translationKey.asString()); - ElementTag fallback = map.getElement("fallback"); - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && fallback != null) { - component.setFallback(fallback.asString()); - } - ListTag withList = map.getObjectAs("with", ListTag.class, CoreUtilities.noDebugContext); - if (withList != null) { - for (String with : withList) { - for (BaseComponent withComponent : parseInternal(with, baseColor, false, optimize)) { - component.addWith(withComponent); - } - } - } - return component; - } - - public static BaseComponent[] parseInternal(String str, ChatColor baseColor, boolean cleanBase, boolean optimize) { - str = CoreUtilities.clearNBSPs(str); - int firstChar = str.indexOf(ChatColor.COLOR_CHAR); - if (firstChar == -1) { - if (str.contains("://")) { - firstChar = 0; - } - else { - TextComponent base = new TextComponent(); - base.addExtra(new TextComponent(str)); // This is for compat with how Spigot does parsing of plaintext. - return new BaseComponent[]{base}; - } - } - str = cleanRedundantCodes(str); - if (cleanBase && str.length() < 512) { - if (!str.contains(ChatColor.COLOR_CHAR + "[") && !str.contains("://")) { - return parseSimpleColorsOnly(str); - } - // Ensure compat with certain weird vanilla translate strings. - if (str.startsWith(ChatColor.COLOR_CHAR + "[translate=") && str.indexOf(']') == str.length() - 1) { - return new BaseComponent[] {parseTranslatable(str.substring("&[translate=".length(), str.length() - 1), baseColor, optimize)}; - } - if (str.length() > 3 && str.startsWith((ChatColor.COLOR_CHAR + "")) && hexMatcher.isMatch(str.charAt(1)) - && str.startsWith(ChatColor.COLOR_CHAR + "[translate=", 2) && str.indexOf(']') == str.length() - 1) { // eg "&6&[translate=block.minecraft.ominous_banner]" - BaseComponent component = parseTranslatable(str.substring("&[translate=".length() + 2, str.length() - 1), baseColor, optimize); - component.setColor(ChatColor.getByChar(str.charAt(1))); - return new BaseComponent[] {component}; - } - } - if (!optimize) { - optimize = str.contains(ChatColor.COLOR_CHAR + "[optimize=true]"); - } - TextComponent root = new TextComponent(); - TextComponent base = new TextComponent(); - if (cleanBase && !optimize) { - base.setBold(false); - base.setItalic(false); - base.setStrikethrough(false); - base.setUnderlined(false); - base.setObfuscated(false); - base.setColor(baseColor); - if (firstChar > 0) { - root.addExtra(new TextComponent(str.substring(0, firstChar))); - } - } - else { - base.setText(str.substring(0, firstChar)); - } - root.addExtra(base); - str = str.substring(firstChar); - char[] chars = str.toCharArray(); - int started = 0; - TextComponent nextText = new TextComponent(); - TextComponent lastText; - for (int i = 0; i < chars.length; i++) { - if (chars[i] == ChatColor.COLOR_CHAR && i + 1 < chars.length) { - char code = chars[i + 1]; - if (!allowedCharCodes.isMatch(code)) { - continue; - } - if (code == '[') { - int endBracket = str.indexOf(']', i + 2); - if (endBracket == -1) { - continue; - } - String innards = str.substring(i + 2, endBracket); - List innardParts = CoreUtilities.split(innards, ';'); - List innardBase = CoreUtilities.split(innardParts.get(0), '=', 2); - innardParts.remove(0); - String innardType = CoreUtilities.toLowerCase(innardBase.get(0)); - if (innardBase.size() == 2) { - nextText.setText(nextText.getText() + str.substring(started, i)); - base.addExtra(nextText); - lastText = nextText; - nextText = copyFormatToNewText(lastText, optimize); - nextText.setText(""); - if (innardType.equals("score") && innardParts.size() == 2) { - ScoreComponent component = new ScoreComponent(unescape(innardBase.get(1)), unescape(innardParts.get(0)), unescape(innardParts.get(1))); - lastText.addExtra(component); - } - else if (innardType.equals("keybind") && Utilities.matchesNamespacedKeyButCaseInsensitive(innardBase.get(1))) { - KeybindComponent component = new KeybindComponent(); - component.setKeybind(unescape(innardBase.get(1))); - lastText.addExtra(component); - } - else if (innardType.equals("selector")) { - SelectorComponent component = new SelectorComponent(unescape(innardBase.get(1))); - lastText.addExtra(component); - } - else if (innardType.equals("translate")) { - lastText.addExtra(parseTranslatable(innards.substring("translate=".length()), baseColor, optimize)); - } - else if (innardType.equals("click") && innardParts.size() == 1) { - int endIndex = findEndIndexFor(str, "click", endBracket); - if (endIndex == -1) { - continue; - } - TextComponent clickableText = new TextComponent(); - ClickEvent.Action action = ElementTag.asEnum(ClickEvent.Action.class, innardBase.get(1)); - clickableText.setClickEvent(new ClickEvent(action == null ? ClickEvent.Action.SUGGEST_COMMAND : action, unescape(innardParts.get(0)))); - for (BaseComponent subComponent : parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)) { - clickableText.addExtra(subComponent); - } - lastText.addExtra(clickableText); - endBracket = endIndex + "&[/click".length(); - } - else if (innardType.equals("hover")) { - int endIndex = findEndIndexFor(str, "hover", endBracket); - if (endIndex == -1) { - continue; - } - TextComponent hoverableText = new TextComponent(); - HoverEvent.Action action = ElementTag.asEnum(HoverEvent.Action.class, innardBase.get(1)); - if (HoverFormatHelper.processHoverInput(action == null ? HoverEvent.Action.SHOW_TEXT : action, hoverableText, innardParts.get(0))) { - continue; - } - for (BaseComponent subComponent : parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)) { - hoverableText.addExtra(subComponent); - } - lastText.addExtra(hoverableText); - endBracket = endIndex + "&[/hover".length(); - } - else if (innardType.equals("insertion")) { - int endIndex = str.indexOf(ChatColor.COLOR_CHAR + "[/insertion]", i); - int backupEndIndex = str.indexOf(ChatColor.COLOR_CHAR + "[insertion=", i + 5); - if (backupEndIndex > 0 && backupEndIndex < endIndex) { - endIndex = backupEndIndex; - } - if (endIndex == -1) { - continue; - } - TextComponent insertableText = new TextComponent(); - insertableText.setInsertion(unescape(innardBase.get(1))); - for (BaseComponent subComponent : parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)) { - insertableText.addExtra(subComponent); - } - lastText.addExtra(insertableText); - endBracket = endIndex + "&[/insertion".length(); - } - else if (innardType.equals("reset")) { - if (innardBase.get(1).length() == 1) { - char subCode = innardBase.get(1).charAt(0); - if (subCode == 'k' || subCode == 'K') { - nextText.setObfuscated(false); - } - else if (subCode == 'l' || subCode == 'L') { - nextText.setBold(false); - } - else if (subCode == 'm' || subCode == 'M') { - nextText.setStrikethrough(false); - } - else if (subCode == 'n' || subCode == 'N') { - nextText.setUnderlined(false); - } - else if (subCode == 'o' || subCode == 'O') { - nextText.setItalic(false); - } - } - else if (innardBase.get(1).equals("font")) { - nextText.setFont(base.getFont()); - } - else { - nextText.setColor(base.getColor()); - } - } - else if (innardType.equals("color")) { - String colorChar = innardBase.get(1); - ChatColor color = null; - if (colorChar.length() == 1) { - color = ChatColor.getByChar(colorChar.charAt(0)); - } - else if (colorChar.length() == 7) { - color = ChatColor.of(CoreUtilities.toUpperCase(colorChar)); - } - else if (CoreConfiguration.debugVerbose) { - Debug.echoError("Text parse issue: cannot interpret color '" + innardBase.get(1) + "'."); - } - if (color != null) { - int endIndex = findEndIndexFor(str, "[color=", "[reset=color]", endBracket); - if (endIndex == -1) { - nextText.setColor(color); - } - else { - TextComponent colorText = new TextComponent(); - colorText.setColor(color); - for (BaseComponent subComponent : parseInternal(str.substring(endBracket + 1, endIndex), color, false, optimize)) { - colorText.addExtra(subComponent); - } - lastText.addExtra(colorText); - endBracket = endIndex + "&[reset=color".length(); - } - } - } - else if (innardType.equals("gradient") && innardParts.size() == 2) { - String from = innardBase.get(1), to = innardParts.get(0), style = innardParts.get(1); - ColorTag fromColor = ColorTag.valueOf(from, CoreUtilities.noDebugContext); - ColorTag toColor = ColorTag.valueOf(to, CoreUtilities.noDebugContext); - BukkitElementExtensions.GradientStyle styleEnum = new ElementTag(style).asEnum(BukkitElementExtensions.GradientStyle.class); - if (fromColor == null || toColor == null || styleEnum == null) { - if (CoreConfiguration.debugVerbose) { - Debug.echoError("Text parse issue: cannot interpret gradient input '" + innards + "'."); - } - } - else { - int endIndex = findNextNormalColorSymbol(str, i + 1); - if (endIndex == -1) { - endIndex = str.length(); - } - String gradientText = BukkitElementExtensions.doGradient(str.substring(endBracket + 1, endIndex), fromColor, toColor, styleEnum); - for (BaseComponent subComponent : parseInternal(gradientText, baseColor, false, optimize)) { - lastText.addExtra(subComponent); - } - endBracket = endIndex - 1; - } - } - else if (innardType.equals("font") && Utilities.matchesNamespacedKey(innardBase.get(1))) { - int endIndex = findEndIndexFor(str, "[font=", "[reset=font]", endBracket); - if (endIndex == -1) { - nextText.setFont(innardBase.get(1)); - } - else { - TextComponent fontText = new TextComponent(); - fontText.setFont(innardBase.get(1)); - for (BaseComponent subComponent : parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)) { - fontText.addExtra(subComponent); - } - lastText.addExtra(fontText); - endBracket = endIndex + "&[reset=font".length(); - } - } - else if (innardType.equals("optimize")) { - // Ignore - } - else { - if (CoreConfiguration.debugVerbose) { - Debug.echoError("Text parse issue: cannot interpret type '" + innardType + "' with " + innardParts.size() + " parts."); - } - } - } - i = endBracket; - started = endBracket + 1; - continue; - } - else if (code == 'r' || code == 'R') { - nextText.setText(nextText.getText() + str.substring(started, i)); - if (!nextText.getText().isEmpty()) { - base.addExtra(nextText); - } - nextText = new TextComponent(); - nextText.setColor(baseColor); - } - else if (colorCodesOrReset.isMatch(code)) { - nextText.setText(nextText.getText() + str.substring(started, i)); - if (!nextText.getText().isEmpty()) { - base.addExtra(nextText); - } - nextText = new TextComponent(); - nextText.setColor(ChatColor.getByChar(code)); - } - else if (code == 'x') { - if (i + 13 >= chars.length) { - continue; - } - StringBuilder color = new StringBuilder(12); - color.append("#"); - for (int c = 1; c <= 6; c++) { - if (chars[i + c * 2] != ChatColor.COLOR_CHAR) { - color = null; - break; - } - char hexPart = chars[i + 1 + c * 2]; - if (!hexMatcher.isMatch(hexPart)) { - color = null; - break; - } - color.append(hexPart); - } - if (color == null) { - continue; - } - nextText.setText(nextText.getText() + str.substring(started, i)); - if (!nextText.getText().isEmpty()) { - base.addExtra(nextText); - } - nextText = new TextComponent(); - nextText.setColor(ChatColor.of(CoreUtilities.toUpperCase(color.toString()))); - i += 13; - started = i + 1; - continue; - } - else { - nextText.setText(nextText.getText() + str.substring(started, i)); - if (!nextText.getText().isEmpty()) { - base.addExtra(nextText); - } - nextText = copyFormatToNewText(nextText, optimize); - if (code == 'k' || code == 'K') { - nextText.setObfuscated(true); - } - else if (code == 'l' || code == 'L') { - nextText.setBold(true); - } - else if (code == 'm' || code == 'M') { - nextText.setStrikethrough(true); - } - else if (code == 'n' || code == 'N') { - nextText.setUnderlined(true); - } - else if (code == 'o' || code == 'O') { - nextText.setItalic(true); - } - } - i++; - started = i + 1; - } - else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { - String subStr = str.substring(i, i + "https://a.".length()); - if (subStr.startsWith("https://") || subStr.startsWith("http://")) { - int nextSpace = CoreUtilities.indexOfAny(str, i, ' ', '\t', '\n', ChatColor.COLOR_CHAR); - if (nextSpace == -1) { - nextSpace = str.length(); - } - String url = str.substring(i, nextSpace); - nextText.setText(nextText.getText() + str.substring(started, i)); - base.addExtra(nextText); - lastText = nextText; - nextText = new TextComponent(lastText); - nextText.setText(""); - TextComponent clickableText = new TextComponent(url); - clickableText.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); - lastText.addExtra(clickableText); - i = nextSpace - 1; - started = nextSpace; - continue; - } - } - } - nextText.setText(nextText.getText() + str.substring(started)); - if (!nextText.getText().isEmpty()) { - base.addExtra(nextText); - } - return new BaseComponent[] { cleanBase && !optimize ? root : base }; - } - - public static int indexOfLastColorBlockStart(String text) { - int result = text.lastIndexOf(ChatColor.COLOR_CHAR + "["); - if (result == -1 || text.indexOf(']', result + 2) != -1) { - return -1; - } - return result; - } - - /** - * Equivalent to DebugInternals.trimMessage, with a special check: - * If a message is cut in the middle of a format block like "&[font=x:y]", cut that block entirely out. - * (This is needed because a snip in the middle of this will explode with parsing errors). - */ - public static String bukkitSafeDebugTrimming(String message) { - int trimSize = CoreConfiguration.debugTrimLength; - if (message.length() > trimSize) { - int firstCut = (trimSize / 2) - 10, secondCut = message.length() - ((trimSize / 2) - 10); - String prePart = message.substring(0, firstCut); - String cutPart = message.substring(firstCut, secondCut); - String postPart = message.substring(secondCut); - int preEarlyCut = indexOfLastColorBlockStart(prePart); - if (preEarlyCut != -1) { - prePart = message.substring(0, preEarlyCut); - } - if (indexOfLastColorBlockStart(cutPart) != -1 || (preEarlyCut != -1 && cutPart.indexOf(']') == -1)) { - int lateCut = postPart.indexOf(']'); - if (lateCut != -1) { - postPart = postPart.substring(lateCut + 1); - } - } - message = prePart + "... *snip!*..." + postPart; - } - return message; - } - - public static Gson getBungeeGson() { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - return VersionedComponentSerializer.forVersion(ChatVersion.V1_21_5).getGson(); - } - else { - return ReflectionHelper.getFieldValue(ComponentSerializer.class, "gson", null); - } - } - - static { - // Explicitly before initializing vanillaStyleSpigotComponentGSON - HoverFormatHelper.tryInitializeItemHoverFix(); - } - - public static final Gson vanillaStyleSpigotComponentGSON = getBungeeGson().newBuilder().disableHtmlEscaping().create(); - - public static String componentToJson(BaseComponent[] components) { - if (components.length == 1) { - return vanillaStyleSpigotComponentGSON.toJson(components[0]); - } - return vanillaStyleSpigotComponentGSON.toJson(new TextComponent(components)); - } - - public static BaseComponent[] parseJson(String json) { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - return VersionedComponentSerializer.forVersion(ChatVersion.V1_21_5).parse(json); - } - return ComponentSerializer.parse(json); - } -} +package com.denizenscript.denizen.paper.utilities; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.paper.properties.PaperElementExtensions; +import com.denizenscript.denizen.utilities.Utilities; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.utilities.AsciiMatcher; +import com.denizenscript.denizencore.utilities.CoreConfiguration; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.*; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.*; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +public class FormattedTextHelper { + + // <--[language] + // @name Denizen Text Formatting + // @group Denizen Magic + // @description + // Denizen provides a variety of special chat format options like "on_hover" and "on_click". + // These options exist within Denizen and do not appear in the historical Minecraft legacy chat format that most plugins and systems read. + // That legacy system has 16 colors (0-9, A-F) and a few toggleable formats (bold, italic, etc). It does not contain anything that needs more than just an on/off. + // + // Modern Minecraft, however, supports a JSON based "raw" message format that can do click events, hover events, full RGB colors, etc. + // + // Denizen therefore has its own internal system that works like the legacy format system, but also supports the new options normally only available as 'raw JSON'. + // + // Because it is entirely processed within Denizen, these options only work within Denizen, when performing actions that support raw JSON input. + // This magic tool exists to let you write messages without having to write the messy JSON. + // + // Be aware that many inputs do not support raw JSON, and as such are limited only the historical Minecraft legacy format. + // Also be aware that click events, hover events, etc. are exclusively limited to the chat bar and the pages of books, as you cannot mouse over anything else. + // + // Also note that RGB colors use a format that Spigot invented, meaning they will work in places that use Spigot's parser OR Denizen's version, but nowhere that uses the vanilla format still. + // + // Thanks to Paper's implementation of component APIs where Spigot was too lazy to, Paper servers have advanced text formatting available in more areas. + // --> + + public static AsciiMatcher needsEscapeMatcher = new AsciiMatcher("&;[]"); + public static final char LEGACY_SECTION = LegacyComponentSerializer.SECTION_CHAR; + + public enum LegacyColor { + BLACK('0', NamedTextColor.BLACK), + DARK_BLUE('1', NamedTextColor.DARK_BLUE), + DARK_GREEN('2', NamedTextColor.DARK_GREEN), + DARK_AQUA('3', NamedTextColor.DARK_AQUA), + DARK_RED('4', NamedTextColor.DARK_RED), + DARK_PURPLE('5', NamedTextColor.DARK_PURPLE), + GOLD('6', NamedTextColor.GOLD), + GRAY('7', NamedTextColor.GRAY), + DARK_GRAY('8', NamedTextColor.DARK_GRAY), + BLUE('9', NamedTextColor.BLUE), + GREEN('a', NamedTextColor.GREEN), + AQUA('b', NamedTextColor.AQUA), + RED('c', NamedTextColor.RED), + LIGHT_PURPLE('d', NamedTextColor.LIGHT_PURPLE), + YELLOW('e', NamedTextColor.YELLOW), + WHITE('f', NamedTextColor.WHITE); + + public final char colorChar; + public final String colorString; + public final NamedTextColor color; + + LegacyColor(char colorChar, NamedTextColor color) { + this.colorChar = colorChar; + this.colorString = new String(new char[]{LEGACY_SECTION, colorChar}); + this.color = color; + } + + @Override + public String toString() { + return colorString; + } + + private static int calculateIndex(char colorChar) { + if (colorChar >= '0' && colorChar <= '9') { + return colorChar - '0'; + } + else if (colorChar >= 'a' && colorChar <= 'f') { + return colorChar - 'a' + 10; + } + else { + return -1; + } + } + + public static NamedTextColor fromChar(char colorChar) { + int index = calculateIndex(colorChar); + return index != -1 ? FROM_LEGACY[index].color : null; + } + + public static LegacyColor legacyFromChar(char colorChar) { + int index = calculateIndex(colorChar); + return index != -1 ? FROM_LEGACY[index] : null; + } + + public static LegacyColor fromModern(NamedTextColor textColor) { + return TO_LEGACY.get(textColor); + } + + private static final Map TO_LEGACY = new IdentityHashMap<>(16); + private static final LegacyColor[] FROM_LEGACY = new LegacyColor[16]; + + static { + for (LegacyColor legacyColor : values()) { + TO_LEGACY.put(legacyColor.color, legacyColor); + FROM_LEGACY[calculateIndex(legacyColor.colorChar)] = legacyColor; + } + } + } + + public enum LegacyFormatting { + BOLD('l'), + ITALIC('o'), + STRIKETHROUGH('m'), + UNDERLINE('n'), + OBFUSCATED('k'), + RESET('r'); + + public final String formatString; + + LegacyFormatting(char formatChar) { + this.formatString = new String(new char[]{LEGACY_SECTION, formatChar}); + } + + @Override + public String toString() { + return formatString; + } + } + + public static String escape(String input) { + if (needsEscapeMatcher.containsAnyMatch(input)) { + input = input.replace("&", "&").replace(";", "&sc").replace("[", "&lb").replace("]", "&rb").replace("\n", "&nl"); + } + return input.replace(String.valueOf(LEGACY_SECTION), "&ss"); + } + + public static String unescape(String input) { + if (input.indexOf('&') != -1) { + return input.replace("&sc", ";").replace("&lb", "[").replace("&rb", "]").replace("&nl", "\n").replace("&ss", String.valueOf(LEGACY_SECTION)).replace("&", "&"); + } + return input; + } + + public static boolean hasRootFormat(Component component) { + if (component == null) { + return false; + } + if (component.hasStyling()) { + return true; + } + if (!(component instanceof TextComponent textComponent)) { + return false; + } + if (!textComponent.content().isEmpty()) { + return false; + } + List children = component.children(); + if (children.isEmpty()) { + return false; + } + return hasRootFormat(children.get(0)); + } + + public static String stringify(Component component) { + if (component == null) { + return null; + } + String output = stringifySub(component); + if (hasRootFormat(component)) { + output = RESET + output; + } + while (output.endsWith(RESET)) { + output = output.substring(0, output.length() - RESET.length()); + } + while (output.startsWith(POSSIBLE_RESET_PREFIX) && output.length() > 4 && colorCodeInvalidator.isMatch(output.charAt(3))) { + output = output.substring(2); + } + return cleanRedundantCodes(output); + } + + public static String stringifyRGBSpigot(String hex) { + StringBuilder hexBuilder = new StringBuilder(7); + hexBuilder.append('x'); + for (int i = hex.length(); i < 6; i++) { + hexBuilder.append('0'); + } + hexBuilder.append(hex); + hex = hexBuilder.toString(); + StringBuilder outColor = new StringBuilder(); + for (char c : hex.toCharArray()) { + outColor.append(LEGACY_SECTION).append(c); + } + return outColor.toString(); + } + + public static String stringifySub(Component component) { + return stringifySub(component, null); + } + + public static String stringifySub(Component component, TextColor parentColor) { + if (component == null) { + return null; + } + StringBuilder builder = new StringBuilder(128); + TextColor color = component.color(); + if (color == null) { + color = parentColor; + } + if (color != null) { + if (color instanceof NamedTextColor namedTextColor) { + builder.append(LegacyColor.fromModern(namedTextColor)); + } + else { + builder.append(stringifyRGBSpigot(color.asHexString().substring(1))); + } + } + if (component.hasDecoration(TextDecoration.BOLD)) { + builder.append(LegacyFormatting.BOLD); + } + if (component.hasDecoration(TextDecoration.ITALIC)) { + builder.append(LegacyFormatting.ITALIC); + } + if (component.hasDecoration(TextDecoration.STRIKETHROUGH)) { + builder.append(LegacyFormatting.STRIKETHROUGH); + } + if (component.hasDecoration(TextDecoration.UNDERLINED)) { + builder.append(LegacyFormatting.UNDERLINE); + } + if (component.hasDecoration(TextDecoration.OBFUSCATED)) { + builder.append(LegacyFormatting.OBFUSCATED); + } + boolean hasFont = component.font() != null; + if (hasFont) { + builder.append(LEGACY_SECTION).append("[font=").append(component.font()).append("]"); + } + boolean hasInsertion = component.insertion() != null; + if (hasInsertion) { + builder.append(LEGACY_SECTION).append("[insertion=").append(escape(component.insertion())).append("]"); + } + boolean hasHover = component.hoverEvent() != null; + if (hasHover) { + HoverEvent hover = component.hoverEvent(); + String hoverString = HoverFormatHelper.stringForHover(hover); + if (hoverString != null) { + builder.append(LEGACY_SECTION).append("[hover=").append(hover.action()).append(";").append(escape(hoverString)).append("]"); + } + else { + hasHover = false; + } + } + boolean hasClick = component.clickEvent() != null; + if (hasClick) { + ClickEvent click = component.clickEvent(); + // TODO modern click events + builder.append(LEGACY_SECTION).append("[click=").append(click.action().name()).append(";").append(escape(click.value())).append("]"); + } + if (component instanceof TextComponent textComponent) { + builder.append(textComponent.content()); + } + else if (component instanceof TranslatableComponent translatableComponent) { + MapTag map = new MapTag(); + map.putObject("key", new ElementTag(translatableComponent.key(), true)); + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && translatableComponent.fallback() != null) { + map.putObject("fallback", new ElementTag(translatableComponent.fallback(), true)); + } + if (!translatableComponent.arguments().isEmpty()) { + map.putObject("with", new ListTag(translatableComponent.arguments(), argument -> new ElementTag(stringifySub(argument.asComponent()), true))); + } + builder.append(LEGACY_SECTION).append("[translate=").append(escape(map.savable())).append(']'); + } + else if (component instanceof SelectorComponent) { + // TODO separator + builder.append(LEGACY_SECTION).append("[selector=").append(escape(((SelectorComponent) component).pattern())).append("]"); + } + else if (component instanceof KeybindComponent) { + builder.append(LEGACY_SECTION).append("[keybind=").append(escape(((KeybindComponent) component).keybind())).append("]"); + } + else if (component instanceof ScoreComponent) { + // TODO value is deprecated + builder.append(LEGACY_SECTION).append("[score=").append(escape(((ScoreComponent) component).name())) + .append(";").append(escape(((ScoreComponent) component).objective())) + .append(";").append(escape(((ScoreComponent) component).value())).append("]"); + } + for (Component afterComponent : component.children()) { + builder.append(stringifySub(afterComponent, color)); + } + if (hasClick) { + builder.append(LEGACY_SECTION + "[/click]"); + } + if (hasHover) { + builder.append(LEGACY_SECTION + "[/hover]"); + } + if (hasInsertion) { + builder.append(LEGACY_SECTION + "[/insertion]"); + } + if (hasFont) { + builder.append(LEGACY_SECTION + "[reset=font]"); + } + builder.append(RESET); + String output = builder.toString(); + return cleanRedundantCodes(output); + } + + public static final String RESET = LegacyFormatting.RESET.toString(), POSSIBLE_RESET_PREFIX = RESET + LEGACY_SECTION; + + private static void copyDecoration(TextDecoration decoration, StyleGetter origin, StyleSetter destination, boolean optimize) { + TextDecoration.State state = origin.decoration(decoration); + if (state == TextDecoration.State.NOT_SET) { + return; + } + if (optimize && state == TextDecoration.State.FALSE) { + return; + } + destination.decoration(decoration, state); + } + + public static TextComponent.Builder copyFormatToNewText(TextComponent.Builder last, boolean minimize) { + TextComponent.Builder toRet = Component.text(); + Component lastBuilt = last.build(); + copyDecoration(TextDecoration.OBFUSCATED, lastBuilt, toRet, minimize); + copyDecoration(TextDecoration.BOLD, lastBuilt, toRet, minimize); + copyDecoration(TextDecoration.STRIKETHROUGH, lastBuilt, toRet, minimize); + copyDecoration(TextDecoration.UNDERLINED, lastBuilt, toRet, minimize); + copyDecoration(TextDecoration.ITALIC, lastBuilt, toRet, minimize); + toRet.color(lastBuilt.color()); + return toRet; + } + + public static Component parse(String str, TextColor baseColor) { + if (str == null) { + return null; + } + return parse(str, baseColor, true); + } + + public static int findNextNormalColorSymbol(String base, int startAt) { + while (true) { + int next = base.indexOf(LEGACY_SECTION, startAt); + if (next == -1 || next + 1 >= base.length()) { + return -1; + } + char after = base.charAt(next + 1); + if (colorCodeInvalidator.isMatch(after)) { + return next; + } + startAt = next + 1; + } + } + + public static int findEndIndexFor(String base, String startSymbol, String endSymbol, int startAt) { + int layers = 1; + while (true) { + int next = base.indexOf(LEGACY_SECTION, startAt); + if (next == -1) { + return -1; + } + if (next + endSymbol.length() >= base.length()) { + return -1; + } + if (base.startsWith(startSymbol, next + 1)) { + layers++; + } + else if (base.startsWith(endSymbol, next + 1)) { + layers--; + if (layers == 0) { + return next; + } + } + startAt = next + 1; + } + } + + public static int findEndIndexFor(String base, String type, int startAt) { + return findEndIndexFor(base, "[" + type + "=", "[/" + type + "]", startAt); + } + + public static String HEX = "0123456789abcdefABCDEF"; + + public static AsciiMatcher allowedCharCodes = new AsciiMatcher(HEX + "klmnorxKLMNORX["); + + public static AsciiMatcher hexMatcher = new AsciiMatcher(HEX); + + public static AsciiMatcher colorCodesOrReset = new AsciiMatcher(HEX + "rR"); // Any color code that can be invalidated + + public static AsciiMatcher colorCodeInvalidator = new AsciiMatcher(HEX + "rRxX"); // Any code that can invalidate the colors above + + public static String cleanRedundantCodes(String str) { + int index = str.indexOf(LEGACY_SECTION); + if (index == -1) { + return str; + } + int start = 0; + StringBuilder output = new StringBuilder(str.length()); + while (index != -1) { + output.append(str, start, index); + start = index; + if (index + 1 >= str.length()) { + break; + } + char symbol = str.charAt(index + 1); + if (allowedCharCodes.isMatch(symbol)) { + if (symbol == 'x' || symbol == 'X') { // Skip entire hex block + index = str.indexOf(LEGACY_SECTION, index + 14); + continue; + } + int nextIndex = str.indexOf(LEGACY_SECTION, index + 1); + if (colorCodesOrReset.isMatch(symbol) && nextIndex == index + 2 && nextIndex + 1 < str.length()) { + char nextSymbol = str.charAt(nextIndex + 1); + if (colorCodeInvalidator.isMatch(nextSymbol)) { + start = index + 2; // Exclude from output the initial (redundant) color code + index = nextIndex; + continue; + } + } + } + index = str.indexOf(LEGACY_SECTION, index + 1); + } + output.append(str, start, str.length()); + return output.toString(); + } + + public static final Style CLEAN_BASE_STYLE = Style.style() + .decoration(TextDecoration.BOLD, false) + .decoration(TextDecoration.ITALIC, false) + .decoration(TextDecoration.STRIKETHROUGH, false) + .decoration(TextDecoration.UNDERLINED, false) + .decoration(TextDecoration.OBFUSCATED, false) + .build(); + + public static TextComponent.Builder getCleanRef() { + return Component.text().style(CLEAN_BASE_STYLE); + } + + public static Component parseSimpleColorsOnly(String str) { + TextComponent.Builder root = Component.text(); + int firstChar = str.indexOf(LEGACY_SECTION); + int lastStart = 0; + if (firstChar > 0) { + root.append(Component.text(str.substring(0, firstChar))); + lastStart = firstChar; + } + TextComponent.Builder nextText = Component.text(); + while (firstChar != -1 && firstChar + 1 < str.length()) { + char c = str.charAt(firstChar + 1); + if (allowedCharCodes.isMatch(c)) { + if (c == 'r' || c == 'R') { + nextText.content(str.substring(lastStart, firstChar)); + if (!nextText.content().isEmpty()) { + root.append(nextText); + } + nextText = getCleanRef(); + lastStart = firstChar + 2; + } + else if (c == 'X' || c == 'x' && firstChar + 13 < str.length()) { + StringBuilder color = new StringBuilder(12); + color.append("#"); + for (int i = 1; i <= 6; i++) { + if (str.charAt(firstChar + i * 2) != LEGACY_SECTION) { + color = null; + break; + } + char hexChar = str.charAt(firstChar + 1 + i * 2); + if (!hexMatcher.isMatch(hexChar)) { + color = null; + break; + } + color.append(hexChar); + } + if (color != null) { + nextText.content(str.substring(lastStart, firstChar)); + if (!nextText.content().isEmpty()) { + root.append(nextText); + } + nextText = getCleanRef(); + nextText.color(TextColor.fromHexString(CoreUtilities.toUpperCase(color.toString()))); + firstChar += 12; + lastStart = firstChar + 2; + } + } + else if (colorCodesOrReset.isMatch(c)) { + nextText.content(str.substring(lastStart, firstChar)); + if (!nextText.content().isEmpty()) { + root.append(nextText); + } + nextText = getCleanRef(); + nextText.color(LegacyColor.fromChar(c)); + lastStart = firstChar + 2; + } + else { // format code + nextText.content(str.substring(lastStart, firstChar)); + if (!nextText.content().isEmpty()) { + root.append(nextText); + } + nextText = copyFormatToNewText(nextText, false); + if (c == 'k' || c == 'K') { + nextText.decoration(TextDecoration.OBFUSCATED, true); + } + else if (c == 'l' || c == 'L') { + nextText.decoration(TextDecoration.BOLD, true); + } + else if (c == 'm' || c == 'M') { + nextText.decoration(TextDecoration.STRIKETHROUGH, true); + } + else if (c == 'n' || c == 'N') { + nextText.decoration(TextDecoration.UNDERLINED, true); + } + else if (c == 'o' || c == 'O') { + nextText.decoration(TextDecoration.ITALIC, true); + } + lastStart = firstChar + 2; + } + } + firstChar = str.indexOf(LEGACY_SECTION, firstChar + 1); + } + if (lastStart < str.length()) { + nextText.content(str.substring(lastStart)); + root.append(nextText); + } + return root.build(); + } + + public static Component parse(String str, TextColor baseColor, boolean cleanBase) { + if (str == null) { + return null; + } + try { + return parseInternal(str, baseColor, cleanBase, false); + } + catch (Throwable ex) { + Debug.echoError(ex); + } + return Component.text(str); + } + + // TODO cleanup handling here? + private static Component parseTranslatable(String str, TextColor baseColor, boolean optimize) { + if (!str.startsWith("map@")) { + List innardParts = CoreUtilities.split(str, ';'); + String translation = unescape(innardParts.get(0)); + if (innardParts.size() == 1) { + return Component.translatable(translation); + } + List args = new ArrayList<>(innardParts.size() - 1); + for (int i = 1; i < innardParts.size(); i++) { + args.add(parseInternal(unescape(innardParts.get(i)), baseColor, false, optimize)); + } + return Component.translatable(translation, args); + } + MapTag map = MapTag.valueOf(unescape(str), CoreUtilities.noDebugContext); + if (map == null) { + return Component.text(str); + } + ElementTag translationKey = map.getElement("key"); + if (translationKey == null) { + return Component.text(str); + } + ListTag withList = map.getObjectAs("with", ListTag.class, CoreUtilities.noDebugContext); + List args; + if (withList != null) { + args = new ArrayList<>(withList.size()); + for (String with : withList) { + args.add(parseInternal(with, baseColor, false, optimize)); + } + } + else { + args = List.of(); + } + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19)) { + return Component.translatable(translationKey.asString(), args); + } + ElementTag fallback = map.getElement("fallback"); + return Component.translatable(translationKey.asString(), fallback != null ? fallback.asString() : null, args, List.of()); + } + + public static Component parseInternal(String str, TextColor baseColor, boolean cleanBase, boolean optimize) { + str = CoreUtilities.clearNBSPs(str); + int firstChar = str.indexOf(LEGACY_SECTION); + if (firstChar == -1) { + if (str.contains("://")) { + firstChar = 0; + } + else { + // This is for compact with how Spigot does parsing of plaintext. + return Component.textOfChildren(Component.text(str)); + } + } + str = cleanRedundantCodes(str); + if (cleanBase && str.length() < 512) { + if (!str.contains(LEGACY_SECTION + "[") && !str.contains("://")) { + return parseSimpleColorsOnly(str); + } + // Ensure compact with certain weird vanilla translate strings. + if (str.startsWith(LEGACY_SECTION + "[translate=") && str.indexOf(']') == str.length() - 1) { + return parseTranslatable(str.substring("&[translate=".length(), str.length() - 1), baseColor, optimize); + } + if (str.length() > 3 && str.startsWith(LEGACY_SECTION + "") && hexMatcher.isMatch(str.charAt(1)) + && str.startsWith(LEGACY_SECTION + "[translate=", 2) && str.indexOf(']') == str.length() - 1) { // eg "&6&[translate=block.minecraft.ominous_banner]" + Component component = parseTranslatable(str.substring("&[translate=".length() + 2, str.length() - 1), baseColor, optimize); + return component.color(LegacyColor.fromChar(str.charAt(1))); + } + } + if (!optimize) { + optimize = str.contains(LEGACY_SECTION + "[optimize=true]"); + } + TextComponent.Builder root = Component.text(); + TextComponent.Builder base; + if (cleanBase && !optimize) { + base = getCleanRef(); + base.color(baseColor); + if (firstChar > 0) { + root.append(Component.text(str.substring(0, firstChar))); + } + } + else { + base = Component.text(); + base.content(str.substring(0, firstChar)); + } + str = str.substring(firstChar); + char[] chars = str.toCharArray(); + int started = 0; + TextComponent.Builder nextText = Component.text(); + TextComponent.Builder lastText; + for (int i = 0; i < chars.length; i++) { + if (chars[i] == LEGACY_SECTION && i + 1 < chars.length) { + char code = chars[i + 1]; + if (!allowedCharCodes.isMatch(code)) { + continue; + } + if (code == '[') { + int endBracket = str.indexOf(']', i + 2); + if (endBracket == -1) { + continue; + } + String innards = str.substring(i + 2, endBracket); + List innardParts = CoreUtilities.split(innards, ';'); + List innardBase = CoreUtilities.split(innardParts.get(0), '=', 2); + innardParts.remove(0); + String innardType = CoreUtilities.toLowerCase(innardBase.get(0)); + if (innardBase.size() == 2) { + nextText.content(nextText.content() + str.substring(started, i)); + lastText = nextText; + nextText = copyFormatToNewText(lastText, optimize); + nextText.content(""); + if (innardType.equals("score") && innardParts.size() == 2) { + // TODO value is no longer a thing? + ScoreComponent component = Component.score(unescape(innardBase.get(1)), unescape(innardParts.get(0)), unescape(innardParts.get(1))); + lastText.append(component); + } + else if (innardType.equals("keybind") && Utilities.matchesNamespacedKeyButCaseInsensitive(innardBase.get(1))) { + KeybindComponent component = Component.keybind(unescape(innardBase.get(1))); + lastText.append(component); + } + else if (innardType.equals("selector")) { + SelectorComponent component = Component.selector(unescape(innardBase.get(1))); + lastText.append(component); + } + else if (innardType.equals("translate")) { + lastText.append(parseTranslatable(innards.substring("translate=".length()), baseColor, optimize)); + } + else if (innardType.equals("click") && innardParts.size() == 1) { + int endIndex = findEndIndexFor(str, "click", endBracket); + if (endIndex == -1) { + continue; + } + TextComponent.Builder clickableText = Component.text(); + ClickEvent.Action action = ElementTag.asEnum(ClickEvent.Action.class, innardBase.get(1)); + // TODO click event types + clickableText.clickEvent(ClickEvent.clickEvent(action == null ? ClickEvent.Action.SUGGEST_COMMAND : action, unescape(innardParts.get(0)))); + clickableText.append(parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)); + lastText.append(clickableText); + endBracket = endIndex + "&[/click".length(); + } + else if (innardType.equals("hover")) { + int endIndex = findEndIndexFor(str, "hover", endBracket); + if (endIndex == -1) { + continue; + } + TextComponent.Builder hoverableText = Component.text(); + HoverEvent.Action action = ElementTag.asEnum(HoverEvent.Action.class, innardBase.get(1)); + if (HoverFormatHelper.processHoverInput(action == null ? HoverEvent.Action.SHOW_TEXT : action, hoverableText, innardParts.get(0))) { + continue; + } + hoverableText.append(parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)); + lastText.append(hoverableText); + endBracket = endIndex + "&[/hover".length(); + } + else if (innardType.equals("insertion")) { + int endIndex = str.indexOf(LEGACY_SECTION + "[/insertion]", i); + int backupEndIndex = str.indexOf(LEGACY_SECTION + "[insertion=", i + 5); + if (backupEndIndex > 0 && backupEndIndex < endIndex) { + endIndex = backupEndIndex; + } + if (endIndex == -1) { + continue; + } + TextComponent.Builder insertableText = Component.text(); + insertableText.insertion(unescape(innardBase.get(1))); + insertableText.append(parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)); + lastText.append(insertableText); + endBracket = endIndex + "&[/insertion".length(); + } + else if (innardType.equals("reset")) { + if (innardBase.get(1).length() == 1) { + char subCode = innardBase.get(1).charAt(0); + if (subCode == 'k' || subCode == 'K') { + nextText.decoration(TextDecoration.OBFUSCATED, false); + } + else if (subCode == 'l' || subCode == 'L') { + nextText.decoration(TextDecoration.BOLD, false); + } + else if (subCode == 'm' || subCode == 'M') { + nextText.decoration(TextDecoration.STRIKETHROUGH, false); + } + else if (subCode == 'n' || subCode == 'N') { + nextText.decoration(TextDecoration.UNDERLINED, false); + } + else if (subCode == 'o' || subCode == 'O') { + nextText.decoration(TextDecoration.ITALIC, false); + } + } + else if (innardBase.get(1).equals("font")) { + // TODO builder + nextText.font(base.build().font()); + } + else { + // TODO builder + nextText.color(base.build().color()); + } + } + else if (innardType.equals("color")) { + String colorChar = innardBase.get(1); + TextColor color = null; + if (colorChar.length() == 1) { + color = LegacyColor.fromChar(colorChar.charAt(0)); + } + else if (colorChar.length() == 7) { + color = TextColor.fromHexString(CoreUtilities.toUpperCase(colorChar)); + } + else if (CoreConfiguration.debugVerbose) { + Debug.echoError("Text parse issue: cannot interpret color '" + innardBase.get(1) + "'."); + } + if (color != null) { + int endIndex = findEndIndexFor(str, "[color=", "[reset=color]", endBracket); + if (endIndex == -1) { + nextText.color(color); + } + else { + TextComponent.Builder colorText = Component.text(); + colorText.color(color); + colorText.append(parseInternal(str.substring(endBracket + 1, endIndex), color, false, optimize)); + lastText.append(colorText); + endBracket = endIndex + "&[reset=color".length(); + } + } + } + else if (innardType.equals("gradient") && innardParts.size() == 2) { + String from = innardBase.get(1), to = innardParts.get(0), style = innardParts.get(1); + ColorTag fromColor = ColorTag.valueOf(from, CoreUtilities.noDebugContext); + ColorTag toColor = ColorTag.valueOf(to, CoreUtilities.noDebugContext); + PaperElementExtensions.GradientStyle styleEnum = new ElementTag(style).asEnum(PaperElementExtensions.GradientStyle.class); + if (fromColor == null || toColor == null || styleEnum == null) { + if (CoreConfiguration.debugVerbose) { + Debug.echoError("Text parse issue: cannot interpret gradient input '" + innards + "'."); + } + } + else { + int endIndex = findNextNormalColorSymbol(str, i + 1); + if (endIndex == -1) { + endIndex = str.length(); + } + String gradientText = PaperElementExtensions.doGradient(str.substring(endBracket + 1, endIndex), fromColor, toColor, styleEnum); + lastText.append(parseInternal(gradientText, baseColor, false, optimize)); + endBracket = endIndex - 1; + } + } + else if (innardType.equals("font") && Utilities.matchesNamespacedKey(innardBase.get(1))) { + int endIndex = findEndIndexFor(str, "[font=", "[reset=font]", endBracket); + if (endIndex == -1) { + nextText.font(Key.key(innardBase.get(1))); + } + else { + TextComponent.Builder fontText = Component.text(); + fontText.font(Key.key(innardBase.get(1))); + fontText.append(parseInternal(str.substring(endBracket + 1, endIndex), baseColor, false, optimize)); + lastText.append(fontText); + endBracket = endIndex + "&[reset=font".length(); + } + } + else if (innardType.equals("optimize")) { + // Ignore + } + else { + if (CoreConfiguration.debugVerbose) { + Debug.echoError("Text parse issue: cannot interpret type '" + innardType + "' with " + innardParts.size() + " parts."); + } + } + base.append(lastText); + } + i = endBracket; + started = endBracket + 1; + continue; + } + else if (code == 'r' || code == 'R') { + nextText.content(nextText.content() + str.substring(started, i)); + if (!nextText.content().isEmpty()) { + base.append(nextText); + } + nextText = Component.text(); + nextText.color(baseColor); + } + else if (colorCodesOrReset.isMatch(code)) { + nextText.content(nextText.content() + str.substring(started, i)); + if (!nextText.content().isEmpty()) { + base.append(nextText); + } + nextText = Component.text(); + nextText.color(LegacyColor.fromChar(code)); + } + else if (code == 'x') { + if (i + 13 >= chars.length) { + continue; + } + StringBuilder color = new StringBuilder(12); + color.append("#"); + for (int c = 1; c <= 6; c++) { + if (chars[i + c * 2] != LEGACY_SECTION) { + color = null; + break; + } + char hexPart = chars[i + 1 + c * 2]; + if (!hexMatcher.isMatch(hexPart)) { + color = null; + break; + } + color.append(hexPart); + } + if (color == null) { + continue; + } + nextText.content(nextText.content() + str.substring(started, i)); + if (!nextText.content().isEmpty()) { + base.append(nextText); + } + nextText = Component.text(); + nextText.color(TextColor.fromHexString(CoreUtilities.toUpperCase(color.toString()))); + i += 13; + started = i + 1; + continue; + } + else { + nextText.content(nextText.content() + str.substring(started, i)); + if (!nextText.content().isEmpty()) { + base.append(nextText); + } + nextText = copyFormatToNewText(nextText, optimize); + if (code == 'k' || code == 'K') { + nextText.decoration(TextDecoration.OBFUSCATED, true); + } + else if (code == 'l' || code == 'L') { + nextText.decoration(TextDecoration.BOLD, true); + } + else if (code == 'm' || code == 'M') { + nextText.decoration(TextDecoration.STRIKETHROUGH, true); + } + else if (code == 'n' || code == 'N') { + nextText.decoration(TextDecoration.UNDERLINED, true); + } + else if (code == 'o' || code == 'O') { + nextText.decoration(TextDecoration.ITALIC, true); + } + } + i++; + started = i + 1; + } + else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { + String subStr = str.substring(i, i + "https://a.".length()); + if (subStr.startsWith("https://") || subStr.startsWith("http://")) { + int nextSpace = CoreUtilities.indexOfAny(str, i, ' ', '\t', '\n', LEGACY_SECTION); + if (nextSpace == -1) { + nextSpace = str.length(); + } + String url = str.substring(i, nextSpace); + nextText.content(nextText.content() + str.substring(started, i)); + lastText = nextText; + // TODO builder copying + nextText = lastText.build().toBuilder(); + nextText.content(""); + TextComponent.Builder clickableText = Component.text().content(url); + clickableText.clickEvent(ClickEvent.openUrl(url)); + lastText.append(clickableText); + base.append(lastText); + i = nextSpace - 1; + started = nextSpace; + continue; + } + } + } + nextText.content(nextText.content() + str.substring(started)); + if (!nextText.content().isEmpty()) { + base.append(nextText); + } + return cleanBase && !optimize ? root.append(base).build() : base.build(); + } + + public static int indexOfLastColorBlockStart(String text) { + int result = text.lastIndexOf(LEGACY_SECTION + "["); + if (result == -1 || text.indexOf(']', result + 2) != -1) { + return -1; + } + return result; + } + + /** + * Equivalent to DebugInternals.trimMessage, with a special check: + * If a message is cut in the middle of a format block like "&[font=x:y]", cut that block entirely out. + * (This is needed because a snip in the middle of this will explode with parsing errors). + */ + public static String bukkitSafeDebugTrimming(String message) { + int trimSize = CoreConfiguration.debugTrimLength; + if (message.length() > trimSize) { + int firstCut = (trimSize / 2) - 10, secondCut = message.length() - ((trimSize / 2) - 10); + String prePart = message.substring(0, firstCut); + String cutPart = message.substring(firstCut, secondCut); + String postPart = message.substring(secondCut); + int preEarlyCut = indexOfLastColorBlockStart(prePart); + if (preEarlyCut != -1) { + prePart = message.substring(0, preEarlyCut); + } + if (indexOfLastColorBlockStart(cutPart) != -1 || (preEarlyCut != -1 && cutPart.indexOf(']') == -1)) { + int lateCut = postPart.indexOf(']'); + if (lateCut != -1) { + postPart = postPart.substring(lateCut + 1); + } + } + message = prePart + "... *snip!*..." + postPart; + } + return message; + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/HoverFormatHelper.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/HoverFormatHelper.java new file mode 100644 index 0000000000..04fa570d9a --- /dev/null +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/HoverFormatHelper.java @@ -0,0 +1,170 @@ +package com.denizenscript.denizen.paper.utilities; + +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.objects.EntityTag; +import com.denizenscript.denizen.objects.ItemTag; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.tags.Attribute; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.inventory.ItemStack; + +import java.lang.invoke.MethodHandle; +import java.util.Map; +import java.util.UUID; + +public class HoverFormatHelper { + + public static boolean processHoverInput(HoverEvent.Action action, TextComponent.Builder hoverableText, String input) { + HoverEventSource content; + if (action == HoverEvent.Action.SHOW_ITEM) { + ItemTag item = ItemTag.valueOf(FormattedTextHelper.unescape(input), CoreUtilities.noDebugContext); + if (item == null) { + return true; + } + content = item.getItemStack(); + } + else if (action == HoverEvent.Action.SHOW_ENTITY) { + String rawInput = FormattedTextHelper.unescape(input); + if (!rawInput.startsWith("map@")) { + content = parseLegacyEntityHover(rawInput); + if (content == null) { + return true; + } + } + else { + MapTag entityHoverData = MapTag.valueOf(rawInput, CoreUtilities.noDebugContext); + if (entityHoverData == null) { + return true; + } + ElementTag uuidElement = entityHoverData.getElement("uuid"); + if (uuidElement == null) { + return true; + } + UUID uuid = CoreUtilities.tryParseUUID(uuidElement.asString()); + if (uuid == null) { + return true; + } + ElementTag type = entityHoverData.getElement("type"); + if (type == null) { + return true; + } + ElementTag rawName = entityHoverData.getElement("name"); + Component name = rawName != null ? FormattedTextHelper.parse(rawName.asString(), NamedTextColor.WHITE) : null; + content = HoverEvent.showEntity(Key.key(type.asString()), uuid, name); + } + } + else { + content = FormattedTextHelper.parse(FormattedTextHelper.unescape(input), NamedTextColor.WHITE); + } + hoverableText.hoverEvent(content); + return false; + } + + public static final MethodHandle ADVENTURE_COMPONENTS_TO_NMS = NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) ? + ReflectionHelper.getMethodHandle( + ReflectionHelper.getClassOrThrow("io.papermc.paper.adventure.PaperAdventure"), "asVanilla", Map.class + ) : null; + + public static String stringForHover(HoverEvent hover) { + if (hover.value() instanceof Component textHover) { + return FormattedTextHelper.stringify(textHover); + } + else if (hover.value() instanceof HoverEvent.ShowItem itemHover) { + Material material = Registry.MATERIAL.get(new NamespacedKey(itemHover.item().namespace(), itemHover.item().value())); + if (material == null || !material.isItem()) { + Debug.echoError("Invalid hover item type '" + itemHover.item() + "', please report this to the developers! See the stacktrace below for more information:"); + Debug.echoError(new RuntimeException()); + return null; + } + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19)) { + ItemStack item = new ItemStack(material, itemHover.count()); + if (itemHover.nbt() != null) { + item = Bukkit.getUnsafe().modifyItemStack(item, itemHover.nbt().string()); + } + return new ItemTag(item).identify(); + } + if (itemHover.dataComponents().isEmpty()) { + return new ItemTag(material, itemHover.count()).identify(); + } + try { + Object nmsPatch = ADVENTURE_COMPONENTS_TO_NMS.invoke(itemHover.dataComponents()); + ItemStack item = NMSHandler.itemHelper.createItemWithNMSComponents(material, itemHover.count(), nmsPatch); + return new ItemTag(item).identify(); + } + catch (Throwable e) { + Debug.echoError(e); + return null; + } + } + else if (hover.value() instanceof HoverEvent.ShowEntity entityHover) { + return createEntityHoverData(entityHover.id(), entityHover.type(), entityHover.name()).savable(); + } + else { + Debug.echoError("Unrecognized hover event: " + hover); + return null; + } + } + + public static MapTag createEntityHoverData(UUID uuid, Key type, Component name) { + MapTag entityHoverData = new MapTag(); + entityHoverData.putObject("uuid", new ElementTag(uuid.toString(), true)); + entityHoverData.putObject("type", new ElementTag(type.asString(), true)); + if (name != null) { + entityHoverData.putObject("name", new ElementTag(FormattedTextHelper.stringify(name), true)); + } + return entityHoverData; + } + + public static String parseObjectToHover(ObjectTag object, HoverEvent.Action action, Attribute attribute) { + if (action == HoverEvent.Action.SHOW_ENTITY) { + EntityTag toShow = object.asType(EntityTag.class, attribute.context); + if (toShow == null) { + attribute.echoError("Invalid hover object '" + object + "' specified for type 'SHOW_ENTITY': must be an EntityTag."); + return null; + } + return createEntityHoverData(toShow.getUUID(), toShow.getBukkitEntityType().key(), toShow.getBukkitEntity() != null ? toShow.getBukkitEntity().customName() : null).savable(); + } + else if (action == HoverEvent.Action.SHOW_ITEM) { + ItemTag toShow = object.asType(ItemTag.class, attribute.context); + if (toShow == null) { + attribute.echoError("Invalid hover object '" + object + "' specified for type 'SHOW_ITEM': must be an ItemTag."); + return null; + } + return toShow.identify(); + } + else if (action == HoverEvent.Action.SHOW_TEXT) { + return object.identify(); + } + else { + attribute.echoError("Using unsupported hover type: " + action + '.'); + return null; + } + } + + private static HoverEventSource parseLegacyEntityHover(String input) { + EntityTag entity = EntityTag.valueOf(input, CoreUtilities.basicContext); + if (entity == null) { + return null; + } + Component name = null; + if (entity.getBukkitEntity() != null && entity.getBukkitEntity().isCustomNameVisible()) { + name = entity.getBukkitEntity().customName(); + } + return HoverEvent.showEntity(entity.getBukkitEntityType(), entity.getUUID(), name); + } +} diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index c468235626..ffb1c9374d 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -8,10 +8,10 @@ import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.DenizenCore; import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -20,10 +20,12 @@ import com.destroystokyo.paper.profile.ProfileProperty; import io.papermc.paper.entity.TeleportFlag; import io.papermc.paper.potion.PotionMix; +import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; @@ -36,6 +38,7 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.*; +import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionBrewer; import org.bukkit.scoreboard.Team; @@ -49,12 +52,12 @@ public class PaperAPIToolsImpl extends PaperAPITools { @Override public Inventory createInventory(InventoryHolder holder, int slots, String title) { - return Bukkit.getServer().createInventory(holder, slots, PaperModule.parseFormattedText(title, ChatColor.BLACK)); + return Bukkit.getServer().createInventory(holder, slots, FormattedTextHelper.parse(title, NamedTextColor.BLACK)); } @Override public Inventory createInventory(InventoryHolder holder, InventoryType type, String title) { - return Bukkit.getServer().createInventory(holder, type, PaperModule.parseFormattedText(title, ChatColor.BLACK)); + return Bukkit.getServer().createInventory(holder, type, FormattedTextHelper.parse(title, NamedTextColor.BLACK)); } @Override @@ -62,8 +65,14 @@ public String parseComponent(Object input) { if (input == null) { return null; } - if (input instanceof Component) { - return PaperModule.stringifyComponent((Component) input); + if (input instanceof Component component) { + return FormattedTextHelper.stringify(component); + } + else if (input instanceof BaseComponent[] components) { + return FormattedTextHelper.stringify(PaperModule.jsonToComponent(bungeeToJson(components.length == 1 ? components[0] : new TextComponent(components)))); + } + else if (input instanceof BaseComponent component) { + return FormattedTextHelper.stringify(PaperModule.jsonToComponent(bungeeToJson(component))); } return super.parseComponent(input); } @@ -76,28 +85,22 @@ public String getTitle(Inventory inventory) { @Override public void setCustomName(Entity entity, String name) { - entity.customName(PaperModule.parseFormattedText(name, ChatColor.WHITE)); + entity.customName(FormattedTextHelper.parse(name, NamedTextColor.WHITE)); } @Override public String getCustomName(Entity entity) { - return PaperModule.stringifyComponent(entity.customName()); - } - - @Override - public BaseComponent[] getCustomNameComponent(Entity entity) { - Component customName = entity.customName(); - return customName != null ? FormattedTextHelper.parseJson(PaperModule.componentToJson(customName)) : null; + return FormattedTextHelper.stringify(entity.customName()); } @Override public void setPlayerListName(Player player, String name) { - player.playerListName(PaperModule.parseFormattedText(name, ChatColor.WHITE)); + player.playerListName(FormattedTextHelper.parse(name, NamedTextColor.WHITE)); } @Override public String getPlayerListName(Player player) { - return PaperModule.stringifyComponent(player.playerListName()); + return FormattedTextHelper.stringify(player.playerListName()); } @Override @@ -105,14 +108,14 @@ public String[] getSignLines(Sign sign) { String[] output = new String[4]; int i = 0; for (Component component : sign.lines()) { - output[i++] = PaperModule.stringifyComponent(component); + output[i++] = FormattedTextHelper.stringify(component); } return output; } @Override public void setSignLine(Sign sign, int line, String text) { - sign.line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK)); + sign.line(line, FormattedTextHelper.parse(text == null ? "" : text, NamedTextColor.BLACK)); } @Override @@ -121,7 +124,7 @@ public void sendResourcePack(Player player, String url, String hash, boolean for super.sendResourcePack(player, url, hash, false, null); } else { - player.setResourcePack(url, CoreUtilities.toLowerCase(hash), forced, PaperModule.parseFormattedText(prompt, ChatColor.WHITE)); + player.setResourcePack(url, CoreUtilities.toLowerCase(hash), forced, FormattedTextHelper.parse(prompt, NamedTextColor.WHITE)); } } @@ -129,24 +132,19 @@ public void sendResourcePack(Player player, String url, String hash, boolean for public void sendSignUpdate(Player player, Location loc, String[] text) { List components = new ArrayList<>(); for (String line : text) { - components.add(PaperModule.parseFormattedText(line, ChatColor.BLACK)); + components.add(FormattedTextHelper.parse(line, NamedTextColor.BLACK)); } player.sendSignChange(loc, components); } @Override public String getCustomName(Nameable object) { - return PaperModule.stringifyComponent(object.customName()); + return FormattedTextHelper.stringify(object.customName()); } @Override public void setCustomName(Nameable object, String name) { - object.customName(PaperModule.parseFormattedText(name, ChatColor.BLACK)); - } - - @Override - public void sendConsoleMessage(CommandSender sender, String text) { - sender.sendMessage(PaperModule.parseFormattedText(text, ChatColor.WHITE)); + object.customName(FormattedTextHelper.parse(name, NamedTextColor.BLACK)); } @Override @@ -249,12 +247,12 @@ public RecipeChoice createPredicateRecipeChoice(Predicate predicate) @Override public String getDeathMessage(PlayerDeathEvent event) { - return PaperModule.stringifyComponent(event.deathMessage()); + return FormattedTextHelper.stringify(event.deathMessage()); } @Override public void setDeathMessage(PlayerDeathEvent event, String message) { - event.deathMessage(PaperModule.parseFormattedText(message, ChatColor.WHITE)); + event.deathMessage(FormattedTextHelper.parse(message, NamedTextColor.WHITE)); } public Set modifiedTextures = new HashSet<>(); @@ -337,22 +335,22 @@ public T spawnEntity(Location location, Class type, Consum @Override public void setTeamPrefix(Team team, String prefix) { - team.prefix(PaperModule.parseFormattedText(prefix, ChatColor.WHITE)); + team.prefix(FormattedTextHelper.parse(prefix, NamedTextColor.WHITE)); } @Override public void setTeamSuffix(Team team, String suffix) { - team.suffix(PaperModule.parseFormattedText(suffix, ChatColor.WHITE)); + team.suffix(FormattedTextHelper.parse(suffix, NamedTextColor.WHITE)); } @Override public String getTeamPrefix(Team team) { - return PaperModule.stringifyComponent(team.prefix()); + return FormattedTextHelper.stringify(team.prefix()); } @Override public String getTeamSuffix(Team team) { - return PaperModule.stringifyComponent(team.suffix()); + return FormattedTextHelper.stringify(team.suffix()); } @Override @@ -361,28 +359,27 @@ public String convertTextToMiniMessage(String text, boolean splitNewlines) { List lines = CoreUtilities.split(text, '\n'); return lines.stream().map(l -> convertTextToMiniMessage(l, false)).collect(Collectors.joining("\n")); } - Component parsed = PaperModule.jsonToComponent(FormattedTextHelper.componentToJson(FormattedTextHelper.parse(text, ChatColor.WHITE, false))); - return MiniMessage.miniMessage().serialize(parsed); + return MiniMessage.miniMessage().serialize(FormattedTextHelper.parse(text, NamedTextColor.WHITE, false)); } @Override public Merchant createMerchant(String title) { - return Bukkit.createMerchant(PaperModule.parseFormattedText(title, ChatColor.BLACK)); + return Bukkit.createMerchant(FormattedTextHelper.parse(title, NamedTextColor.BLACK)); } @Override public String getText(TextDisplay textDisplay) { - return PaperModule.stringifyComponent(textDisplay.text()); + return FormattedTextHelper.stringify(textDisplay.text()); } @Override public void setText(TextDisplay textDisplay, String text) { - textDisplay.text(PaperModule.parseFormattedText(text, ChatColor.WHITE)); + textDisplay.text(FormattedTextHelper.parse(text, NamedTextColor.WHITE)); } @Override public void kickPlayer(Player player, String message) { - player.kick(PaperModule.parseFormattedText(message, ChatColor.WHITE)); + player.kick(FormattedTextHelper.parse(message, NamedTextColor.WHITE)); } @Override @@ -409,4 +406,80 @@ public void setMaterialTags(Material type, Set tags) { } BlockTagsSetter.INSTANCE.setTags(type, tags); } + + @Override + public String getPage(BookMeta meta, int page) { + return FormattedTextHelper.stringify(meta.page(page)); + } + + @Override + public ListTag getPages(BookMeta meta) { + return new ListTag(meta.pages(), page -> new ElementTag(FormattedTextHelper.stringify(page), true)); + } + + @Override + public void addPage(BookMeta meta, String page) { + meta.addPages(FormattedTextHelper.parse(page, NamedTextColor.BLACK)); + } + + @Override + public void setPages(BookMeta meta, List pages) { + List parsedPages = new ArrayList<>(pages.size()); + for (String page : pages) { + parsedPages.add(FormattedTextHelper.parse(page, NamedTextColor.BLACK)); + } + meta.pages(parsedPages); + } + + @Override + public void setJsonPages(BookMeta meta, List jsonPages) { + List parsedPages = new ArrayList<>(jsonPages.size()); + for (String jsonPage : jsonPages) { + parsedPages.add(PaperModule.jsonToComponent(jsonPage)); + } + meta.pages(parsedPages); + } + + @Override + public void sendMessage(CommandSender sender, String text) { + sender.sendMessage(FormattedTextHelper.parse(text, NamedTextColor.WHITE)); + } + + @Override + public void sendMessage(CommandSender sender, String text, UUID senderId) { + sender.sendMessage(Identity.identity(senderId), FormattedTextHelper.parse(text, NamedTextColor.WHITE)); + } + + @Override + public void broadcast(String text, Predicate filter) { + Component message = null; + for (Player player : Bukkit.getOnlinePlayers()) { + if (filter == null || filter.test(player)) { + if (message == null) { + message = FormattedTextHelper.parse(text, NamedTextColor.WHITE); + } + player.sendMessage(message); + } + } + } + + @Override + public void sendActionBar(Player player, String text) { + player.sendActionBar(FormattedTextHelper.parse(text, NamedTextColor.WHITE)); + } + + @Override + public String parseTextToJson(String formattedText, BaseColor baseColor) { + return PaperModule.componentToJson(FormattedTextHelper.parse(formattedText, switch (baseColor) { + case WHITE -> NamedTextColor.WHITE; + case BLACK -> NamedTextColor.BLACK; + case GRAY -> NamedTextColor.GRAY; + case DARK_GRAY -> NamedTextColor.DARK_GRAY; + })); + } + + @Override + public String parseJsonToText(String json) { + return FormattedTextHelper.stringify(PaperModule.jsonToComponent(json)); + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java index 9060b805b9..334e684df3 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/Denizen.java +++ b/plugin/src/main/java/com/denizenscript/denizen/Denizen.java @@ -51,7 +51,6 @@ import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; -import com.denizenscript.denizencore.utilities.debugging.DebugInternals; import com.denizenscript.denizencore.utilities.debugging.StrongWarning; import com.denizenscript.denizencore.utilities.text.ConfigUpdater; import org.bukkit.Bukkit; @@ -132,7 +131,6 @@ public void onEnable() { if (!PlayerFlagHandler.dataFolder.exists()) { PlayerFlagHandler.dataFolder.mkdir(); } - DebugInternals.alternateTrimLogic = FormattedTextHelper::bukkitSafeDebugTrimming; String javaVersion = System.getProperty("java.version"); Debug.log("Running on java version: " + javaVersion); if (javaVersion.startsWith("8") || javaVersion.startsWith("1.8") || javaVersion.startsWith("9") || javaVersion.startsWith("1.9") diff --git a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerReceivesMessageScriptEvent.java b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerReceivesMessageScriptEvent.java index 46efe9d46f..0779818494 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerReceivesMessageScriptEvent.java +++ b/plugin/src/main/java/com/denizenscript/denizen/events/player/PlayerReceivesMessageScriptEvent.java @@ -2,15 +2,13 @@ import com.denizenscript.denizen.events.BukkitScriptEvent; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntryData; import com.denizenscript.denizencore.utilities.CoreUtilities; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; public class PlayerReceivesMessageScriptEvent extends BukkitScriptEvent { @@ -49,7 +47,6 @@ public PlayerReceivesMessageScriptEvent() { public ElementTag message; public ElementTag rawJson; public boolean didModify; - public BaseComponent[] altMessageDetermination; public ElementTag system; public boolean modified; public PlayerTag player; @@ -62,7 +59,6 @@ public void reset() { system = null; cancelled = false; modified = false; - altMessageDetermination = null; didModify = false; } @@ -89,14 +85,13 @@ public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) { String lower = CoreUtilities.toLowerCase(determination); if (lower.startsWith("message:")) { message = new ElementTag(determination.substring("message:".length()), true); - altMessageDetermination = FormattedTextHelper.parse(message.asString(), ChatColor.WHITE); + rawJson = new ElementTag(PaperAPITools.instance.parseTextToJson(message.asString(), PaperAPITools.BaseColor.WHITE), true); modified = true; return true; } if (lower.startsWith("raw_json:")) { - rawJson = new ElementTag(determination.substring("raw_json:".length())); - altMessageDetermination = null; - message = new ElementTag(FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson.asString())), true); + rawJson = new ElementTag(determination.substring("raw_json:".length()), true); + message = new ElementTag(PaperAPITools.instance.parseJsonToText(rawJson.asString()), true); modified = true; return true; } @@ -114,20 +109,12 @@ public ObjectTag getContext(String name) { switch (name) { case "message": return message; case "system_message": return system; - case "raw_json": - if (altMessageDetermination != null) { - return new ElementTag(FormattedTextHelper.componentToJson(altMessageDetermination), true); - } - return rawJson; + case "raw_json": return rawJson; } return super.getContext(name); } public PlayerReceivesMessageScriptEvent triggerNow() { - PlayerReceivesMessageScriptEvent event = (PlayerReceivesMessageScriptEvent) fire(); - if (event.modified && event.altMessageDetermination == null) { - event.altMessageDetermination = FormattedTextHelper.parseJson(event.rawJson.asString()); - } - return event; + return (PlayerReceivesMessageScriptEvent) fire(); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java index 4ae68a5f7f..a1b27a7218 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/ItemHelper.java @@ -6,7 +6,6 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.utilities.nbt.CustomNBT; import com.denizenscript.denizencore.objects.core.MapTag; -import com.google.gson.JsonObject; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import org.bukkit.DyeColor; @@ -44,15 +43,7 @@ public abstract class ItemHelper { public abstract String getJsonString(ItemStack itemStack); - public String getLegacyHoverNbt(ItemTag item) { // TODO: once 1.20 is the minimum supported version, remove this - return item.getItemMeta().getAsString(); - } - - public JsonObject getRawHoverComponentsJson(ItemStack item) { - throw new UnsupportedOperationException(); - } - - public ItemStack applyRawHoverComponentsJson(ItemStack item, JsonObject components) { + public ItemStack createItemWithNMSComponents(Material type, int count, Object nmsPatch) { throw new UnsupportedOperationException(); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java index 32a8a85a28..af114ff6eb 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java @@ -3,24 +3,16 @@ import com.denizenscript.denizen.objects.*; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper; -import com.denizenscript.denizen.tags.core.CustomColorTagBase; -import com.denizenscript.denizen.utilities.BukkitImplDeprecations; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.denizenscript.denizen.utilities.HoverFormatHelper; import com.denizenscript.denizen.utilities.TextWidthHelper; import com.denizenscript.denizencore.objects.ArgumentHelper; -import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.objects.core.MapTag; -import com.denizenscript.denizencore.tags.TagManager; -import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.Deprecations; import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.HoverEvent; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -326,19 +318,6 @@ public static void register() { return new ElementTag(org.bukkit.ChatColor.getLastColors(object.asString())); }); - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Returns the element with all color encoding stripped. - // This will remove any/all colors, formats (bold/italic/etc), advanced formats (fonts/clickables/etc), and translate any translatables (&translate, &score, etc). - // This will automatically translate translatable sections - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "strip_color", (attribute, object) -> { - return new ElementTag(FormattedTextHelper.parse(object.asString(), ChatColor.WHITE)[0].toPlainText()); - }); - // <--[tag] // @attribute )]> // @returns ElementTag @@ -404,508 +383,6 @@ public static void register() { return new ElementTag(new String(bytes, StandardCharsets.UTF_8)); }); - // <--[tag] - // @attribute - // @returns ElementTag - // @group conversion - // @description - // Converts normal colored text to Minecraft-style "raw JSON" format. - // Inverts <@link tag ElementTag.from_raw_json>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "to_raw_json", (attribute, object) -> { - return new ElementTag(FormattedTextHelper.componentToJson(FormattedTextHelper.parse(object.asString(), ChatColor.WHITE))); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group conversion - // @description - // Un-hides the element's text from invisible color codes back to normal text. - // Inverts <@link tag ElementTag.to_raw_json>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "from_raw_json", (attribute, object) -> { - return new ElementTag(FormattedTextHelper.stringify(FormattedTextHelper.parseJson(object.asString()))); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group conversion - // @description - // Tells the formatted text parser to try to produce mininalist JSON text. - // This is useful in particular for very long text or where text is being sent rapidly/repeatedly. - // It is not needed in most normal messages. - // It will produce incompatibility issues if used in items or other locations where raw JSON matching is required. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "optimize_json", (attribute, object) -> { - String opti = ChatColor.COLOR_CHAR + "[optimize=true]"; - if (object.asString().contains(opti)) { - return object; - } - return new ElementTag(opti + object.asString(), true); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a hover message to the element, which makes the element display the input ItemTag when the mouse is left over it. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // @example - // - narrate "You can ]> to see what you held!" - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ItemTag.class, "hover_item", (attribute, object, item) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[hover=SHOW_ITEM;" + FormattedTextHelper.escape(item.identify()) + "]" + object.asString() + ChatColor.COLOR_CHAR + "[/hover]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a hover message to the element, which makes the element display the input hover text when the mouse is left over it. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerTag(ElementTag.class, ObjectTag.class, "on_hover", (attribute, object, hover) -> { // non-static due to hacked sub-tag - HoverEvent.Action type = HoverEvent.Action.SHOW_TEXT; - - // <--[tag] - // @attribute ].type[]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a hover message to the element, which makes the element display the input hover text when the mouse is left over it. - // Available hover types: SHOW_TEXT, SHOW_ITEM, or SHOW_ENTITY. - // Note: for "SHOW_ITEM", replace the text with a valid ItemTag. For "SHOW_ENTITY", replace the text with a valid spawned EntityTag (requires F3+H to see entities). - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // For show_text, prefer <@link tag ElementTag.on_hover> - // For show_item, prefer <@link tag ElementTag.hover_item> - // --> - if (attribute.startsWith("type", 2)) { - attribute.fulfill(1); - type = ElementTag.asEnum(HoverEvent.Action.class, attribute.getParam()); - if (type == null) { - attribute.echoError("Invalid hover type specified."); - return null; - } - } - String hoverData = HoverFormatHelper.parseObjectToHover(hover, type, attribute); - if (hoverData == null) { - return null; - } - return new ElementTag(ChatColor.COLOR_CHAR + "[hover=" + type + ';' + FormattedTextHelper.escape(hoverData) + ']' - + object.asString() + ChatColor.COLOR_CHAR + "[/hover]", true); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a click command to the element, which makes the element open the given URL when clicked. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // @example - // - narrate "You can to learn about Denizen!" - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "click_url", (attribute, object, url) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[click=OPEN_URL;" + FormattedTextHelper.escape(url.toString()) + "]" + object.asString() + ChatColor.COLOR_CHAR + "[/click]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a click command to the element, which makes the element pseudo-chat the input message when clicked, for activating interact script chat triggers (<@link language Chat Triggers>). - // This internally uses the command "/denizenclickable chat SOME MESSAGE HERE" (requires players have permission "denizen.clickable") - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // @example - // - narrate "You can to say hello to an NPC's interact script!" - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "click_chat", (attribute, object, chat) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[click=RUN_COMMAND;/denizenclickable chat " + FormattedTextHelper.escape(chat.toString()) + "]" + object.asString() + ChatColor.COLOR_CHAR + "[/click]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a click command to the element, which makes the element execute the input command when clicked. - // To execute a command "/" should be used at the start. Prior to 1.19, leaving off the "/" would display the text as chat. This feature was removed as part of the 1.19 secure chat system. - // For activating interact script chat triggers (<@link language Chat Triggers>), you can use the command "/denizenclickable chat SOME MESSAGE HERE" (requires players have permission "denizen.clickable") - // For that, instead prefer <@link tag ElementTag.click_chat> - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // @example - // - narrate "You can for help!" - // @example - // - narrate "You can to say hello to an NPC's interact script!" - // --> - ElementTag.tagProcessor.registerTag(ElementTag.class, ElementTag.class, "on_click", (attribute, object, command) -> { // non-static due to hacked sub-tag - String type = "RUN_COMMAND"; - - // <--[tag] - // @attribute ].type[]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds a click command to the element, which makes the element execute the input command when clicked. - // Available command types: OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, COPY_TO_CLIPBOARD, or CHANGE_PAGE. - // For example: - narrate "You can to learn about Denizen!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // For run_command, prefer <@link tag ElementTag.on_click> - // For chat, prefer <@link tag ElementTag.click_chat> - // For URLs, prefer <@link tag ElementTag.click_url> - // --> - if (attribute.startsWith("type", 2)) { - type = attribute.getContext(2); - attribute.fulfill(1); - } - return new ElementTag(ChatColor.COLOR_CHAR + "[click=" + type + ";" + FormattedTextHelper.escape(command.asString()) + "]" - + object.asString() + ChatColor.COLOR_CHAR + "[/click]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Adds an insertion message to the element, which makes the element insert the input message to chat when shift-clicked. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "with_insertion", (attribute, object, insertion) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[insertion=" + FormattedTextHelper.escape(insertion.asString()) + "]" - + object.asString() + ChatColor.COLOR_CHAR + "[/insertion]"); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes a color code (&0123456789abcdef) not reset other formatting details. - // Use like '<&c.no_reset>' or ''. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "no_reset", (attribute, object) -> { - if (object.asString().length() == 2 && object.asString().charAt(0) == ChatColor.COLOR_CHAR) { - return new ElementTag(ChatColor.COLOR_CHAR + "[color=" + object.asString().charAt(1) + "]"); - } - return null; - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes a chat format code (&klmno, or &[font=...]) be the end of a format, as opposed to the start. - // Use like '<&o.end_format>' or ''. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "end_format", (attribute, object) -> { - if (object.asString().length() == 2 && object.asString().charAt(0) == ChatColor.COLOR_CHAR) { - return new ElementTag(ChatColor.COLOR_CHAR + "[reset=" + object.asString().charAt(1) + "]"); - } - else if (object.asString().startsWith(ChatColor.COLOR_CHAR + "[font=") && object.asString().endsWith("]")) { - return new ElementTag(ChatColor.COLOR_CHAR + "[reset=font]"); - } - return null; - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text italic. Equivalent to "<&o><&o.end_format>" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "italicize", (attribute, object) -> { - return new ElementTag(ChatColor.ITALIC + object.asString() + ChatColor.COLOR_CHAR + "[reset=o]"); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text bold. Equivalent to "<&l><&l.end_format>" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "bold", (attribute, object) -> { - return new ElementTag(ChatColor.BOLD + object.asString() + ChatColor.COLOR_CHAR + "[reset=l]"); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text underlined. Equivalent to "<&n><&n.end_format>" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "underline", (attribute, object) -> { - return new ElementTag(ChatColor.UNDERLINE + object.asString() + ChatColor.COLOR_CHAR + "[reset=n]"); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text struck-through. Equivalent to "<&m><&m.end_format>" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "strikethrough", (attribute, object) -> { - return new ElementTag(ChatColor.STRIKETHROUGH + object.asString() + ChatColor.COLOR_CHAR + "[reset=m]"); - }); - - // <--[tag] - // @attribute - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text obfuscated. Equivalent to "<&k><&k.end_format>" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "obfuscate", (attribute, object) -> { - return new ElementTag(ChatColor.MAGIC + object.asString() + ChatColor.COLOR_CHAR + "[reset=k]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text colored by the custom color value based on the common base color names defined in the Denizen config file. - // If the color name is unrecognized, returns the value of color named 'default'. - // Default color names are 'base', 'emphasis', 'warning', 'error'. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "custom_color", (attribute, object, name) -> { - String color = CustomColorTagBase.getColor(name.asLowerString(), attribute.context); - if (color == null) { - return null; - } - return new ElementTag(ChatColor.COLOR_CHAR + "[color=f]" + color + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text colored by the input color. Equivalent to "" - // Color can be a color name, color code, hex, or ColorTag... that is: ".color[gold]", ".color[6]", and ".color[#AABB00]" are all valid. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "color", (attribute, object, colorElement) -> { - String colorName = colorElement.asString(); - String colorOut = null; - if (colorName.length() == 1) { - ChatColor color = ChatColor.getByChar(colorName.charAt(0)); - if (color != null) { - colorOut = color.toString(); - } - } - else if (colorName.length() == 7 && colorName.startsWith("#")) { - return new ElementTag(ChatColor.COLOR_CHAR + "[color=" + colorName + "]" + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - } - else if (colorName.length() == 14 && colorName.startsWith(ChatColor.COLOR_CHAR + "x")) { - return new ElementTag(ChatColor.COLOR_CHAR + "[color=#" + CoreUtilities.replace(colorName.substring(2), String.valueOf(ChatColor.COLOR_CHAR), "") + "]" + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - } - else if (colorName.startsWith("co@")) { - ColorTag color = ColorTag.valueOf(colorName, attribute.context); - if (color == null && TagManager.isStaticParsing) { - return null; - } - StringBuilder hex = new StringBuilder(Integer.toHexString(color.asRGB())); - while (hex.length() < 6) { - hex.insert(0, "0"); - } - return new ElementTag(ChatColor.COLOR_CHAR + "[color=#" + hex + "]" + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - } - if (colorOut == null) { - try { - ChatColor color = ChatColor.of(colorName.toUpperCase()); - if (color.getColor() == null) { - if (!TagManager.isStaticParsing) { - attribute.echoError("Color '" + colorName + "' is valid but is a format code not a real color (for ElementTag.color[...])."); - } - return null; - } - String colorStr = color.toString().replace(String.valueOf(ChatColor.COLOR_CHAR), "").replace("x", "#"); - colorOut = ChatColor.COLOR_CHAR + "[color=" + colorStr + "]"; - } - catch (IllegalArgumentException ex) { - ColorTag color = ColorTag.valueOf(colorName, attribute.context); - if (color != null) { - StringBuilder hex = new StringBuilder(Integer.toHexString(color.asRGB())); - while (hex.length() < 6) { - hex.insert(0, "0"); - } - return new ElementTag(ChatColor.COLOR_CHAR + "[color=#" + hex + "]" + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - } - if (!TagManager.isStaticParsing) { - attribute.echoError("Color '" + colorName + "' doesn't exist (for ElementTag.color[...])."); - } - return null; - } - } - return new ElementTag(colorOut + object.asString() + ChatColor.COLOR_CHAR + "[reset=color]"); - }); - - // <--[tag] - // @attribute ]> - // @returns ElementTag - // @group text manipulation - // @description - // Makes the input text display with the input font name. Equivalent to "<&font[new-font]><&font[new-font].end_format>" - // The default font is "minecraft:default". - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, ElementTag.class, "font", (attribute, object, fontName) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[font=" + fontName + "]" + object.asString() + ChatColor.COLOR_CHAR + "[reset=font]"); - }); - - // <--[tag] - // @attribute )]> - // @returns ElementTag - // @group text manipulation - // @description - // Returns the element with rainbow colors applied. - // Optionally, specify a color pattern to follow. By default, this is "4c6e2ab319d5". - // That is, a repeating color of: Red, Orange, Yellow, Green, Cyan, Blue, Purple. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "rainbow", (attribute, object) -> { - String str = object.asString(); - String pattern = "4c6e2ab319d5"; - if (attribute.hasParam()) { - pattern = attribute.getParam(); - } - StringBuilder output = new StringBuilder(str.length() * 3); - for (int i = 0; i < str.length(); i++) { - output.append(ChatColor.COLOR_CHAR).append(pattern.charAt(i % pattern.length())).append(str.charAt(i)); - } - return new ElementTag(output.toString()); - }); - - // <--[tag] - // @attribute )]> - // @returns ElementTag - // @group text manipulation - // @description - // Returns the element with RGB rainbow colors applied. - // Optionally, specify a length (how many characters before the colors repeat). If unspecified, will use the input element length. - // If the element starts with a hex color code, that will be used as the starting color of the rainbow. - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, "hex_rainbow", (attribute, object) -> { - String str = object.asString(); - int[] HSB = new int[] { 0, 255, 255 }; - if (str.startsWith(ChatColor.COLOR_CHAR + "x") && str.length() > 14) { - char[] colors = new char[6]; - for (int i = 0; i < 6; i++) { - colors[i] = str.charAt(3 + (i * 2)); - } - int rgb = Integer.parseInt(new String(colors), 16); - HSB = ColorTag.fromRGB(rgb).toHSB(); - str = str.substring(14); - } - float hue = HSB[0] / 255f; - int length = ChatColor.stripColor(str).length(); - if (length == 0) { - return new ElementTag(""); - } - if (attribute.hasParam()) { - length = attribute.getIntParam(); - } - float increment = 1.0f / length; - String addedFormat = ""; - StringBuilder output = new StringBuilder(str.length() * 8); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (c == ChatColor.COLOR_CHAR && i + 1 < str.length()) { - char c2 = str.charAt(i + 1); - if (FORMAT_CODES_MATCHER.isMatch(c2)) { - addedFormat += String.valueOf(ChatColor.COLOR_CHAR) + c2; - } - else { - addedFormat = ""; - } - i++; - continue; - } - String hex = Integer.toHexString(ColorTag.fromHSB(HSB).asRGB()); - output.append(FormattedTextHelper.stringifyRGBSpigot(hex)).append(addedFormat).append(c); - hue += increment; - HSB[0] = Math.round(hue * 255f); - } - return new ElementTag(output.toString()); - }); - - // <--[tag] - // @attribute ;to=;(style={RGB}/HSB)]> - // @returns ElementTag - // @group text manipulation - // @description - // Returns the element with an RGB color gradient applied, with a unique color per character. - // Specify the input as a map with keys 'from' and 'to' both set to hex colors (or any valid ColorTag). - // You can also choose a style (defaults to RGB): - // "style=RGB" tends to produce smooth gradients, - // "style=HSB" tends to produce bright rainbow-like color patterns. - // @example - // - narrate "" - // @example - // - narrate "" - // @example - // - narrate "" - // @example - // - narrate "" - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, MapTag.class, "color_gradient", (attribute, object, inputMap) -> { - ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); - ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); - ElementTag style = inputMap.getElement("style", "RGB"); - if (fromColor == null || toColor == null) { - return null; - } - if (!style.matchesEnum(BukkitElementExtensions.GradientStyle.class)) { - attribute.echoError("Invalid gradient style '" + style + "'"); - return null; - } - String res = doGradient(object.asString(), fromColor, toColor, style.asEnum(GradientStyle.class)); - if (res == null) { - return null; - } - return new ElementTag(res); - }); - - // <--[tag] - // @attribute ;to=]> - // @returns ElementTag - // @group text manipulation - // @deprecated use color_gradient[from=color;to=color;style=HSB] - // @description - // Deprecated in favor of using <@link tag ElementTag.color_gradient> with "style=hsb" - // --> - ElementTag.tagProcessor.registerStaticTag(ElementTag.class, MapTag.class, "hsb_color_gradient", (attribute, object, inputMap) -> { - BukkitImplDeprecations.hsbColorGradientTag.warn(attribute.context); - ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); - ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); - if (fromColor == null || toColor == null) { - return null; - } - String res = doGradient(object.asString(), fromColor, toColor, GradientStyle.HSB); - if (res == null) { - return null; - } - return new ElementTag(res); - }); - // <--[tag] // @attribute // @returns MapTag @@ -930,96 +407,4 @@ else if (colorName.startsWith("co@")) { } }); } - - public enum GradientStyle { RGB, HSB } - - public static String doGradient(String str, ColorTag fromColor, ColorTag toColor, GradientStyle style) { - int length = FormattedTextHelper.parse(str, ChatColor.WHITE)[0].toPlainText().length(); - if (length == 0) { - return ""; - } - if (fromColor == null || toColor == null) { - return null; - } - float r, g, b, x = 0, rMove, gMove, bMove, xMove = 0, toR, toG, toB; - int[] hsbHelper = null; - if (style == GradientStyle.RGB) { - r = ColorTag.fromSRGB(fromColor.red); - g = ColorTag.fromSRGB(fromColor.green); - b = ColorTag.fromSRGB(fromColor.blue); - x = (float) Math.pow(r + g + b, 0.43); - toR = ColorTag.fromSRGB(toColor.red); - toG = ColorTag.fromSRGB(toColor.green); - toB = ColorTag.fromSRGB(toColor.blue); - float toBrightness = (float) Math.pow(toR + toG + toB, 0.43); - xMove = (toBrightness - x) / length; - } - else { - hsbHelper = fromColor.toHSB(); - int[] toHSB = toColor.toHSB(); - r = hsbHelper[0]; - g = hsbHelper[1]; - b = hsbHelper[2]; - toR = toHSB[0]; - toG = toHSB[1]; - toB = toHSB[2]; - } - rMove = (toR - r) / length; - gMove = (toG - g) / length; - bMove = (toB - b) / length; - String addedFormat = ""; - StringBuilder output = new StringBuilder(str.length() * 15); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (c == ChatColor.COLOR_CHAR && i + 1 < str.length()) { - char c2 = str.charAt(i + 1); - if (FORMAT_CODES_MATCHER.isMatch(c2)) { - addedFormat += String.valueOf(ChatColor.COLOR_CHAR) + c2; - } - else if (c2 == '[') { - int endBracket = str.indexOf(']', i); - if (endBracket != -1) { - addedFormat += str.substring(i, endBracket + 1); - i = endBracket - 1; - } - } - else { - addedFormat = ""; - } - i++; - continue; - } - String hex; - if (style == GradientStyle.RGB) { - // Based on https://stackoverflow.com/questions/22607043/color-gradient-algorithm/49321304#49321304 - float newRed = r, newGreen = g, newBlue = b; - float sum = newRed + newGreen + newBlue; - if (sum > 0) { - float multiplier = (float) Math.pow(x, 1f / 0.43f) / sum; - newRed *= multiplier; - newGreen *= multiplier; - newBlue *= multiplier; - } - newRed = ColorTag.toSRGB(newRed); - newGreen = ColorTag.toSRGB(newGreen); - newBlue = ColorTag.toSRGB(newBlue); - hex = Integer.toHexString((((int) newRed) << 16) | (((int) newGreen) << 8) | ((int) newBlue)); - x += xMove; - } - else { - hsbHelper[0] = (int)r; - hsbHelper[1] = (int)g; - hsbHelper[2] = (int)b; - ColorTag currentColor = ColorTag.fromHSB(hsbHelper); - hex = Integer.toHexString(currentColor.asRGB()); - } - output.append(FormattedTextHelper.stringifyRGBSpigot(hex)).append(addedFormat).append(str.charAt(i)); - r += rMove; - g += gMove; - b += bMove; - } - return output.toString(); - } - - public static AsciiMatcher FORMAT_CODES_MATCHER = new AsciiMatcher("klmnoKLMNO"); } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemBook.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemBook.java index b428803ccf..4aacdb64f1 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemBook.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemBook.java @@ -2,7 +2,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; @@ -10,14 +10,9 @@ import com.denizenscript.denizencore.objects.properties.Property; import com.denizenscript.denizencore.objects.properties.PropertyParser; import com.denizenscript.denizencore.tags.core.EscapeTagUtil; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Material; import org.bukkit.inventory.meta.BookMeta; -import java.util.ArrayList; -import java.util.List; - public class ItemBook implements Property { public static boolean describes(ObjectTag item) { @@ -89,12 +84,7 @@ public static void register() { // Returns the plain-text pages of the book as a ListTag. // --> PropertyParser.registerTag(ItemBook.class, ListTag.class, "book_pages", (attribute, object) -> { - List pages = object.getBookMeta().spigot().getPages(); - ListTag pageList = new ListTag(pages.size()); - for (BaseComponent[] page : pages) { - pageList.addObject(new ElementTag(FormattedTextHelper.stringify(page), true)); - } - return pageList; + return PaperAPITools.instance.getPages(object.getBookMeta()); }); // <--[tag] @@ -129,15 +119,11 @@ public static void register() { } if ((attribute.startsWith("page", 2) || attribute.startsWith("get_page", 2)) && attribute.hasContext(2)) { attribute.fulfill(1); - return new ElementTag(FormattedTextHelper.stringify(bookMeta.spigot().getPage(attribute.getIntParam()))); + return new ElementTag(PaperAPITools.instance.getPage(bookMeta, attribute.getIntParam())); } if (attribute.startsWith("pages", 2)) { attribute.fulfill(1); - ListTag output = new ListTag(); - for (BaseComponent[] page : bookMeta.spigot().getPages()) { - output.add(FormattedTextHelper.stringify(page)); - } - return output; + return PaperAPITools.instance.getPages(bookMeta); } String output = object.getOutputString(); if (output == null) { @@ -157,11 +143,7 @@ public static void register() { // --> PropertyParser.registerMechanism(ItemBook.class, ListTag.class, "book_pages", (object, mechanism, input) -> { BookMeta bookMeta = object.getBookMeta(); - List newPages = new ArrayList<>(input.size()); - for (String page : input) { - newPages.add(FormattedTextHelper.parse(page, ChatColor.BLACK)); - } - bookMeta.spigot().setPages(newPages); + PaperAPITools.instance.setPages(bookMeta, input); object.item.setItemMeta(bookMeta); }); @@ -242,11 +224,7 @@ public static void register() { } ListTag pages = bookMap.getObjectAs("pages", ListTag.class, mechanism.context); if (pages != null) { - List newPages = new ArrayList<>(pages.size()); - for (String page : pages) { - newPages.add(FormattedTextHelper.parse(page, ChatColor.BLACK)); - } - bookMeta.spigot().setPages(newPages); + PaperAPITools.instance.setPages(bookMeta, pages); } object.item.setItemMeta(bookMeta); return; @@ -274,18 +252,10 @@ public static void register() { } } if (data.get(0).equalsIgnoreCase("raw_pages")) { - List newPages = new ArrayList<>(data.size()); - for (int i = 1; i < data.size(); i++) { - newPages.add(FormattedTextHelper.parseJson(EscapeTagUtil.unEscape(data.get(i)))); - } - bookMeta.spigot().setPages(newPages); + PaperAPITools.instance.setJsonPages(bookMeta, data.stream().skip(1).map(EscapeTagUtil::unEscape).toList()); } else if (data.get(0).equalsIgnoreCase("pages")) { - List newPages = new ArrayList<>(data.size()); - for (int i = 1; i < data.size(); i++) { - newPages.add(FormattedTextHelper.parse(EscapeTagUtil.unEscape(data.get(i)), ChatColor.BLACK)); - } - bookMeta.spigot().setPages(newPages); + PaperAPITools.instance.setPages(bookMeta, data.stream().skip(1).map(EscapeTagUtil::unEscape).toList()); } else { mechanism.echoError("Invalid book input!"); @@ -304,12 +274,7 @@ public MapTag getBookMap() { bookMap.putObject("title", new ElementTag(bookMeta.getTitle(), true)); } if (bookMeta.hasPages()) { - List pages = bookMeta.spigot().getPages(); - ListTag pageList = new ListTag(pages.size()); - for (BaseComponent[] page : pages) { - pageList.addObject(new ElementTag(FormattedTextHelper.stringify(page), true)); - } - bookMap.putObject("pages", pageList); + bookMap.putObject("pages", PaperAPITools.instance.getPages(bookMeta)); } return bookMap; } @@ -332,8 +297,8 @@ public String getOutputString() { } output.append("pages|"); if (bookMeta.hasPages()) { - for (BaseComponent[] page : bookMeta.spigot().getPages()) { - output.append(EscapeTagUtil.escape(FormattedTextHelper.stringify(page))).append("|"); + for (String page : PaperAPITools.instance.getPages(bookMeta)) { + output.append(EscapeTagUtil.escape(page)).append("|"); } } return output.substring(0, output.length() - 1); diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ActionBarCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ActionBarCommand.java index 46c26002d2..7e06cf300c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ActionBarCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ActionBarCommand.java @@ -2,7 +2,7 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.tags.BukkitTagContext; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; @@ -16,8 +16,6 @@ import com.denizenscript.denizencore.scripts.containers.core.FormatScriptContainer; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.ChatMessageType; import java.util.Collections; import java.util.List; @@ -135,7 +133,7 @@ public void execute(ScriptEntry scriptEntry) { context.player = player; personalText = TagManager.tag(personalText, context); } - player.getPlayerEntity().spigot().sendMessage(ChatMessageType.ACTION_BAR, FormattedTextHelper.parse(format != null ? format.getFormattedText(personalText, scriptEntry) : personalText, ChatColor.WHITE)); + PaperAPITools.instance.sendActionBar(player.getPlayerEntity(), format != null ? format.getFormattedText(personalText, scriptEntry) : personalText); } else { Debug.echoError("Sent actionbar to non-existent player!?"); diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/NarrateCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/NarrateCommand.java index eca26b3eee..38d33f46d0 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/NarrateCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/NarrateCommand.java @@ -2,7 +2,7 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.tags.BukkitTagContext; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; @@ -18,9 +18,6 @@ import com.denizenscript.denizencore.scripts.containers.core.FormatScriptContainer; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Bukkit; import java.util.Collections; @@ -133,6 +130,7 @@ public void execute(ScriptEntry scriptEntry) { if (scriptEntry.dbCallShouldDebug()) { Debug.report(scriptEntry, getName(), db("Narrating", text), db("Targets", targets), formatObj, perPlayerObj, from); } + // TODO: as of signed chat, this has no effect. Either add proper signed chat support or deprecate. UUID fromId = null; if (from != null) { if (from.asString().startsWith("p@")) { @@ -151,7 +149,7 @@ public void execute(ScriptEntry scriptEntry) { formattingContext = scriptContainer != null ? scriptContainer.getFormattingContext() : null; } if (targets == null) { - Bukkit.getServer().getConsoleSender().spigot().sendMessage(FormattedTextHelper.parse(formattingContext != null ? formattingContext.format(NARRATE_FORMAT_TYPE, text, scriptEntry) : text, ChatColor.WHITE)); + PaperAPITools.instance.sendMessage(Bukkit.getServer().getConsoleSender(), formattingContext != null ? formattingContext.format(NARRATE_FORMAT_TYPE, text, scriptEntry) : text); return; } for (PlayerTag player : targets) { @@ -165,12 +163,12 @@ public void execute(ScriptEntry scriptEntry) { context.player = player; personalText = TagManager.tag(personalText, context); } - BaseComponent[] component = FormattedTextHelper.parse(formattingContext != null ? formattingContext.format(NARRATE_FORMAT_TYPE, personalText, scriptEntry) : personalText, ChatColor.WHITE); + String formattedText = formattingContext != null ? formattingContext.format(NARRATE_FORMAT_TYPE, personalText, scriptEntry) : personalText; if (fromId == null) { - player.getPlayerEntity().spigot().sendMessage(component); + PaperAPITools.instance.sendMessage(player.getPlayerEntity(), formattedText); } else { - player.getPlayerEntity().spigot().sendMessage(ChatMessageType.CHAT, fromId, component); + PaperAPITools.instance.sendMessage(player.getPlayerEntity(), formattedText, fromId); } } else { diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/server/AnnounceCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/server/AnnounceCommand.java index 7d9f0ca4e5..d5aa13fcac 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/server/AnnounceCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/server/AnnounceCommand.java @@ -1,8 +1,7 @@ package com.denizenscript.denizen.scripts.commands.server; -import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.ElementTag; @@ -13,7 +12,6 @@ import com.denizenscript.denizencore.scripts.containers.ScriptContainer; import com.denizenscript.denizencore.scripts.containers.core.FormatScriptContainer; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -137,30 +135,18 @@ public void execute(ScriptEntry scriptEntry) { // Use Bukkit to broadcast the message to everybody in the server. switch (type) { case ALL: - Denizen.getInstance().getServer().spigot().broadcast(FormattedTextHelper.parse(message, ChatColor.WHITE)); + PaperAPITools.instance.broadcast(message, null); break; case TO_OPS: - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.isOp()) { - player.spigot().sendMessage(FormattedTextHelper.parse(message, ChatColor.WHITE)); - } - } + PaperAPITools.instance.broadcast(message, Player::isOp); break; case TO_PERMISSION: - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.hasPermission(flag.asString())) { - player.spigot().sendMessage(FormattedTextHelper.parse(message, ChatColor.WHITE)); - } - } + PaperAPITools.instance.broadcast(message, player -> player.hasPermission(flag.asString())); case TO_FLAGGED: - for (Player player : Bukkit.getOnlinePlayers()) { - if (new PlayerTag(player).getFlagTracker().hasFlag(flag.asString())) { - player.spigot().sendMessage(FormattedTextHelper.parse(message, ChatColor.WHITE)); - } - } + PaperAPITools.instance.broadcast(message, player -> new PlayerTag(player).getFlagTracker().hasFlag(flag.asString())); break; case TO_CONSOLE: - Bukkit.getServer().getConsoleSender().spigot().sendMessage(FormattedTextHelper.parse(message, ChatColor.WHITE)); + PaperAPITools.instance.sendMessage(Bukkit.getServer().getConsoleSender(), message); break; } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/BookScriptContainer.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/BookScriptContainer.java index f2ab0280f1..32811c1769 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/BookScriptContainer.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/BookScriptContainer.java @@ -2,13 +2,12 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.tags.BukkitTagContext; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.core.ScriptTag; import com.denizenscript.denizencore.scripts.containers.ScriptContainer; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.YamlConfiguration; -import net.md_5.bungee.api.ChatColor; import org.bukkit.Material; import org.bukkit.inventory.meta.BookMeta; @@ -94,8 +93,7 @@ public ItemTag writeBookTo(ItemTag book, TagContext context) { if (contains("text", List.class)) { List pages = getStringList("text"); for (String page : pages) { - page = TagManager.tag(page, context); - bookInfo.spigot().addPage(FormattedTextHelper.parse(page, ChatColor.BLACK)); + PaperAPITools.instance.addPage(bookInfo, TagManager.tag(page, context)); } } book.setItemMeta(bookInfo); diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/EnchantmentScriptContainer.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/EnchantmentScriptContainer.java index 29c080c550..3752675dff 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/EnchantmentScriptContainer.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/containers/core/EnchantmentScriptContainer.java @@ -4,8 +4,7 @@ import com.denizenscript.denizen.objects.EntityTag; import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.tags.BukkitTagContext; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ScriptTag; @@ -18,8 +17,7 @@ import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.YamlConfiguration; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; +import com.denizenscript.denizencore.utilities.debugging.Debug; import org.bukkit.Bukkit; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -225,7 +223,7 @@ public EnchantmentScriptContainer(YamlConfiguration configurationSection, String public List slots; - public HashMap fullNamePerLevel = new HashMap<>(); + public HashMap fullNamePerLevel = new HashMap<>(); public Enchantment enchantment; @@ -280,13 +278,13 @@ public boolean isCompatible(Enchantment enchantment) { return CoreUtilities.toLowerCase(res).equals("true"); } - public BaseComponent[] getFullName(int level) { - BaseComponent[] result = fullNamePerLevel.get(level); + public String getFullName(int level) { + String result = fullNamePerLevel.get(level); if (result != null) { return result; } String tagged = autoTagForLevel(fullNameTaggable, level); - result = FormattedTextHelper.parse(tagged, ChatColor.GRAY); + result = PaperAPITools.instance.parseTextToJson(tagged, PaperAPITools.BaseColor.GRAY); fullNamePerLevel.put(level, result); return result; } diff --git a/plugin/src/main/java/com/denizenscript/denizen/tags/core/TextTagBase.java b/plugin/src/main/java/com/denizenscript/denizen/tags/core/TextTagBase.java index ac638557c9..5be9330afd 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/tags/core/TextTagBase.java +++ b/plugin/src/main/java/com/denizenscript/denizen/tags/core/TextTagBase.java @@ -1,18 +1,9 @@ package com.denizenscript.denizen.tags.core; -import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.denizenscript.denizen.utilities.HoverFormatHelper; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.core.ListTag; -import com.denizenscript.denizencore.objects.core.MapTag; import com.denizenscript.denizencore.tags.TagManager; -import com.denizenscript.denizencore.tags.core.EscapeTagUtil; import com.denizenscript.denizencore.utilities.CoreUtilities; -import net.md_5.bungee.api.chat.HoverEvent; import org.bukkit.ChatColor; public class TextTagBase { @@ -32,324 +23,6 @@ public TextTagBase() { // --> TagManager.registerStaticTagBaseHandler(ElementTag.class, "p", (attribute) -> new ElementTag("\n " + ChatColor.RESET + " \n")); - // <--[tag] - // @attribute <&hover[]> - // @returns ElementTag - // @description - // Returns a special chat code that makes the following text display the input hover text when the mouse is left over it. - // This tag must be followed by an <&end_hover> tag. - // For example: - narrate "There is a <&hover[you found it!]>secret<&end_hover> in this message!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerTagHandler(ElementTag.class, ObjectTag.class, "&hover", (attribute, hover) -> { // Cannot be static due to hacked sub-tag - - // <--[tag] - // @attribute <&hover[].type[]> - // @returns ElementTag - // @description - // Returns a special chat code that makes the following text display the input hover text when the mouse is left over it. - // This tag must be followed by an <&end_hover> tag. - // Available hover types: SHOW_TEXT, SHOW_ITEM, or SHOW_ENTITY. - // For example: - narrate "There is a <&hover[you found it!].type[SHOW_TEXT]>secret<&end_hover> in this message!" - // Note: for "SHOW_ITEM", replace the text with a valid ItemTag. For "SHOW_ENTITY", replace the text with a valid spawned EntityTag (requires F3+H to see entities). - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - HoverEvent.Action type = HoverEvent.Action.SHOW_TEXT; - if (attribute.startsWith("type", 2)) { - attribute.fulfill(1); - type = ElementTag.asEnum(HoverEvent.Action.class, attribute.getParam()); - if (type == null) { - attribute.echoError("Invalid hover type specified."); - return null; - } - } - String hoverData = HoverFormatHelper.parseObjectToHover(hover, type, attribute); - if (hoverData == null) { - return null; - } - return new ElementTag(ChatColor.COLOR_CHAR + "[hover=" + type + ';' + FormattedTextHelper.escape(hoverData) + ']', true); - }); - - // <--[tag] - // @attribute <&click[]> - // @returns ElementTag - // @description - // Returns a special chat code that makes the following text execute the input command line value when clicked. - // To execute a command "/" should be used at the start. Otherwise, it will display as chat. - // This tag must be followed by an <&end_click> tag. - // For example: - narrate "You can <&click[wow]>click here<&end_click> to say wow!" - // For example: - narrate "You can <&click[/help]>click here<&end_click> for help!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerTagHandler(ElementTag.class, "&click", (attribute) -> { // Cannot be static due to hacked sub-tag - if (!attribute.hasParam()) { - return null; - } - String clickText = attribute.getParam(); - - // <--[tag] - // @attribute <&click[].type[]> - // @returns ElementTag - // @description - // Returns a special chat code that makes the following text execute the input command when clicked. - // This tag must be followed by an <&end_click> tag. - // Available command types: OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, COPY_TO_CLIPBOARD, or CHANGE_PAGE. - // For example: - narrate "You can <&click[https://denizenscript.com].type[OPEN_URL]>click here<&end_click> to learn about Denizen!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - String type = "RUN_COMMAND"; - if (attribute.startsWith("type", 2)) { - type = attribute.getContext(2); - attribute.fulfill(1); - } - return new ElementTag(ChatColor.COLOR_CHAR + "[click=" + type + ";" + FormattedTextHelper.escape(clickText) + "]"); - }); - - // <--[tag] - // @attribute <&insertion[]> - // @returns ElementTag - // @description - // Returns a special chat code that makes the following text insert the input message to chat when shift-clicked. - // This tag must be followed by an <&end_insertion> tag. - // For example: - narrate "You can <&insertion[wow]>click here<&end_insertion> to add 'wow' to your chat!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&insertion", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - String insertText = attribute.getParam(); - return new ElementTag(ChatColor.COLOR_CHAR + "[insertion=" + FormattedTextHelper.escape(insertText) + "]"); - }); - - // <--[tag] - // @attribute <&end_click> - // @returns ElementTag - // @description - // Returns a special chat code that ends a '&click' tag. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_click", (attribute) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[/click]"); - }); - - // <--[tag] - // @attribute <&end_hover> - // @returns ElementTag - // @description - // Returns a special chat code that ends a '&hover' tag. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_hover", (attribute) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[/hover]"); - }); - - // <--[tag] - // @attribute <&end_insertion> - // @returns ElementTag - // @description - // Returns a special chat code that ends an '&insertion' tag. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&end_insertion", (attribute) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[/insertion]"); - }); - - // <--[tag] - // @attribute <&keybind[]> - // @returns ElementTag - // @description - // Returns a special chat code that displays a keybind. - // For example: - narrate "Press your <&keybind[key.jump]> key!" - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&keybind", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - String keybindText = attribute.getParam(); - return new ElementTag(ChatColor.COLOR_CHAR + "[keybind=" + FormattedTextHelper.escape(keybindText) + "]"); - }); - - // <--[tag] - // @attribute <&selector[]> - // @returns ElementTag - // @description - // Returns a special chat code that displays a vanilla selector. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&selector", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - String selectorText = attribute.getParam(); - return new ElementTag(ChatColor.COLOR_CHAR + "[selector=" + FormattedTextHelper.escape(selectorText) + "]"); - }); - - // <--[tag] - // @attribute <&translate[key=;(fallback=);(with=|...)]> - // @returns ElementTag - // @description - // Returns a special chat code that is read by the client to display an auto-translated message. - // "key" is the translation key. - // Optionally specify "fallback" as text to display when the client can't find a translation for the key. - // Optionally specify "with" as a list of input data for the translatable message (parts of the message that are dynamic). - // Be warned that language keys can change between Minecraft versions. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // You can use <@link tag ElementTag.strip_color> to convert the translated output to plain text (pre-translated). - // @example - // # Narrates a translatable of a diamond sword's name. - // - narrate "Reward: <&translate[key=item.minecraft.diamond_sword]>" - // @example - // # Narrates a translatable with some input data. - // - narrate <&translate[key=commands.give.success.single;with=32|<&translate[key=item.minecraft.diamond_sword]>|]> - // @example - // # Narrates a custom translatable (from something like a resource pack), with a fallback in case it can't be translated. - // - narrate <&translate[key=my.custom.translation;fallback=Please use the resource pack!]> - // --> - TagManager.registerTagHandler(ElementTag.class, ObjectTag.class, "&translate", (attribute, param) -> { // Cannot be static due to hacked sub-tag - MapTag translateMap = param.asType(MapTag.class, CoreUtilities.noDebugContext); - if (translateMap == null) { - BukkitImplDeprecations.translateLegacySyntax.warn(attribute.context); - translateMap = new MapTag(); - translateMap.putObject("key", param); - - // <--[tag] - // @attribute <&translate[].with[|...]> - // @returns ElementTag - // @deprecated Use '<&translate[key=;with=|...]>'. - // @description - // Deprecated in favor of <@link tag &translate>. - // --> - if (attribute.startsWith("with", 2)) { - translateMap.putObject("with", new ListTag(attribute.contextAsType(2, ListTag.class), with -> new ElementTag(EscapeTagUtil.unEscape(with), true))); - attribute.fulfill(1); - } - } - return new ElementTag(ChatColor.COLOR_CHAR + "[translate=" + FormattedTextHelper.escape(translateMap.savable()) + ']', true); - }); - - // <--[tag] - // @attribute <&score[|(|)]> - // @returns ElementTag - // @description - // Returns a special chat code that displays a scoreboard entry. Input is an escaped list of: - // Name of the relevant entity, name of the objective, then optionally a value (if unspecified, will use current scoreboard value). - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&score", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - ListTag scoreList = attribute.paramAsType(ListTag.class); - if (scoreList.size() < 2) { - return null; - } - String name = FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(0))); - String objective = FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(1))); - String value = scoreList.size() >= 3 ? FormattedTextHelper.escape(EscapeTagUtil.unEscape(scoreList.get(2))) : ""; - return new ElementTag(ChatColor.COLOR_CHAR + "[score=" + name + ";" + objective + ";" + value + "]"); - }); - - // <--[tag] - // @attribute <&color[]> - // @returns ElementTag - // @description - // Returns a chat code that makes the following text be the specified color. - // Color can be a color name, color code, hex, or ColorTag... that is: "&color[gold]", "&color[6]", and "&color[#AABB00]" are all valid. - // The ColorTag input option can be used for dynamic color effects, such as automatic rainbows. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&color", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - String colorName = attribute.getParam(); - String colorOut = null; - if (colorName.length() == 1) { - ChatColor color = ChatColor.getByChar(colorName.charAt(0)); - if (color != null) { - colorOut = color.toString(); - } - } - else if (colorName.length() == 7 && colorName.startsWith("#")) { - colorOut = FormattedTextHelper.stringifyRGBSpigot(colorName.substring(1)); - } - else if (colorName.startsWith("co@") || colorName.lastIndexOf(',') > colorName.indexOf(',')) { - ColorTag color = ColorTag.valueOf(colorName, attribute.context); - if (color == null && TagManager.isStaticParsing) { - return null; - } - String hex = Integer.toHexString(color.asRGB()); - colorOut = FormattedTextHelper.stringifyRGBSpigot(hex); - } - if (colorOut == null) { - try { - ChatColor color = ChatColor.valueOf(CoreUtilities.toUpperCase(colorName)); - colorOut = color.toString(); - } - catch (IllegalArgumentException ex) { - attribute.echoError("Color '" + colorName + "' doesn't exist (for tag &color[...])."); - return null; - } - } - return new ElementTag(colorOut); - }); - - // <--[tag] - // @attribute <&gradient[from=;to=;(style={RGB}/HSB)]> - // @returns ElementTag - // @description - // Returns a chat code that makes the following text be the specified color. - // Input works equivalently to <@link tag ElementTag.color_gradient>, return to that tag for more documentation detail and input examples. - // The gradient runs from whatever text is after this gradient, until the next color tag (0-9, a-f, 'r' reset, or an RGB code. Does not get stop at formatting codes, they will be included in the gradient). - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // @example - // - narrate "<&gradient[from=black;to=white]>these are the shades of gray that solidifies to pure white" - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, MapTag.class, "&gradient", (attribute, inputMap) -> { - ColorTag fromColor = inputMap.getRequiredObjectAs("from", ColorTag.class, attribute); - ColorTag toColor = inputMap.getRequiredObjectAs("to", ColorTag.class, attribute); - ElementTag style = inputMap.getElement("style", "RGB"); - if (fromColor == null || toColor == null) { - return null; - } - if (!style.matchesEnum(BukkitElementExtensions.GradientStyle.class)) { - attribute.echoError("Invalid gradient style '" + style + "'"); - return null; - } - return new ElementTag(ChatColor.COLOR_CHAR + "[gradient=" + fromColor + ";" + toColor + ";" + style + "]"); - }); - - // <--[tag] - // @attribute <&font[]> - // @returns ElementTag - // @description - // Returns a chat code that makes the following text display with the specified font. - // The default font is "minecraft:default". - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&font", (attribute) -> { - if (!attribute.hasParam()) { - return null; - } - return new ElementTag(ChatColor.COLOR_CHAR + "[font=" + attribute.getParam() + "]"); - }); - - // <--[tag] - // @attribute <&optimize> - // @returns ElementTag - // @description - // Returns a chat code that tells the formatted text parser to try to produce mininalist JSON text. - // This is useful in particular for very long text or where text is being sent rapidly/repeatedly. - // It is not needed in most normal messages. - // It will produce incompatibility issues if used in items or other locations where raw JSON matching is required. - // Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>. - // --> - TagManager.registerStaticTagBaseHandler(ElementTag.class, "&optimize", (attribute) -> { - return new ElementTag(ChatColor.COLOR_CHAR + "[optimize=true]", true); - }); - // <--[tag] // @attribute <&0> // @returns ElementTag diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/HoverFormatHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/HoverFormatHelper.java deleted file mode 100644 index 3f71572930..0000000000 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/HoverFormatHelper.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.denizenscript.denizen.utilities; - -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.NMSVersion; -import com.denizenscript.denizen.objects.EntityTag; -import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.core.MapTag; -import com.denizenscript.denizencore.tags.Attribute; -import com.denizenscript.denizencore.utilities.CoreUtilities; -import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; -import com.google.gson.*; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.hover.content.*; -import net.md_5.bungee.chat.ChatVersion; -import net.md_5.bungee.chat.ComponentSerializer; -import net.md_5.bungee.chat.VersionedComponentSerializer; -import org.bukkit.Bukkit; -import org.bukkit.Registry; -import org.bukkit.inventory.ItemStack; - -import java.lang.reflect.Type; -import java.util.UUID; - -public class HoverFormatHelper { - - public static boolean processHoverInput(HoverEvent.Action action, TextComponent hoverableText, String input) { - Content content; - if (action == HoverEvent.Action.SHOW_ITEM) { - ItemTag item = ItemTag.valueOf(FormattedTextHelper.unescape(input), CoreUtilities.noDebugContext); - if (item == null) { - return true; - } - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { - content = new FixedItemHover(item.getBukkitMaterial().getKey().toString(), item.getAmount(), NMSHandler.itemHelper.getRawHoverComponentsJson(item.getItemStack())); - } - else { - content = new Item(item.getBukkitMaterial().getKey().toString(), item.getAmount(), net.md_5.bungee.api.chat.ItemTag.ofNbt(NMSHandler.itemHelper.getLegacyHoverNbt(item))); - } - } - else if (action == HoverEvent.Action.SHOW_ENTITY) { - String rawInput = FormattedTextHelper.unescape(input); - if (!rawInput.startsWith("map@")) { - content = parseLegacyEntityHover(rawInput); - if (content == null) { - return true; - } - } - else { - MapTag entityHoverData = MapTag.valueOf(rawInput, CoreUtilities.noDebugContext); - if (entityHoverData == null) { - return true; - } - ElementTag uuid = entityHoverData.getElement("uuid"); - if (uuid == null) { - return true; - } - ElementTag type = entityHoverData.getElement("type"); - ElementTag rawName = entityHoverData.getElement("name"); - BaseComponent name = rawName != null ? new TextComponent(FormattedTextHelper.parse(rawName.asString(), ChatColor.WHITE)) : null; - content = new Entity(type != null ? type.asString() : null, uuid.asString(), name); - } - } - else { - content = new Text(FormattedTextHelper.parse(FormattedTextHelper.unescape(input), ChatColor.WHITE)); - } - hoverableText.setHoverEvent(new HoverEvent(action, content)); - return false; - } - - public static String stringForHover(HoverEvent hover) { - if (hover.getContents().isEmpty()) { - return ""; - } - Content contentObject = hover.getContents().get(0); - if (contentObject instanceof Text textHover) { - Object value = textHover.getValue(); - if (value instanceof BaseComponent[] componentsValue) { - return FormattedTextHelper.stringify(componentsValue); - } - else { - return value.toString(); - } - } - else if (contentObject instanceof Item itemHover) { - ItemStack item = new ItemStack(Registry.MATERIAL.get(Utilities.parseNamespacedKey(itemHover.getId())), itemHover.getCount() == -1 ? 1 : itemHover.getCount()); - if (itemHover instanceof FixedItemHover fixedItemHover && fixedItemHover.getComponents() != null) { - item = NMSHandler.itemHelper.applyRawHoverComponentsJson(item, fixedItemHover.getComponents()); - } - else if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19) && itemHover.getTag() != null && itemHover.getTag().getNbt() != null) { - item = Bukkit.getUnsafe().modifyItemStack(item, itemHover.getTag().getNbt()); - } - return new ItemTag(item).identify(); - } - else if (contentObject instanceof Entity entityHover) { - return createEntityHoverData(entityHover.getId(), entityHover.getType(), entityHover.getName()).savable(); - } - else { - throw new UnsupportedOperationException(); - } - } - - public static MapTag createEntityHoverData(String uuid, String type, BaseComponent name) { - MapTag entityHoverData = new MapTag(); - entityHoverData.putObject("uuid", new ElementTag(uuid, true)); - if (type != null) { - entityHoverData.putObject("type", new ElementTag(type, true)); - } - else { - try { - // This isn't even optional, but is in Bungee for some reason - try our best to have a value - org.bukkit.entity.Entity found = EntityTag.getEntityForID(UUID.fromString(uuid)); - if (found != null) { - entityHoverData.putObject("type", new ElementTag(found.getType().getKey().toString(), true)); - } - } - catch (IllegalArgumentException ignore) {} - } - if (name != null) { - entityHoverData.putObject("name", new ElementTag(FormattedTextHelper.stringify(name), true)); - } - return entityHoverData; - } - - public static String parseObjectToHover(ObjectTag object, HoverEvent.Action action, Attribute attribute) { - return switch (action) { - case SHOW_ENTITY -> { - EntityTag toShow = object.asType(EntityTag.class, attribute.context); - if (toShow == null) { - attribute.echoError("Invalid hover object '" + object + "' specified for type 'SHOW_ENTITY': must be an EntityTag."); - yield null; - } - BaseComponent[] customName = PaperAPITools.instance.getCustomNameComponent(toShow.getBukkitEntity()); - yield createEntityHoverData(toShow.getUUID().toString(), toShow.getBukkitEntityType().getKey().toString(), customName != null ? new TextComponent(customName) : null).savable(); - } - case SHOW_ITEM -> { - ItemTag toShow = object.asType(ItemTag.class, attribute.context); - if (toShow == null) { - attribute.echoError("Invalid hover object '" + object + "' specified for type 'SHOW_ITEM': must be an ItemTag."); - yield null; - } - yield toShow.identify(); - } - case SHOW_TEXT -> object.toString(); - default -> { - attribute.echoError("Using unsupported hover type: " + action + '.'); - yield null; - } - }; - } - - private static Entity parseLegacyEntityHover(String input) { - EntityTag entity = EntityTag.valueOf(input, CoreUtilities.basicContext); - if (entity == null) { - return null; - } - BaseComponent name = null; - if (entity.getBukkitEntity() != null && entity.getBukkitEntity().isCustomNameVisible()) { - name = new TextComponent(); - for (BaseComponent component : FormattedTextHelper.parse(entity.getBukkitEntity().getCustomName(), ChatColor.WHITE)) { - name.addExtra(component); - } - } - return new Entity(entity.getBukkitEntityType().getKey().toString(), entity.getUUID().toString(), name); - } - - public static void tryInitializeItemHoverFix() { - if (!NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { - return; - } - Gson bungeeGson = FormattedTextHelper.getBungeeGson(); - if (bungeeGson == null) { - return; - } - Gson fixedGson = bungeeGson.newBuilder() - .registerTypeAdapter(FixedItemHover.class, new FixedItemHoverSerializer()) - .registerTypeAdapter(Item.class, new FixedItemHoverSerializer()) - .create(); - try { - if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_21)) { - ReflectionHelper.setFieldValue(VersionedComponentSerializer.class, "gson", VersionedComponentSerializer.forVersion(ChatVersion.V1_21_5), fixedGson); - } - else { - ReflectionHelper.getFinalSetter(ComponentSerializer.class, "gson").invoke(fixedGson); - } - } - catch (Throwable e) { - Debug.echoError(e); - } - } - - public static class FixedItemHover extends Item { - - private final JsonObject components; - - public FixedItemHover(String id, int count, JsonObject components) { - super(id, count, null); - this.components = components; - } - - public JsonObject getComponents() { - return components; - } - } - - public static class FixedItemHoverSerializer extends ItemSerializer { - - @Override - public Item deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException { - Item deserialized = super.deserialize(element, type, context); - if (deserialized.getTag() != null) { - return deserialized; - } - JsonObject componentsObject = element.getAsJsonObject().getAsJsonObject("components"); - if (componentsObject == null) { - return deserialized; - } - return new FixedItemHover(deserialized.getId(), deserialized.getCount(), componentsObject); - } - - @Override - public JsonElement serialize(Item content, Type type, JsonSerializationContext context) { - JsonElement serialized = super.serialize(content, type, context); - if (!(content instanceof FixedItemHover fixedItemHover) || fixedItemHover.getComponents() == null) { - return serialized; - } - JsonObject serializedObject = serialized.getAsJsonObject(); - serializedObject.remove("tag"); - serializedObject.add("components", fixedItemHover.getComponents()); - return serializedObject; - } - } -} diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 2625cc5ced..13206b05f7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -5,9 +5,16 @@ import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; +import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ChatVersion; +import net.md_5.bungee.chat.ComponentSerializer; +import net.md_5.bungee.chat.VersionedComponentSerializer; import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; @@ -20,13 +27,16 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.*; +import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.scoreboard.Team; import org.bukkit.util.Consumer; import java.lang.invoke.MethodHandle; +import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.function.Predicate; public class PaperAPITools { @@ -45,14 +55,14 @@ public String parseComponent(Object input) { if (input == null) { return null; } - if (input instanceof String) { - return (String) input; + if (input instanceof String str) { + return str; } - else if (input instanceof BaseComponent[]) { - return FormattedTextHelper.stringify((BaseComponent[]) input); + else if (input instanceof BaseComponent[] components) { + return components.length == 1 ? components[0].toLegacyText() : new TextComponent(components).toLegacyText(); } - else if (input instanceof BaseComponent) { - return FormattedTextHelper.stringify((BaseComponent) input); + else if (input instanceof BaseComponent component) { + return component.toLegacyText(); } else { return input.toString(); @@ -71,11 +81,6 @@ public String getCustomName(Entity entity) { return entity.getCustomName(); } - public BaseComponent[] getCustomNameComponent(Entity entity) { - String customName = entity.getCustomName(); - return customName != null ? FormattedTextHelper.parseSimpleColorsOnly(customName) : null; - } - public void setPlayerListName(Player player, String name) { player.setPlayerListName(name); } @@ -112,10 +117,6 @@ public void setCustomName(Nameable object, String name) { object.setCustomName(name); } - public void sendConsoleMessage(CommandSender sender, String text) { - sender.spigot().sendMessage(FormattedTextHelper.parse(text, net.md_5.bungee.api.ChatColor.WHITE)); - } - public InventoryView openAnvil(Player player, Location loc) { throw new UnsupportedOperationException(); } @@ -233,4 +234,87 @@ public boolean hasCustomName(PotionMeta meta) { public void setMaterialTags(Material type, Set tags) { NMSHandler.blockHelper.setVanillaTags(type, tags); } + + public String getPage(BookMeta meta, int page) { + return meta.getPage(page); + } + + public ListTag getPages(BookMeta meta) { + return new ListTag(meta.getPages()); + } + + public void addPage(BookMeta meta, String page) { + meta.addPage(page); + } + + public void setPages(BookMeta meta, List pages) { + meta.setPages(pages); + } + + public void setJsonPages(BookMeta meta, List jsonPages) { + List parsedPages = new ArrayList<>(jsonPages.size()); + for (String jsonPage : jsonPages) { + parsedPages.add(jsonToBungee(jsonPage)); + } + meta.spigot().setPages(parsedPages); + } + + public void sendMessage(CommandSender sender, String text) { + sender.sendMessage(text); + } + + public void sendMessage(CommandSender sender, String text, UUID senderId) { + sender.sendMessage(senderId, text); + } + + public void broadcast(String text, Predicate filter) { + for (Player player : Bukkit.getOnlinePlayers()) { + if (filter == null || filter.test(player)) { + player.sendMessage(text); + } + } + } + + public void sendActionBar(Player player, String text) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacy(text)); + } + + public enum BaseColor { WHITE, BLACK, GRAY, DARK_GRAY } + + public String parseTextToJson(String formattedText, BaseColor baseColor) { + TextComponent textComponent = new TextComponent(formattedText); + textComponent.setBold(false); + textComponent.setItalic(false); + textComponent.setStrikethrough(false); + textComponent.setUnderlined(false); + textComponent.setObfuscated(false); + textComponent.setColor(switch (baseColor) { + case WHITE -> ChatColor.WHITE; + case BLACK -> ChatColor.BLACK; + case GRAY -> ChatColor.GRAY; + case DARK_GRAY -> ChatColor.DARK_GRAY; + }); + TextComponent base = new TextComponent(); + base.addExtra(textComponent); + return bungeeToJson(base); + } + + public String parseJsonToText(String json) { + BaseComponent[] components = jsonToBungee(json); + return components.length == 1 ? components[0].toLegacyText() : new TextComponent(components).toLegacyText(); + } + + protected String bungeeToJson(BaseComponent component) { + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_20)) { + return ComponentSerializer.toString(component); + } + return VersionedComponentSerializer.forVersion(ChatVersion.V1_21_5).toString(component); + } + + protected BaseComponent[] jsonToBungee(String json) { + if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_20)) { + return ComponentSerializer.parse(json); + } + return VersionedComponentSerializer.forVersion(ChatVersion.V1_21_5).parse(json); + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExCommandHandler.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExCommandHandler.java index 2714009df1..9dcee43564 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExCommandHandler.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExCommandHandler.java @@ -3,7 +3,7 @@ import com.denizenscript.denizen.objects.NPCTag; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.tags.BukkitTagContext; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.depends.Depends; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; @@ -94,7 +94,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String alias, String List scriptEntries = ScriptBuilder.buildScriptEntries(entries, null, new BukkitScriptEntryData(sender instanceof Player player ? new PlayerTag(player) : null, npc)); queue.addEntries(scriptEntries); if (!quiet && sender instanceof Player) { - queue.debugOutput = s -> sender.spigot().sendMessage(FormattedTextHelper.parse(s.replace("", ""), net.md_5.bungee.api.ChatColor.WHITE)); + queue.debugOutput = s -> PaperAPITools.instance.sendMessage(sender, s.replace("", "")); } queue.start(); return true; diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExSustainedCommandHandler.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExSustainedCommandHandler.java index bf5bdf8c60..b9aed1c7c6 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExSustainedCommandHandler.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/command/ExSustainedCommandHandler.java @@ -3,7 +3,7 @@ import com.denizenscript.denizen.Denizen; import com.denizenscript.denizen.objects.NPCTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.depends.Depends; import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; @@ -72,7 +72,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String alias, String } TimedQueue queue = getOrMakeQueue(sender instanceof Player player ? player : null, quiet); if (!quiet && sender instanceof Player) { - queue.debugOutput = s -> sender.spigot().sendMessage(FormattedTextHelper.parse(s.replace("", ""), net.md_5.bungee.api.ChatColor.WHITE)); + queue.debugOutput = s -> PaperAPITools.instance.sendMessage(sender, s.replace("", "")); } else { queue.debugOutput = null; diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/DebugConsoleSender.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/DebugConsoleSender.java index 236119899f..b36d238a48 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/DebugConsoleSender.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/debugging/DebugConsoleSender.java @@ -19,7 +19,7 @@ public static void sendMessage(String string) { // "[HH:mm:ss INFO]: " string = CoreConfiguration.debugPrefix + string.replace("", " "); if (showColor) { - PaperAPITools.instance.sendConsoleMessage(commandSender, string); + PaperAPITools.instance.sendMessage(commandSender, string); } else { commandSender.sendMessage(ChatColor.stripColor(string)); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/DenizenPacketHandler.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/DenizenPacketHandler.java index 04493160b0..dcf796c677 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/DenizenPacketHandler.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/packets/DenizenPacketHandler.java @@ -113,8 +113,8 @@ public PlayerReceivesMessageScriptEvent sendPacket(final Player player, final Pa if (event.loaded) { Callable eventCall = () -> { event.reset(); - event.message = new ElementTag(chat.getMessage()); - event.rawJson = new ElementTag(chat.getRawJson()); + event.message = new ElementTag(chat.getMessage(), true); + event.rawJson = new ElementTag(chat.getRawJson(), true); event.system = new ElementTag(chat.isSystem()); event.player = PlayerTag.mirrorBukkitPlayer(player); return event.triggerNow(); diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/Handler.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/Handler.java index de970ac638..e2df45a86c 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/Handler.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/Handler.java @@ -11,6 +11,7 @@ import com.denizenscript.denizen.nms.v1_17.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v1_17.impl.SidebarImpl; import com.denizenscript.denizen.nms.v1_17.impl.blocks.BlockLightImpl; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; @@ -18,8 +19,6 @@ import com.google.common.collect.Iterables; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.Registry; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.StringTag; @@ -271,13 +270,17 @@ else if (base instanceof ByteArrayTag) { return null; } - public static BaseComponent[] componentToSpigot(Component nms) { - String json = Component.Serializer.toJson(nms); - return ComponentSerializer.parse(json); + public static String stringifyNMSComponent(Component nms) { + if (nms == null) { + return null; + } + return PaperAPITools.instance.parseJsonToText(Component.Serializer.toJson(nms)); } - public static MutableComponent componentToNMS(BaseComponent[] spigot) { - String json = ComponentSerializer.toString(spigot); - return Component.Serializer.fromJson(json); + public static MutableComponent parseNMSComponent(String formattedText, PaperAPITools.BaseColor baseColor) { + if (formattedText == null) { + return null; + } + return Component.Serializer.fromJson(PaperAPITools.instance.parseTextToJson(formattedText, baseColor)); } } diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/AdvancementHelperImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/AdvancementHelperImpl.java index b717f9db6c..bd3a7fe51b 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/AdvancementHelperImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/AdvancementHelperImpl.java @@ -1,11 +1,10 @@ package com.denizenscript.denizen.nms.v1_17.helpers; import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; +import com.denizenscript.denizen.nms.v1_17.Handler; import com.denizenscript.denizen.nms.v1_17.ReflectionMappingsInfo; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizen.nms.v1_17.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.ImpossibleTrigger; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; @@ -178,7 +177,7 @@ private static Advancement asNMSCopy(com.denizenscript.denizen.nms.util.Advancem ? getAdvancementDataWorld().advancements.advancements.get(asResourceLocation(advancement.parent)) : null; DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), - Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)), + Handler.parseNMSComponent(advancement.title, PaperAPITools.BaseColor.WHITE), Handler.parseNMSComponent(advancement.description, PaperAPITools.BaseColor.WHITE), asResourceLocation(advancement.background), FrameType.valueOf(advancement.frame.name()), advancement.toast, advancement.announceToChat, advancement.hidden); display.setLocation(advancement.xOffset, advancement.yOffset); diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/EnchantmentHelperImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/EnchantmentHelperImpl.java index be378e2c3d..76edb98920 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/EnchantmentHelperImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/EnchantmentHelperImpl.java @@ -3,9 +3,8 @@ import com.denizenscript.denizen.nms.interfaces.EnchantmentHelper; import com.denizenscript.denizen.nms.v1_17.Handler; import com.denizenscript.denizen.scripts.containers.core.EnchantmentScriptContainer; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -92,7 +91,7 @@ public String getDescriptionId() { } @Override public Component getFullname(int level) { - return Handler.componentToNMS(script.script.getFullName(level)); + return Component.Serializer.fromJson(script.script.getFullName(level)); } @Override public boolean canEnchant(net.minecraft.world.item.ItemStack var0) { @@ -174,7 +173,7 @@ public int getMaxCost(Enchantment enchantment, int level) { @Override public String getFullName(Enchantment enchantment, int level) { - return FormattedTextHelper.stringify(Handler.componentToSpigot(((CraftEnchantment) enchantment).getHandle().getFullname(level))); + return Handler.stringifyNMSComponent(((CraftEnchantment) enchantment).getHandle().getFullname(level)); } @Override diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/ItemHelperImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/ItemHelperImpl.java index b5aa9388e6..47d9bc1c9a 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/ItemHelperImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/ItemHelperImpl.java @@ -4,7 +4,7 @@ import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_17.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.collect.Iterables; @@ -15,9 +15,6 @@ import com.mojang.authlib.properties.Property; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; @@ -164,15 +161,6 @@ public String getJsonString(ItemStack itemStack) { return json.substring(176, json.length() - 185); } - @Override - public String getLegacyHoverNbt(ItemTag item) { - net.minecraft.nbt.CompoundTag tag = CraftItemStack.asNMSCopy(item.getItemStack()).getTag(); - if (tag == null) { - return null; - } - return tag.toString(); - } - @Override public PlayerProfile getSkullSkin(ItemStack is) { net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(is); @@ -250,8 +238,7 @@ public String getDisplayName(ItemTag item) { } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); String jsonText = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getString("Name"); - BaseComponent[] nameComponent = ComponentSerializer.parse(jsonText); - return FormattedTextHelper.stringify(nameComponent); + return PaperAPITools.instance.parseJsonToText(jsonText); } @Override @@ -263,8 +250,7 @@ public List getLore(ItemTag item) { ListTag list = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getList("Lore", 8); List outList = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { - BaseComponent[] lineComponent = ComponentSerializer.parse(list.getString(i)); - outList.add(FormattedTextHelper.stringify(lineComponent)); + outList.add(PaperAPITools.instance.parseJsonToText(list.getString(i))); } return outList; } @@ -281,8 +267,7 @@ public void setDisplayName(ItemTag item, String name) { display.put("Name", null); return; } - BaseComponent[] components = FormattedTextHelper.parse(name, ChatColor.WHITE); - display.put("Name", net.minecraft.nbt.StringTag.valueOf(ComponentSerializer.toString(components))); + display.put("Name", net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(name, PaperAPITools.BaseColor.WHITE))); item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); } @@ -300,7 +285,7 @@ public void setLore(ItemTag item, List lore) { else { ListTag tagList = new ListTag(); for (String line : lore) { - tagList.add(net.minecraft.nbt.StringTag.valueOf(ComponentSerializer.toString(FormattedTextHelper.parse(line, ChatColor.WHITE)))); + tagList.add(net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(line, PaperAPITools.BaseColor.WHITE))); } display.put("Lore", tagList); } diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PacketHelperImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PacketHelperImpl.java index d4e4143485..7b71d68a56 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PacketHelperImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PacketHelperImpl.java @@ -9,7 +9,7 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizen.utilities.maps.MapImage; @@ -22,7 +22,6 @@ import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.ListBinaryTag; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -224,8 +223,8 @@ public void showBannerUpdate(Player player, Location location, List pat @Override public void showTabListHeaderFooter(Player player, String header, String footer) { - Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); - Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + Component cHeader = Handler.parseNMSComponent(header, PaperAPITools.BaseColor.WHITE); + Component cFooter = Handler.parseNMSComponent(footer, PaperAPITools.BaseColor.WHITE); ClientboundTabListPacket packet = new ClientboundTabListPacket(cHeader, cFooter); send(player, packet); } @@ -234,10 +233,10 @@ public void showTabListHeaderFooter(Player player, String header, String footer) public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); + send(player, new ClientboundSetTitleTextPacket(Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE))); } if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); + send(player, new ClientboundSetSubtitleTextPacket(Handler.parseNMSComponent(subtitle, PaperAPITools.BaseColor.WHITE))); } } @@ -342,7 +341,7 @@ public void sendRename(Player player, Entity entity, String name, boolean listMo SynchedEntityData fakeData = new SynchedEntityData(((CraftEntity) entity).getHandle()); ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entity.getEntityId(), fakeData, false); List> list = new ArrayList<>(); - list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_METADATA, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))))); + list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_METADATA, Optional.of(Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE)))); list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_VISIBLE_METADATA, true)); ENTITY_METADATA_LIST_SETTER.invoke(packet, list); send(player, packet); diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PlayerHelperImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PlayerHelperImpl.java index 5ff8967e98..1255f9ad3c 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PlayerHelperImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/helpers/PlayerHelperImpl.java @@ -15,14 +15,13 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.entity.DenizenEntityType; import com.denizenscript.denizen.utilities.entity.FakeEntity; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.protocol.game.*; import net.minecraft.network.syncher.EntityDataAccessor; @@ -348,7 +347,7 @@ public void setSkinLayers(Player player, byte flags) { @Override public void setBossBarTitle(BossBar bar, String title) { - ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().name = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); } diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/ProfileEditorImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/ProfileEditorImpl.java index f0438b1c45..6ba0bbdc4d 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/ProfileEditorImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/ProfileEditorImpl.java @@ -1,24 +1,23 @@ package com.denizenscript.denizen.nms.v1_17.impl; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ProfileEditor; +import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_17.Handler; import com.denizenscript.denizen.nms.v1_17.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_17.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.util.PlayerProfile; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket; import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; @@ -104,7 +103,7 @@ public static boolean handleAlteredProfiles(ClientboundPlayerInfoPacket packet, patchedProfile.getProperties().putAll(data.getProfile().getProperties()); } String listRename = RenameCommand.getCustomNameFor(data.getProfile().getId(), manager.player.getBukkitEntity(), true); - Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : data.getDisplayName(); + Component displayName = listRename != null ? Handler.parseNMSComponent(listRename, PaperAPITools.BaseColor.WHITE) : data.getDisplayName(); ClientboundPlayerInfoPacket.PlayerUpdate newData = new ClientboundPlayerInfoPacket.PlayerUpdate(patchedProfile, data.getLatency(), data.getGameMode(), displayName); newPacketDataList.add(newData); manager.oldManager.send(newPacket); diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/SidebarImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/SidebarImpl.java index 8c0dc6356a..c4fadc7aca 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/SidebarImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/SidebarImpl.java @@ -1,12 +1,11 @@ package com.denizenscript.denizen.nms.v1_17.impl; +import com.denizenscript.denizen.nms.abstracts.Sidebar; import com.denizenscript.denizen.nms.v1_17.Handler; import com.denizenscript.denizen.nms.v1_17.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.abstracts.Sidebar; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; @@ -44,7 +43,7 @@ public class SidebarImpl extends Sidebar { public SidebarImpl(Player player) { super(player); - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); } @@ -52,7 +51,7 @@ public SidebarImpl(Player player) { @Override protected void setDisplayName(String title) { if (this.obj1 != null) { - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1.setDisplayName(chatComponentTitle); this.obj2.setDisplayName(chatComponentTitle); } @@ -73,7 +72,7 @@ public void sendUpdate() { String lineId = Utilities.generateRandomColors(8); PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); team.getPlayers().add(lineId); - team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + team.setPlayerPrefix(Handler.parseNMSComponent(line, PaperAPITools.BaseColor.WHITE)); generatedTeams.add(team); PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); PacketHelperImpl.send(player, new ClientboundSetScorePacket(ServerScoreboard.Method.CHANGE, obj1.getName(), lineId, this.scores[i])); diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/handlers/DenizenNetworkManagerImpl.java index 4f948d0b87..bbb1fe1a41 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -3,20 +3,21 @@ import com.denizenscript.denizen.events.player.PlayerHearsSoundScriptEvent; import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; import com.denizenscript.denizen.events.player.PlayerReceivesMessageScriptEvent; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.BlockLight; import com.denizenscript.denizen.nms.v1_17.Handler; import com.denizenscript.denizen.nms.v1_17.ReflectionMappingsInfo; import com.denizenscript.denizen.nms.v1_17.impl.ProfileEditorImpl; -import com.denizenscript.denizen.nms.v1_17.impl.network.packets.*; import com.denizenscript.denizen.nms.v1_17.impl.blocks.BlockLightImpl; import com.denizenscript.denizen.nms.v1_17.impl.entities.EntityFakePlayerImpl; +import com.denizenscript.denizen.nms.v1_17.impl.network.packets.PacketOutChatImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.scripts.commands.entity.FakeEquipCommand; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.scripts.commands.entity.SneakCommand; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; @@ -26,16 +27,13 @@ import com.denizenscript.denizen.utilities.packets.HideParticles; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.utilities.CoreConfiguration; +import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.datafixers.util.Pair; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.core.SectionPos; @@ -271,10 +269,10 @@ public boolean processActionbarPacket(Packet packet, GenericFutureListener packet, GenericFutureListener name = Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))); + Optional name = Optional.of(Handler.parseNMSComponent(nameToApply, PaperAPITools.BaseColor.WHITE)); data.set(i, new SynchedEntityData.DataItem(watcherObject, name)); any = true; } @@ -949,7 +946,7 @@ public boolean processPacketHandlerForPacket(Packet packet) { return true; } if (result.modified) { - packetHelper.setRawJson(ComponentSerializer.toString(result.altMessageDetermination)); + packetHelper.setRawJson(result.rawJson.asString()); } } } diff --git a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/packets/PacketOutChatImpl.java b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/packets/PacketOutChatImpl.java index e4ff599738..3a0407168c 100644 --- a/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/packets/PacketOutChatImpl.java +++ b/v1_17/src/main/java/com/denizenscript/denizen/nms/v1_17/impl/network/packets/PacketOutChatImpl.java @@ -1,9 +1,8 @@ package com.denizenscript.denizen.nms.v1_17.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizen.nms.v1_17.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.chat.ChatType; @@ -25,13 +24,13 @@ public PacketOutChatImpl(ClientboundChatPacket internal) { try { Component baseComponent = (Component) MESSAGE.get(internal); if (baseComponent != null) { - message = FormattedTextHelper.stringify(Handler.componentToSpigot(baseComponent)); rawJson = Component.Serializer.toJson(baseComponent); + message = PaperAPITools.instance.parseJsonToText(rawJson); } else { if (internal.components != null) { - message = FormattedTextHelper.stringify(internal.components); rawJson = ComponentSerializer.toString(internal.components); + message = PaperAPITools.instance.parseJsonToText(rawJson); } bungee = true; } diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/Handler.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/Handler.java index 8d45840736..ff22d85099 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/Handler.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/Handler.java @@ -12,7 +12,6 @@ import com.denizenscript.denizen.nms.v1_18.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v1_18.impl.SidebarImpl; import com.denizenscript.denizen.nms.v1_18.impl.blocks.BlockLightImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -21,9 +20,6 @@ import com.google.common.collect.Iterables; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.nbt.ByteArrayTag; @@ -193,7 +189,7 @@ else if (MINECRAFT_INVENTORY.isInstance(nms)) { public void setInventoryTitle(InventoryView view, String title) { AbstractContainerMenu menu = ((CraftInventoryView) view).getHandle(); try { - AbstractContainerMenu_title_SETTER.invoke(menu, componentToNMS(FormattedTextHelper.parse(title, ChatColor.DARK_GRAY))); + AbstractContainerMenu_title_SETTER.invoke(menu, parseNMSComponent(title, PaperAPITools.BaseColor.DARK_GRAY)); } catch (Throwable ex) { Debug.echoError(ex); @@ -295,19 +291,17 @@ else if (base instanceof ByteArrayTag) { return null; } - public static BaseComponent[] componentToSpigot(Component nms) { + public static String stringifyNMSComponent(Component nms) { if (nms == null) { return null; } - String json = Component.Serializer.toJson(nms); - return ComponentSerializer.parse(json); + return PaperAPITools.instance.parseJsonToText(Component.Serializer.toJson(nms)); } - public static MutableComponent componentToNMS(BaseComponent[] spigot) { - if (spigot == null) { + public static MutableComponent parseNMSComponent(String formattedText, PaperAPITools.BaseColor baseColor) { + if (formattedText == null) { return null; } - String json = ComponentSerializer.toString(spigot); - return Component.Serializer.fromJson(json); + return Component.Serializer.fromJson(PaperAPITools.instance.parseTextToJson(formattedText, baseColor)); } } diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/AdvancementHelperImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/AdvancementHelperImpl.java index 2b312a5912..71d83c16d4 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/AdvancementHelperImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/AdvancementHelperImpl.java @@ -1,11 +1,10 @@ package com.denizenscript.denizen.nms.v1_18.helpers; import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; +import com.denizenscript.denizen.nms.v1_18.Handler; import com.denizenscript.denizen.nms.v1_18.ReflectionMappingsInfo; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizen.nms.v1_18.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.ImpossibleTrigger; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; @@ -178,7 +177,7 @@ private static Advancement asNMSCopy(com.denizenscript.denizen.nms.util.Advancem ? getAdvancementDataWorld().advancements.advancements.get(asResourceLocation(advancement.parent)) : null; DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), - Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)), + Handler.parseNMSComponent(advancement.title, PaperAPITools.BaseColor.WHITE), Handler.parseNMSComponent(advancement.description, PaperAPITools.BaseColor.WHITE), asResourceLocation(advancement.background), FrameType.valueOf(advancement.frame.name()), advancement.toast, advancement.announceToChat, advancement.hidden); display.setLocation(advancement.xOffset, advancement.yOffset); diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/EnchantmentHelperImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/EnchantmentHelperImpl.java index 6fa2f7d5f2..30d0039d4d 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/EnchantmentHelperImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/EnchantmentHelperImpl.java @@ -4,9 +4,8 @@ import com.denizenscript.denizen.nms.v1_18.Handler; import com.denizenscript.denizen.nms.v1_18.ReflectionMappingsInfo; import com.denizenscript.denizen.scripts.containers.core.EnchantmentScriptContainer; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; @@ -96,7 +95,7 @@ public String getDescriptionId() { } @Override public Component getFullname(int level) { - return Handler.componentToNMS(script.script.getFullName(level)); + return Component.Serializer.fromJson(script.script.getFullName(level)); } @Override public boolean canEnchant(net.minecraft.world.item.ItemStack var0) { @@ -183,7 +182,7 @@ public int getMaxCost(Enchantment enchantment, int level) { @Override public String getFullName(Enchantment enchantment, int level) { - return FormattedTextHelper.stringify(Handler.componentToSpigot(((CraftEnchantment) enchantment).getHandle().getFullname(level))); + return Handler.stringifyNMSComponent(((CraftEnchantment) enchantment).getHandle().getFullname(level)); } @Override diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/ItemHelperImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/ItemHelperImpl.java index 86470a16c0..6c21ebbab9 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/ItemHelperImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/ItemHelperImpl.java @@ -4,7 +4,7 @@ import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_18.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.collect.*; @@ -13,9 +13,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; @@ -248,8 +245,7 @@ public String getDisplayName(ItemTag item) { } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); String jsonText = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getString("Name"); - BaseComponent[] nameComponent = ComponentSerializer.parse(jsonText); - return FormattedTextHelper.stringify(nameComponent); + return PaperAPITools.instance.parseJsonToText(jsonText); } @Override @@ -261,8 +257,7 @@ public List getLore(ItemTag item) { ListTag list = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getList("Lore", 8); List outList = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { - BaseComponent[] lineComponent = ComponentSerializer.parse(list.getString(i)); - outList.add(FormattedTextHelper.stringify(lineComponent)); + outList.add(PaperAPITools.instance.parseJsonToText(list.getString(i))); } return outList; } @@ -279,8 +274,7 @@ public void setDisplayName(ItemTag item, String name) { display.put("Name", null); return; } - BaseComponent[] components = FormattedTextHelper.parse(name, ChatColor.WHITE); - display.put("Name", net.minecraft.nbt.StringTag.valueOf(ComponentSerializer.toString(components))); + display.put("Name", net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(name, PaperAPITools.BaseColor.WHITE))); item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); } @@ -298,7 +292,7 @@ public void setLore(ItemTag item, List lore) { else { ListTag tagList = new ListTag(); for (String line : lore) { - tagList.add(net.minecraft.nbt.StringTag.valueOf(ComponentSerializer.toString(FormattedTextHelper.parse(line, ChatColor.WHITE)))); + tagList.add(net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(line, PaperAPITools.BaseColor.WHITE))); } display.put("Lore", tagList); } diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PacketHelperImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PacketHelperImpl.java index eb2c1f71c3..7b828f249b 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PacketHelperImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PacketHelperImpl.java @@ -9,7 +9,7 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizen.utilities.maps.MapImage; @@ -22,7 +22,6 @@ import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.ListBinaryTag; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -203,8 +202,8 @@ public void showBannerUpdate(Player player, Location location, List pat @Override public void showTabListHeaderFooter(Player player, String header, String footer) { - Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); - Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + Component cHeader = Handler.parseNMSComponent(header, PaperAPITools.BaseColor.WHITE); + Component cFooter = Handler.parseNMSComponent(footer, PaperAPITools.BaseColor.WHITE); ClientboundTabListPacket packet = new ClientboundTabListPacket(cHeader, cFooter); send(player, packet); } @@ -213,10 +212,10 @@ public void showTabListHeaderFooter(Player player, String header, String footer) public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); + send(player, new ClientboundSetTitleTextPacket(Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE))); } if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); + send(player, new ClientboundSetSubtitleTextPacket(Handler.parseNMSComponent(subtitle, PaperAPITools.BaseColor.WHITE))); } } @@ -305,7 +304,7 @@ public void sendRename(Player player, Entity entity, String name, boolean listMo SynchedEntityData fakeData = new SynchedEntityData(((CraftEntity) entity).getHandle()); ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entity.getEntityId(), fakeData, false); List> list = new ArrayList<>(); - list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_METADATA, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))))); + list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_METADATA, Optional.of(Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE)))); list.add(new SynchedEntityData.DataItem<>(ENTITY_CUSTOM_NAME_VISIBLE_METADATA, true)); ENTITY_METADATA_LIST_SETTER.invoke(packet, list); send(player, packet); diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PlayerHelperImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PlayerHelperImpl.java index 566afc4032..f1e4e99ee5 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PlayerHelperImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/helpers/PlayerHelperImpl.java @@ -16,7 +16,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.entity.DenizenEntityType; import com.denizenscript.denizen.utilities.entity.FakeEntity; import com.denizenscript.denizencore.objects.Mechanism; @@ -25,7 +25,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.ints.IntList; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.network.protocol.game.*; @@ -365,7 +364,7 @@ public void setSkinLayers(Player player, byte flags) { @Override public void setBossBarTitle(BossBar bar, String title) { - ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().name = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); } @@ -414,7 +413,7 @@ public void sendPlayerInfoAddPacket(Player player, EnumSet edit if (texture != null) { profile.getProperties().put("textures", new Property("textures", texture, signature)); } - packet.getEntries().add(new ClientboundPlayerInfoPacket.PlayerUpdate(profile, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)))); + packet.getEntries().add(new ClientboundPlayerInfoPacket.PlayerUpdate(profile, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.parseNMSComponent(display, PaperAPITools.BaseColor.WHITE))); PacketHelperImpl.send(player, packet); } diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/ProfileEditorImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/ProfileEditorImpl.java index edbc58e63e..7e6eecdb37 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/ProfileEditorImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/ProfileEditorImpl.java @@ -1,22 +1,21 @@ package com.denizenscript.denizen.nms.v1_18.impl; +import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.abstracts.ProfileEditor; +import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_18.Handler; import com.denizenscript.denizen.nms.v1_18.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_18.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.denizenscript.denizen.nms.NMSHandler; -import com.denizenscript.denizen.nms.util.PlayerProfile; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; @@ -89,7 +88,7 @@ public static boolean handleAlteredProfiles(ClientboundPlayerInfoPacket packet, patchedProfile.getProperties().putAll(data.getProfile().getProperties()); } String listRename = RenameCommand.getCustomNameFor(data.getProfile().getId(), manager.player.getBukkitEntity(), true); - Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : data.getDisplayName(); + Component displayName = listRename != null ? Handler.parseNMSComponent(listRename, PaperAPITools.BaseColor.WHITE) : data.getDisplayName(); ClientboundPlayerInfoPacket.PlayerUpdate newData = new ClientboundPlayerInfoPacket.PlayerUpdate(patchedProfile, data.getLatency(), data.getGameMode(), displayName); newPacketDataList.add(newData); manager.oldManager.send(newPacket); diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/SidebarImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/SidebarImpl.java index 767842eae6..b6d26ebf70 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/SidebarImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/SidebarImpl.java @@ -1,12 +1,11 @@ package com.denizenscript.denizen.nms.v1_18.impl; +import com.denizenscript.denizen.nms.abstracts.Sidebar; import com.denizenscript.denizen.nms.v1_18.Handler; import com.denizenscript.denizen.nms.v1_18.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.abstracts.Sidebar; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; @@ -44,7 +43,7 @@ public class SidebarImpl extends Sidebar { public SidebarImpl(Player player) { super(player); - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); } @@ -52,7 +51,7 @@ public SidebarImpl(Player player) { @Override protected void setDisplayName(String title) { if (this.obj1 != null) { - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1.setDisplayName(chatComponentTitle); this.obj2.setDisplayName(chatComponentTitle); } @@ -73,7 +72,7 @@ public void sendUpdate() { String lineId = Utilities.generateRandomColors(8); PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); team.getPlayers().add(lineId); - team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + team.setPlayerPrefix(Handler.parseNMSComponent(line, PaperAPITools.BaseColor.WHITE)); generatedTeams.add(team); PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); PacketHelperImpl.send(player, new ClientboundSetScorePacket(ServerScoreboard.Method.CHANGE, obj1.getName(), lineId, this.scores[i])); diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/handlers/DenizenNetworkManagerImpl.java index 4d830865e1..9e1ea84a79 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -16,7 +16,7 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.scripts.commands.entity.*; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; @@ -37,8 +37,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.core.SectionPos; @@ -350,7 +348,7 @@ public boolean processTablistPacket(Packet packet, GenericFutureListener packet, GenericFutureListener packet, GenericFutureListener packet, GenericFutureListener name = Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))); + Optional name = Optional.of(Handler.parseNMSComponent(nameToApply, PaperAPITools.BaseColor.WHITE)); data.set(i, new SynchedEntityData.DataItem(watcherObject, name)); any = true; } @@ -1118,7 +1115,7 @@ public boolean processPacketHandlerForPacket(Packet packet) { return true; } if (result.modified) { - packetHelper.setRawJson(ComponentSerializer.toString(result.altMessageDetermination)); + packetHelper.setRawJson(result.rawJson.asString()); } } } diff --git a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/packets/PacketOutChatImpl.java b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/packets/PacketOutChatImpl.java index 2166ed8dac..e6076991a2 100644 --- a/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/packets/PacketOutChatImpl.java +++ b/v1_18/src/main/java/com/denizenscript/denizen/nms/v1_18/impl/network/packets/PacketOutChatImpl.java @@ -1,9 +1,8 @@ package com.denizenscript.denizen.nms.v1_18.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizen.nms.v1_18.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.chat.ChatType; @@ -25,13 +24,13 @@ public PacketOutChatImpl(ClientboundChatPacket internal) { try { Component baseComponent = (Component) MESSAGE.get(internal); if (baseComponent != null) { - message = FormattedTextHelper.stringify(Handler.componentToSpigot(baseComponent)); rawJson = Component.Serializer.toJson(baseComponent); + message = PaperAPITools.instance.parseJsonToText(rawJson); } else { if (internal.components != null) { - message = FormattedTextHelper.stringify(internal.components); rawJson = ComponentSerializer.toString(internal.components); + message = PaperAPITools.instance.parseJsonToText(rawJson); } bungee = true; } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/Handler.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/Handler.java index 09913ac081..99bd8cf5c8 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/Handler.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/Handler.java @@ -12,7 +12,6 @@ import com.denizenscript.denizen.nms.v1_19.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v1_19.impl.SidebarImpl; import com.denizenscript.denizen.nms.v1_19.impl.blocks.BlockLightImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -21,9 +20,6 @@ import com.google.common.collect.Iterables; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ByteArrayTag; @@ -197,7 +193,7 @@ else if (MINECRAFT_INVENTORY.isInstance(nms)) { public void setInventoryTitle(InventoryView view, String title) { AbstractContainerMenu menu = ((CraftInventoryView) view).getHandle(); try { - AbstractContainerMenu_title_SETTER.invoke(menu, componentToNMS(FormattedTextHelper.parse(title, ChatColor.DARK_GRAY))); + AbstractContainerMenu_title_SETTER.invoke(menu, parseNMSComponent(title, PaperAPITools.BaseColor.DARK_GRAY)); } catch (Throwable ex) { Debug.echoError(ex); @@ -316,19 +312,17 @@ public void setBossbarUUID(BossBar bar, UUID id) { } } - public static BaseComponent[] componentToSpigot(Component nms) { + public static String stringifyNMSComponent(Component nms) { if (nms == null) { return null; } - String json = Component.Serializer.toJson(nms); - return ComponentSerializer.parse(json); + return PaperAPITools.instance.parseJsonToText(Component.Serializer.toJson(nms)); } - public static MutableComponent componentToNMS(BaseComponent[] spigot) { - if (spigot == null) { + public static MutableComponent parseNMSComponent(String formattedText, PaperAPITools.BaseColor baseColor) { + if (formattedText == null) { return null; } - String json = FormattedTextHelper.componentToJson(spigot); - return Component.Serializer.fromJson(json); + return Component.Serializer.fromJson(PaperAPITools.instance.parseTextToJson(formattedText, baseColor)); } } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/AdvancementHelperImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/AdvancementHelperImpl.java index 24dbf20f06..bbce83bf07 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/AdvancementHelperImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/AdvancementHelperImpl.java @@ -1,11 +1,10 @@ package com.denizenscript.denizen.nms.v1_19.helpers; import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; +import com.denizenscript.denizen.nms.v1_19.Handler; import com.denizenscript.denizen.nms.v1_19.ReflectionMappingsInfo; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; -import com.denizenscript.denizen.nms.v1_19.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.ImpossibleTrigger; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; @@ -178,7 +177,7 @@ private static Advancement asNMSCopy(com.denizenscript.denizen.nms.util.Advancem ? getAdvancementDataWorld().advancements.advancements.get(asResourceLocation(advancement.parent)) : null; DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), - Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)), + Handler.parseNMSComponent(advancement.title, PaperAPITools.BaseColor.WHITE), Handler.parseNMSComponent(advancement.description, PaperAPITools.BaseColor.WHITE), asResourceLocation(advancement.background), FrameType.valueOf(advancement.frame.name()), advancement.toast, advancement.announceToChat, advancement.hidden); display.setLocation(advancement.xOffset, advancement.yOffset); diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/EnchantmentHelperImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/EnchantmentHelperImpl.java index 395b31fb0a..79a7c616f0 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/EnchantmentHelperImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/EnchantmentHelperImpl.java @@ -4,10 +4,9 @@ import com.denizenscript.denizen.nms.v1_19.Handler; import com.denizenscript.denizen.nms.v1_19.ReflectionMappingsInfo; import com.denizenscript.denizen.scripts.containers.core.EnchantmentScriptContainer; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.CoreUtilities; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.debugging.Debug; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -98,7 +97,7 @@ public String getDescriptionId() { } @Override public Component getFullname(int level) { - return Handler.componentToNMS(script.script.getFullName(level)); + return Component.Serializer.fromJson(script.script.getFullName(level)); } @Override public boolean canEnchant(net.minecraft.world.item.ItemStack var0) { @@ -185,7 +184,7 @@ public int getMaxCost(Enchantment enchantment, int level) { @Override public String getFullName(Enchantment enchantment, int level) { - return FormattedTextHelper.stringify(Handler.componentToSpigot(((CraftEnchantment) enchantment).getHandle().getFullname(level))); + return Handler.stringifyNMSComponent(((CraftEnchantment) enchantment).getHandle().getFullname(level)); } @Override diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/ItemHelperImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/ItemHelperImpl.java index e4bcbbb22b..501a24cf54 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/ItemHelperImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/ItemHelperImpl.java @@ -4,7 +4,7 @@ import com.denizenscript.denizen.nms.util.PlayerProfile; import com.denizenscript.denizen.nms.v1_19.ReflectionMappingsInfo; import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -14,9 +14,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; @@ -252,8 +249,7 @@ public String getDisplayName(ItemTag item) { } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); String jsonText = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getString("Name"); - BaseComponent[] nameComponent = ComponentSerializer.parse(jsonText); - return FormattedTextHelper.stringify(nameComponent); + return PaperAPITools.instance.parseJsonToText(jsonText); } @Override @@ -265,8 +261,7 @@ public List getLore(ItemTag item) { ListTag list = ((net.minecraft.nbt.CompoundTag) nmsItemStack.getTag().get("display")).getList("Lore", 8); List outList = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { - BaseComponent[] lineComponent = ComponentSerializer.parse(list.getString(i)); - outList.add(FormattedTextHelper.stringify(lineComponent)); + outList.add(PaperAPITools.instance.parseJsonToText(list.getString(i))); } return outList; } @@ -283,8 +278,7 @@ public void setDisplayName(ItemTag item, String name) { display.put("Name", null); return; } - BaseComponent[] components = FormattedTextHelper.parse(name, ChatColor.WHITE); - display.put("Name", net.minecraft.nbt.StringTag.valueOf(FormattedTextHelper.componentToJson(components))); + display.put("Name", net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(name, PaperAPITools.BaseColor.WHITE))); item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); } @@ -305,7 +299,7 @@ public void setLore(ItemTag item, List lore) { else { ListTag tagList = new ListTag(); for (String line : lore) { - tagList.add(net.minecraft.nbt.StringTag.valueOf(FormattedTextHelper.componentToJson(FormattedTextHelper.parse(line, ChatColor.WHITE)))); + tagList.add(net.minecraft.nbt.StringTag.valueOf(PaperAPITools.instance.parseTextToJson(line, PaperAPITools.BaseColor.WHITE))); } display.put("Lore", tagList); } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PacketHelperImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PacketHelperImpl.java index 2cefae3d5e..5750ce0db2 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PacketHelperImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PacketHelperImpl.java @@ -9,7 +9,7 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizen.utilities.blocks.FakeBlock; import com.denizenscript.denizen.utilities.maps.MapImage; @@ -21,7 +21,6 @@ import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.ListBinaryTag; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -190,8 +189,8 @@ public void showBannerUpdate(Player player, Location location, List pat @Override public void showTabListHeaderFooter(Player player, String header, String footer) { - Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); - Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + Component cHeader = Handler.parseNMSComponent(header, PaperAPITools.BaseColor.WHITE); + Component cFooter = Handler.parseNMSComponent(footer, PaperAPITools.BaseColor.WHITE); ClientboundTabListPacket packet = new ClientboundTabListPacket(cHeader, cFooter); send(player, packet); } @@ -200,10 +199,10 @@ public void showTabListHeaderFooter(Player player, String header, String footer) public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); + send(player, new ClientboundSetTitleTextPacket(Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE))); } if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); + send(player, new ClientboundSetSubtitleTextPacket(Handler.parseNMSComponent(subtitle, PaperAPITools.BaseColor.WHITE))); } } @@ -278,7 +277,7 @@ public void sendRename(Player player, Entity entity, String name, boolean listMo } SynchedEntityData fakeData = new SynchedEntityData(((CraftEntity) entity).getHandle()); List> list = new ArrayList<>(); - list.add(new SynchedEntityData.DataValue<>(ENTITY_DATA_ACCESSOR_CUSTOM_NAME.getId(), ENTITY_DATA_ACCESSOR_CUSTOM_NAME.getSerializer(), Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))))); + list.add(new SynchedEntityData.DataValue<>(ENTITY_DATA_ACCESSOR_CUSTOM_NAME.getId(), ENTITY_DATA_ACCESSOR_CUSTOM_NAME.getSerializer(), Optional.of(Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE)))); list.add(new SynchedEntityData.DataValue<>(ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE.getId(), ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE.getSerializer(), true)); send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), list)); } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PlayerHelperImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PlayerHelperImpl.java index 59927a9144..b9f9d3216e 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PlayerHelperImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/helpers/PlayerHelperImpl.java @@ -17,7 +17,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.entity.DenizenEntityType; import com.denizenscript.denizen.utilities.entity.FakeEntity; import com.denizenscript.denizencore.objects.Mechanism; @@ -26,7 +26,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.ints.IntList; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -370,7 +369,7 @@ public void setSkinLayers(Player player, byte flags) { @Override public void setBossBarTitle(BossBar bar, String title) { - ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().name = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); } @@ -425,7 +424,7 @@ public void sendPlayerInfoAddPacket(Player player, EnumSet edit if (texture != null) { profile.getProperties().put("textures", new Property("textures", texture, signature)); } - ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), null); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.parseNMSComponent(display, PaperAPITools.BaseColor.WHITE), null); PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/ProfileEditorImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/ProfileEditorImpl.java index 04b7b8d42a..6987e04506 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/ProfileEditorImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/ProfileEditorImpl.java @@ -8,12 +8,11 @@ import com.denizenscript.denizen.nms.v1_19.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_19.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; @@ -89,7 +88,7 @@ public static boolean handleAlteredProfiles(ClientboundPlayerInfoUpdatePacket pa patchedProfile.getProperties().putAll(Denizen.supportsPaper ? data.profile().getProperties() : baseProfile.getProperties()); } String listRename = RenameCommand.getCustomNameFor(data.profileId(), manager.player.getBukkitEntity(), true); - Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : data.displayName(); + Component displayName = listRename != null ? Handler.parseNMSComponent(listRename, PaperAPITools.BaseColor.WHITE) : data.displayName(); ClientboundPlayerInfoUpdatePacket.Entry newData = new ClientboundPlayerInfoUpdatePacket.Entry(data.profileId(), patchedProfile, data.listed(), data.latency(), data.gameMode(), displayName, data.chatSession()); manager.oldManager.send(createInfoPacket(actions, List.of(newData))); } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/SidebarImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/SidebarImpl.java index c56298727c..3efd9d9e45 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/SidebarImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/SidebarImpl.java @@ -1,12 +1,11 @@ package com.denizenscript.denizen.nms.v1_19.impl; +import com.denizenscript.denizen.nms.abstracts.Sidebar; import com.denizenscript.denizen.nms.v1_19.Handler; import com.denizenscript.denizen.nms.v1_19.helpers.PacketHelperImpl; -import com.denizenscript.denizen.nms.abstracts.Sidebar; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; @@ -44,7 +43,7 @@ public class SidebarImpl extends Sidebar { public SidebarImpl(Player player) { super(player); - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER); } @@ -52,7 +51,7 @@ public SidebarImpl(Player player) { @Override protected void setDisplayName(String title) { if (this.obj1 != null) { - MutableComponent chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + MutableComponent chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1.setDisplayName(chatComponentTitle); this.obj2.setDisplayName(chatComponentTitle); } @@ -73,7 +72,7 @@ public void sendUpdate() { String lineId = Utilities.generateRandomColors(8); PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); team.getPlayers().add(lineId); - team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + team.setPlayerPrefix(Handler.parseNMSComponent(line, PaperAPITools.BaseColor.WHITE)); generatedTeams.add(team); PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); PacketHelperImpl.send(player, new ClientboundSetScorePacket(ServerScoreboard.Method.CHANGE, obj1.getName(), lineId, this.scores[i])); diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/handlers/DenizenNetworkManagerImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/handlers/DenizenNetworkManagerImpl.java index 60724c27f0..5261101266 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/handlers/DenizenNetworkManagerImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/handlers/DenizenNetworkManagerImpl.java @@ -14,7 +14,7 @@ import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.scripts.commands.entity.*; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Settings; import com.denizenscript.denizen.utilities.blocks.ChunkCoordinate; import com.denizenscript.denizen.utilities.blocks.FakeBlock; @@ -35,7 +35,6 @@ import com.mojang.datafixers.util.Pair; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.core.SectionPos; @@ -409,7 +408,7 @@ public boolean processTablistPacket(Packet packet, PacketSendListener generic } String modeText = update.gameMode() == null ? null : update.gameMode().name(); PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.getId(), update.listed(), profile.getName(), - update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); + update.displayName() == null ? null : Handler.stringifyNMSComponent(update.displayName()), modeText, texture, signature, update.latency()); PlayerReceivesTablistUpdateScriptEvent.fire(player.getBukkitEntity(), data); if (data.modified) { if (!isOverriding) { @@ -427,7 +426,7 @@ public boolean processTablistPacket(Packet packet, PacketSendListener generic newProfile.getProperties().put("textures", new Property("textures", data.texture, data.signature)); } ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.getId(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), - data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.chatSession()); + data.display == null ? null : Handler.parseNMSComponent(data.display, PaperAPITools.BaseColor.WHITE), update.chatSession()); oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry)), genericfuturelistener); } } @@ -464,10 +463,10 @@ public boolean processActionbarPacket(Packet packet, PacketSendListener gener if (packet instanceof ClientboundSetActionBarTextPacket) { ClientboundSetActionBarTextPacket actionbarPacket = (ClientboundSetActionBarTextPacket) packet; PlayerReceivesActionbarScriptEvent event = PlayerReceivesActionbarScriptEvent.instance; - Component baseComponent = actionbarPacket.getText(); + String rawJson = Component.Serializer.toJson(actionbarPacket.getText()); event.reset(); - event.message = new ElementTag(FormattedTextHelper.stringify(Handler.componentToSpigot(baseComponent))); - event.rawJson = new ElementTag(Component.Serializer.toJson(baseComponent)); + event.message = new ElementTag(PaperAPITools.instance.parseJsonToText(rawJson), true); + event.rawJson = new ElementTag(rawJson, true); event.system = new ElementTag(false); event.player = PlayerTag.mirrorBukkitPlayer(player.getBukkitEntity()); event = (PlayerReceivesActionbarScriptEvent) event.triggerNow(); @@ -475,8 +474,7 @@ public boolean processActionbarPacket(Packet packet, PacketSendListener gener return true; } if (event.modified) { - Component component = Handler.componentToNMS(event.altMessageDetermination); - ClientboundSetActionBarTextPacket newPacket = new ClientboundSetActionBarTextPacket(component); + ClientboundSetActionBarTextPacket newPacket = new ClientboundSetActionBarTextPacket(Component.Serializer.fromJson(event.rawJson.asString())); oldManager.send(newPacket, genericfuturelistener); return true; } @@ -840,7 +838,7 @@ else if (nameToApply == null || (dataValue.id() != 2 && dataValue.id() != 3)) { data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); } if (nameToApply != null) { - data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))))); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.parseNMSComponent(nameToApply, PaperAPITools.BaseColor.WHITE)))); data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true)); } return new ClientboundSetEntityDataPacket(metadataPacket.id(), data); @@ -1237,7 +1235,7 @@ else if (packet instanceof ClientboundPlayerChatPacket playerChatPacket) { return true; } if (result.modified) { - oldManager.send(new ClientboundSystemChatPacket(result.altMessageDetermination, isActionbar), genericfuturelistener); + oldManager.send(new ClientboundSystemChatPacket(result.rawJson.asString(), isActionbar), genericfuturelistener); return true; } } diff --git a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/packets/PacketOutChatImpl.java b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/packets/PacketOutChatImpl.java index 1a7ed32da1..a06b378b8b 100644 --- a/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/packets/PacketOutChatImpl.java +++ b/v1_19/src/main/java/com/denizenscript/denizen/nms/v1_19/impl/network/packets/PacketOutChatImpl.java @@ -1,7 +1,7 @@ package com.denizenscript.denizen.nms.v1_19.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import net.md_5.bungee.chat.ComponentSerializer; @@ -36,14 +36,14 @@ public PacketOutChatImpl(ClientboundSystemChatPacket internal) { Debug.echoError(ex); } } - message = FormattedTextHelper.stringify(ComponentSerializer.parse(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); isOverlayActionbar = internal.overlay(); } public PacketOutChatImpl(ClientboundPlayerChatPacket internal) { playerPacket = internal; rawJson = ComponentSerializer.toString(internal.body().content()); - message = FormattedTextHelper.stringify(ComponentSerializer.parse(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); } @Override diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java index f162d44efd..66fa5509ac 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java @@ -16,7 +16,6 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; @@ -33,9 +32,6 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.yggdrasil.ProfileResult; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Rotations; @@ -108,7 +104,7 @@ public Handler() { enchantmentHelper = new EnchantmentHelperImpl(); registerConversion(ItemTag.class, ItemStack.class, item -> CraftItemStack.asNMSCopy(item.getItemStack())); - registerConversion(ElementTag.class, Component.class, element -> componentToNMS(FormattedTextHelper.parse(element.asString(), ChatColor.WHITE))); + registerConversion(ElementTag.class, Component.class, element -> parseNMSComponent(element.asString(), PaperAPITools.BaseColor.WHITE)); registerConversion(MaterialTag.class, BlockState.class, material -> ((CraftBlockData) material.getModernData()).getState()); registerConversion(LocationTag.class, Rotations.class, location -> new Rotations((float) location.getX(), (float) location.getY(), (float) location.getZ())); registerConversion(LocationTag.class, BlockPos.class, CraftLocation::toBlockPosition); @@ -240,7 +236,7 @@ else if (MINECRAFT_INVENTORY.isInstance(nms)) { public void setInventoryTitle(InventoryView view, String title) { AbstractContainerMenu menu = ((CraftInventoryView) view).getHandle(); try { - AbstractContainerMenu_title_SETTER.invoke(menu, componentToNMS(FormattedTextHelper.parse(title, ChatColor.DARK_GRAY))); + AbstractContainerMenu_title_SETTER.invoke(menu, parseNMSComponent(title, PaperAPITools.BaseColor.DARK_GRAY)); } catch (Throwable ex) { Debug.echoError(ex); @@ -359,22 +355,22 @@ public void setBossbarUUID(BossBar bar, UUID id) { } } - public static BaseComponent[] componentToSpigot(Component nms) { + @Override + public String updateLegacyName(Class type, String legacyName) { + return FieldRename.rename(ApiVersion.FIELD_NAME_PARITY, DebugInternals.getFullClassNameOpti(type).replace('.', '/'), legacyName); + } + + public static String stringifyNMSComponent(Component nms) { if (nms == null) { return null; } - return ComponentSerializer.parse(CraftChatMessage.toJSON(nms)); + return PaperAPITools.instance.parseJsonToText(CraftChatMessage.toJSON(nms)); } - public static Component componentToNMS(BaseComponent[] spigot) { - if (spigot == null) { + public static Component parseNMSComponent(String formattedText, PaperAPITools.BaseColor baseColor) { + if (formattedText == null) { return null; } - return CraftChatMessage.fromJSONOrNull(FormattedTextHelper.componentToJson(spigot)); - } - - @Override - public String updateLegacyName(Class type, String legacyName) { - return FieldRename.rename(ApiVersion.FIELD_NAME_PARITY, DebugInternals.getFullClassNameOpti(type).replace('.', '/'), legacyName); + return CraftChatMessage.fromJSON(PaperAPITools.instance.parseTextToJson(formattedText, baseColor)); } } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/AdvancementHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/AdvancementHelperImpl.java index 7b70014dcb..59c4630773 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/AdvancementHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/AdvancementHelperImpl.java @@ -2,9 +2,8 @@ import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; import com.denizenscript.denizen.nms.v1_20.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.google.common.collect.ImmutableMap; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.ImpossibleTrigger; import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket; @@ -159,7 +158,7 @@ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Ad ? getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.parent)) : null; DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), - Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)), + Handler.parseNMSComponent(advancement.title, PaperAPITools.BaseColor.WHITE), Handler.parseNMSComponent(advancement.description, PaperAPITools.BaseColor.WHITE), Optional.ofNullable(advancement.background).map(CraftNamespacedKey::toMinecraft), AdvancementType.valueOf(advancement.frame.name()), advancement.toast, advancement.announceToChat, advancement.hidden); display.setLocation(advancement.xOffset, advancement.yOffset); diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EnchantmentHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EnchantmentHelperImpl.java index c8b1400c6a..d4b1cf1d38 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EnchantmentHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EnchantmentHelperImpl.java @@ -5,7 +5,6 @@ import com.denizenscript.denizen.nms.v1_20.Handler; import com.denizenscript.denizen.nms.v1_20.ReflectionMappingsInfo; import com.denizenscript.denizen.scripts.containers.core.EnchantmentScriptContainer; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -22,6 +21,7 @@ import org.bukkit.craftbukkit.v1_20_R4.enchantments.CraftEnchantment; import org.bukkit.craftbukkit.v1_20_R4.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R4.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.event.entity.EntityDamageEvent; @@ -106,7 +106,7 @@ public String getDescriptionId() { } @Override public Component getFullname(int level) { - return Handler.componentToNMS(script.script.getFullName(level)); + return CraftChatMessage.fromJSON(script.script.getFullName(level)); } @Override public boolean canEnchant(net.minecraft.world.item.ItemStack var0) { @@ -192,7 +192,7 @@ public int getMaxCost(Enchantment enchantment, int level) { @Override public String getFullName(Enchantment enchantment, int level) { - return FormattedTextHelper.stringify(Handler.componentToSpigot(((CraftEnchantment) enchantment).getHandle().getFullname(level))); + return Handler.stringifyNMSComponent(((CraftEnchantment) enchantment).getHandle().getFullname(level)); } // TODO: 1.20.6: MobType was removed in favor of using the entity type directly - deprecate + potentially backsupport with vanilla tags diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java index cc304f59b4..29b395566a 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/ItemHelperImpl.java @@ -8,7 +8,6 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.MapTag; @@ -16,14 +15,11 @@ import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.collect.*; -import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.serialization.Dynamic; -import com.mojang.serialization.JsonOps; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.critereon.BlockPredicate; import net.minecraft.core.*; import net.minecraft.core.component.DataComponentMap; @@ -70,6 +66,7 @@ import org.bukkit.craftbukkit.v1_20_R4.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftInventoryPlayer; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemType; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftRecipe; import org.bukkit.craftbukkit.v1_20_R4.map.CraftMapView; import org.bukkit.craftbukkit.v1_20_R4.util.CraftMagicNumbers; @@ -203,26 +200,13 @@ public String getJsonString(ItemStack itemStack) { } @Override - public JsonObject getRawHoverComponentsJson(ItemStack item) { - DataComponentPatch nmsComponents = CraftItemStack.asNMSCopy(item).getComponentsPatch(); - if (nmsComponents.isEmpty()) { - return null; + public ItemStack createItemWithNMSComponents(Material type, int count, Object nmsPatchObject) { + if (!(nmsPatchObject instanceof DataComponentPatch nmsPatch)) { + throw new IllegalArgumentException(nmsPatchObject + " is not a DataComponentPatch"); } - return DataComponentPatch.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), nmsComponents).getOrThrow().getAsJsonObject(); - } - - @Override - public ItemStack applyRawHoverComponentsJson(ItemStack item, JsonObject components) { - return DataComponentPatch.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), components).mapOrElse( - nmsComponents -> { - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); - nmsItem.applyComponents(nmsComponents); - return CraftItemStack.asCraftMirror(nmsItem); - }, - error -> { - Debug.echoError("Invalid hover item data '" + components + "': " + error.message()); - return item; - }); + return CraftItemStack.asCraftMirror(new net.minecraft.world.item.ItemStack( + BuiltInRegistries.ITEM.wrapAsHolder(CraftItemType.bukkitToMinecraft(type)), count, nmsPatch + )); } @Override @@ -446,7 +430,7 @@ public String getDisplayName(ItemTag item) { } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); Component nmsDisplayName = nmsItemStack.get(DataComponents.CUSTOM_NAME); - return FormattedTextHelper.stringify(Handler.componentToSpigot(nmsDisplayName)); + return Handler.stringifyNMSComponent(nmsDisplayName); } @Override @@ -458,7 +442,7 @@ public List getLore(ItemTag item) { ItemLore nmsLore = nmsItemStack.get(DataComponents.LORE); List outList = new ArrayList<>(nmsLore.lines().size()); for (Component nmsLoreLine : nmsLore.lines()) { - outList.add(FormattedTextHelper.stringify(Handler.componentToSpigot(nmsLoreLine))); + outList.add(Handler.stringifyNMSComponent(nmsLoreLine)); } return outList; } @@ -470,7 +454,7 @@ public void setDisplayName(ItemTag item, String name) { nmsItemStack.remove(DataComponents.CUSTOM_NAME); } else { - nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))); + nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE)); } item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); } @@ -484,7 +468,7 @@ public void setLore(ItemTag item, List lore) { else { List nmsLore = new ArrayList<>(lore.size()); for (String loreLine : lore) { - nmsLore.add(Handler.componentToNMS(FormattedTextHelper.parse(loreLine, ChatColor.WHITE))); + nmsLore.add(Handler.parseNMSComponent(loreLine, PaperAPITools.BaseColor.WHITE)); } nmsItemStack.set(DataComponents.LORE, new ItemLore(nmsLore)); } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PacketHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PacketHelperImpl.java index 9d9ce41a15..5028e0dbaf 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PacketHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PacketHelperImpl.java @@ -7,14 +7,13 @@ import com.denizenscript.denizen.nms.v1_20.impl.SidebarImpl; import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizen.utilities.maps.MapImage; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; @@ -148,8 +147,8 @@ public void showBlockAction(Player player, Location location, int action, int st @Override public void showTabListHeaderFooter(Player player, String header, String footer) { - Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); - Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + Component cHeader = Handler.parseNMSComponent(header, PaperAPITools.BaseColor.WHITE); + Component cFooter = Handler.parseNMSComponent(footer, PaperAPITools.BaseColor.WHITE); send(player, new ClientboundTabListPacket(cHeader, cFooter)); } @@ -157,10 +156,10 @@ public void showTabListHeaderFooter(Player player, String header, String footer) public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); + send(player, new ClientboundSetTitleTextPacket(Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE))); } if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); + send(player, new ClientboundSetSubtitleTextPacket(Handler.parseNMSComponent(subtitle, PaperAPITools.BaseColor.WHITE))); } } @@ -238,7 +237,7 @@ public void sendRename(Player player, Entity entity, String name, boolean listMo return; } List> list = List.of( - createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE)))), + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE))), createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true) ); send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), list)); diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PlayerHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PlayerHelperImpl.java index 2f0c9f0d10..8acf11433b 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PlayerHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/PlayerHelperImpl.java @@ -17,7 +17,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.entity.DenizenEntityType; import com.denizenscript.denizen.utilities.entity.FakeEntity; import com.denizenscript.denizencore.objects.Mechanism; @@ -26,7 +26,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.ints.IntList; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -366,7 +365,7 @@ public void setSkinLayers(Player player, byte flags) { @Override public void setBossBarTitle(BossBar bar, String title) { - ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().name = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); } @@ -421,7 +420,7 @@ public void sendPlayerInfoAddPacket(Player player, EnumSet edit if (texture != null) { profile.getProperties().put("textures", new Property("textures", texture, signature)); } - ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), null); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.parseNMSComponent(display, PaperAPITools.BaseColor.WHITE), null); PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/ProfileEditorImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/ProfileEditorImpl.java index 7c911163f0..cc2ba96ae1 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/ProfileEditorImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/ProfileEditorImpl.java @@ -8,12 +8,11 @@ import com.denizenscript.denizen.nms.v1_20.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; @@ -94,7 +93,7 @@ public static ClientboundPlayerInfoUpdatePacket processPlayerInfoUpdatePacket(De modifiedProfile.getProperties().putAll(Denizen.supportsPaper ? entry.profile().getProperties() : baseProfile.getProperties()); } String listRename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), true); - Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : entry.displayName(); + Component displayName = listRename != null ? Handler.parseNMSComponent(listRename, PaperAPITools.BaseColor.WHITE) : entry.displayName(); ClientboundPlayerInfoUpdatePacket.Entry modifiedEntry = new ClientboundPlayerInfoUpdatePacket.Entry(entry.profileId(), modifiedProfile, entry.listed(), entry.latency(), entry.gameMode(), displayName, entry.chatSession()); modifiedEntries.add(modifiedEntry); } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/SidebarImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/SidebarImpl.java index 5a76a4a10e..37cc69310f 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/SidebarImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/SidebarImpl.java @@ -3,9 +3,8 @@ import com.denizenscript.denizen.nms.abstracts.Sidebar; import com.denizenscript.denizen.nms.v1_20.Handler; import com.denizenscript.denizen.nms.v1_20.helpers.PacketHelperImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.numbers.StyledFormat; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; @@ -47,7 +46,7 @@ public class SidebarImpl extends Sidebar { public SidebarImpl(Player player) { super(player); - Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + Component chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); } @@ -55,7 +54,7 @@ public SidebarImpl(Player player) { @Override protected void setDisplayName(String title) { if (this.obj1 != null) { - Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + Component chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1.setDisplayName(chatComponentTitle); this.obj2.setDisplayName(chatComponentTitle); } @@ -77,7 +76,7 @@ public void sendUpdate() { String lineId = ids[i]; PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); team.getPlayers().add(lineId); - team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + team.setPlayerPrefix(Handler.parseNMSComponent(line, PaperAPITools.BaseColor.WHITE)); generatedTeams.add(team); PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); PacketHelperImpl.send(player, new ClientboundSetScorePacket(lineId, obj1.getName(), this.scores[i], Optional.empty(), Optional.of(StyledFormat.SIDEBAR_DEFAULT))); diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index 7bb358a154..8479718a07 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -1,10 +1,9 @@ package com.denizenscript.denizen.nms.v1_20.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; -import com.denizenscript.denizen.nms.v1_20.Handler; import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.core.ElementTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; @@ -22,9 +21,9 @@ public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNe return actionbarPacket; } event.reset(); - Component actionbarText = actionbarPacket.text(); - event.message = new ElementTag(FormattedTextHelper.stringify(Handler.componentToSpigot(actionbarText)), true); - event.rawJson = new ElementTag(CraftChatMessage.toJSON(actionbarText), true); + String rawJson = CraftChatMessage.toJSON(actionbarPacket.text()); + event.message = new ElementTag(PaperAPITools.instance.parseJsonToText(rawJson), true); + event.rawJson = new ElementTag(rawJson, true); event.system = new ElementTag(false); event.player = PlayerTag.mirrorBukkitPlayer(networkManager.player.getBukkitEntity()); event = (PlayerReceivesActionbarScriptEvent) event.triggerNow(); @@ -32,7 +31,7 @@ public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNe return null; } if (event.modified) { - return new ClientboundSetActionBarTextPacket(Handler.componentToNMS(event.altMessageDetermination)); + return new ClientboundSetActionBarTextPacket(CraftChatMessage.fromJSON(event.rawJson.asString())); } return actionbarPacket; } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java index bf1b80eb75..8ea4a50b65 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -8,6 +8,7 @@ import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import org.bukkit.craftbukkit.v1_20_R4.util.CraftChatMessage; public class DenizenPacketHandlerPacketHandlers { @@ -37,7 +38,7 @@ else if (packet instanceof ClientboundPlayerChatPacket playerChatPacket) { return null; } if (result.modified) { - return new ClientboundSystemChatPacket(result.altMessageDetermination, isActionbar); + return new ClientboundSystemChatPacket(CraftChatMessage.fromJSON(result.rawJson.asString()), isActionbar); } } } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/EntityMetadataPacketHandlers.java index 40cf0c42af..f6ca91442e 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/EntityMetadataPacketHandlers.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -7,9 +7,8 @@ import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.scripts.commands.entity.SneakCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; @@ -61,7 +60,7 @@ else if (nameToApply == null || (dataValue.id() != 2 && dataValue.id() != 3)) { data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); } if (nameToApply != null) { - data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))))); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.parseNMSComponent(nameToApply, PaperAPITools.BaseColor.WHITE)))); data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true)); } return new ClientboundSetEntityDataPacket(metadataPacket.id(), data); diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java index 41695a47a6..da9fde198d 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -4,13 +4,12 @@ import com.denizenscript.denizen.nms.v1_20.Handler; import com.denizenscript.denizen.nms.v1_20.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v1_20.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.base.Joiner; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; @@ -80,7 +79,7 @@ public static Packet processTablistPacket(DenizenNetwo } String modeText = update.gameMode() == null ? null : update.gameMode().name(); PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.getId(), update.listed(), profile.getName(), - update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); + update.displayName() == null ? null : Handler.stringifyNMSComponent(update.displayName()), modeText, texture, signature, update.latency()); PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); if (data.modified) { if (!isOverriding) { @@ -98,7 +97,7 @@ public static Packet processTablistPacket(DenizenNetwo newProfile.getProperties().put("textures", new Property("textures", data.texture, data.signature)); } ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.getId(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), - data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.chatSession()); + data.display == null ? null : Handler.parseNMSComponent(data.display, PaperAPITools.BaseColor.WHITE), update.chatSession()); networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry))); } } diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/packets/PacketOutChatImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/packets/PacketOutChatImpl.java index f8e82c3183..7bdc683926 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/packets/PacketOutChatImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/impl/network/packets/PacketOutChatImpl.java @@ -1,7 +1,7 @@ package com.denizenscript.denizen.nms.v1_20.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; @@ -18,14 +18,14 @@ public class PacketOutChatImpl extends PacketOutChat { public PacketOutChatImpl(ClientboundSystemChatPacket internal) { systemPacket = internal; rawJson = CraftChatMessage.toJSON(internal.content()); - message = FormattedTextHelper.stringify(ComponentSerializer.parse(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); isOverlayActionbar = internal.overlay(); } public PacketOutChatImpl(ClientboundPlayerChatPacket internal) { playerPacket = internal; rawJson = ComponentSerializer.toString(internal.body().content()); - message = FormattedTextHelper.stringify(ComponentSerializer.parse(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); } @Override diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java index 1cd431f486..2dbfa250f7 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/Handler.java @@ -16,7 +16,6 @@ import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.MaterialTag; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; @@ -34,8 +33,6 @@ import com.mojang.authlib.yggdrasil.ProfileResult; import com.mojang.serialization.DynamicOps; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; @@ -115,7 +112,7 @@ public Handler() { enchantmentHelper = new EnchantmentHelperImpl(); registerConversion(ItemTag.class, ItemStack.class, item -> CraftItemStack.asNMSCopy(item.getItemStack())); - registerConversion(ElementTag.class, Component.class, element -> componentToNMS(FormattedTextHelper.parse(element.asString(), ChatColor.WHITE))); + registerConversion(ElementTag.class, Component.class, element -> parseNMSComponent(element.asString(), PaperAPITools.BaseColor.WHITE)); registerConversion(MaterialTag.class, BlockState.class, material -> ((CraftBlockData) material.getModernData()).getState()); registerConversion(LocationTag.class, Rotations.class, location -> new Rotations((float) location.getX(), (float) location.getY(), (float) location.getZ())); registerConversion(LocationTag.class, BlockPos.class, CraftLocation::toBlockPosition); @@ -247,7 +244,7 @@ else if (MINECRAFT_INVENTORY.isInstance(nms)) { public void setInventoryTitle(InventoryView view, String title) { AbstractContainerMenu menu = ((CraftInventoryView) view).getHandle(); try { - AbstractContainerMenu_title_SETTER.invoke(menu, componentToNMS(FormattedTextHelper.parse(title, ChatColor.DARK_GRAY))); + AbstractContainerMenu_title_SETTER.invoke(menu, parseNMSComponent(title, PaperAPITools.BaseColor.DARK_GRAY)); } catch (Throwable ex) { Debug.echoError(ex); @@ -366,20 +363,6 @@ public void setBossbarUUID(BossBar bar, UUID id) { } } - public static BaseComponent[] componentToSpigot(Component nms) { - if (nms == null) { - return null; - } - return FormattedTextHelper.parseJson(CraftChatMessage.toJSON(nms)); - } - - public static Component componentToNMS(BaseComponent[] spigot) { - if (spigot == null) { - return null; - } - return CraftChatMessage.fromJSONOrNull(FormattedTextHelper.componentToJson(spigot)); - } - public static final MethodHandle TAG_VALUE_OUTPUT_CONSTRUCTOR = ReflectionHelper.getConstructor(TagValueOutput.class, ProblemReporter.class, DynamicOps.class, CompoundTag.class); public static CompoundTag useValueOutput(Consumer handler) { @@ -422,4 +405,18 @@ private static void handleProblems(ProblemReporter.Collector nmsProblemReporter) public String updateLegacyName(Class type, String legacyName) { return FieldRename.rename(ApiVersion.FIELD_NAME_PARITY, DebugInternals.getFullClassNameOpti(type).replace('.', '/'), legacyName); } + + public static String stringifyNMSComponent(Component nms) { + if (nms == null) { + return null; + } + return PaperAPITools.instance.parseJsonToText(CraftChatMessage.toJSON(nms)); + } + + public static Component parseNMSComponent(String formattedText, PaperAPITools.BaseColor baseColor) { + if (formattedText == null) { + return null; + } + return CraftChatMessage.fromJSON(PaperAPITools.instance.parseTextToJson(formattedText, baseColor)); + } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java index 0b2ca9366e..a7129e3638 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/AdvancementHelperImpl.java @@ -2,9 +2,8 @@ import com.denizenscript.denizen.nms.interfaces.AdvancementHelper; import com.denizenscript.denizen.nms.v1_21.Handler; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.google.common.collect.ImmutableMap; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.ImpossibleTrigger; import net.minecraft.core.ClientAsset; @@ -175,7 +174,7 @@ private static AdvancementHolder asNMSCopy(com.denizenscript.denizen.nms.util.Ad ? getNMSAdvancementManager().advancements.get(CraftNamespacedKey.toMinecraft(advancement.parent)) : null; DisplayInfo display = new DisplayInfo(CraftItemStack.asNMSCopy(advancement.icon), - Handler.componentToNMS(FormattedTextHelper.parse(advancement.title, ChatColor.WHITE)), Handler.componentToNMS(FormattedTextHelper.parse(advancement.description, ChatColor.WHITE)), + Handler.parseNMSComponent(advancement.title, PaperAPITools.BaseColor.WHITE), Handler.parseNMSComponent(advancement.description, PaperAPITools.BaseColor.WHITE), Optional.ofNullable(advancement.background).map(CraftNamespacedKey::toMinecraft).map(ClientAsset::new), AdvancementType.valueOf(advancement.frame.name()), advancement.toast, advancement.announceToChat, advancement.hidden); display.setLocation(advancement.xOffset, advancement.yOffset); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java index 14298cc907..bccbed6fcc 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/ItemHelperImpl.java @@ -8,7 +8,6 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.properties.item.ItemComponentsPatch; import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; -import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.MapTag; @@ -16,14 +15,11 @@ import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.collect.*; -import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.serialization.Dynamic; -import com.mojang.serialization.JsonOps; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.md_5.bungee.api.ChatColor; import net.minecraft.advancements.critereon.BlockPredicate; import net.minecraft.advancements.critereon.DataComponentMatchers; import net.minecraft.core.*; @@ -315,26 +311,13 @@ public String getJsonString(ItemStack itemStack) { } @Override - public JsonObject getRawHoverComponentsJson(ItemStack item) { - DataComponentPatch nmsComponents = CraftItemStack.asNMSCopy(item).getComponentsPatch(); - if (nmsComponents.isEmpty()) { - return null; + public ItemStack createItemWithNMSComponents(Material type, int count, Object nmsPatchObject) { + if (!(nmsPatchObject instanceof DataComponentPatch nmsPatch)) { + throw new IllegalArgumentException(nmsPatchObject + " is not a DataComponentPatch"); } - return DataComponentPatch.CODEC.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), nmsComponents).getOrThrow().getAsJsonObject(); - } - - @Override - public ItemStack applyRawHoverComponentsJson(ItemStack item, JsonObject components) { - return DataComponentPatch.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE), components).mapOrElse( - nmsComponents -> { - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); - nmsItem.applyComponents(nmsComponents); - return CraftItemStack.asCraftMirror(nmsItem); - }, - error -> { - Debug.echoError("Invalid hover item data '" + components + "': " + error.message()); - return item; - }); + return CraftItemStack.asCraftMirror(new net.minecraft.world.item.ItemStack( + BuiltInRegistries.ITEM.wrapAsHolder(CraftItemType.bukkitToMinecraft(type)), count, nmsPatch + )); } @Override @@ -556,7 +539,7 @@ public String getDisplayName(ItemTag item) { } net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(item.getItemStack()); Component nmsDisplayName = nmsItemStack.get(DataComponents.CUSTOM_NAME); - return FormattedTextHelper.stringify(Handler.componentToSpigot(nmsDisplayName)); + return Handler.stringifyNMSComponent(nmsDisplayName); } @Override @@ -568,7 +551,7 @@ public List getLore(ItemTag item) { ItemLore nmsLore = nmsItemStack.get(DataComponents.LORE); List outList = new ArrayList<>(nmsLore.lines().size()); for (Component nmsLoreLine : nmsLore.lines()) { - outList.add(FormattedTextHelper.stringify(Handler.componentToSpigot(nmsLoreLine))); + outList.add(Handler.stringifyNMSComponent(nmsLoreLine)); } return outList; } @@ -580,7 +563,7 @@ public void setDisplayName(ItemTag item, String name) { nmsItemStack.remove(DataComponents.CUSTOM_NAME); } else { - nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE))); + nmsItemStack.set(DataComponents.CUSTOM_NAME, Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE)); } item.setItemStack(CraftItemStack.asBukkitCopy(nmsItemStack)); } @@ -594,7 +577,7 @@ public void setLore(ItemTag item, List lore) { else { List nmsLore = new ArrayList<>(lore.size()); for (String loreLine : lore) { - nmsLore.add(Handler.componentToNMS(FormattedTextHelper.parse(loreLine, ChatColor.WHITE))); + nmsLore.add(Handler.parseNMSComponent(loreLine, PaperAPITools.BaseColor.WHITE)); } nmsItemStack.set(DataComponents.LORE, new ItemLore(nmsLore)); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java index 0156bee78a..6501710d7b 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PacketHelperImpl.java @@ -8,14 +8,13 @@ import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizen.utilities.maps.MapImage; import com.denizenscript.denizen.utilities.packets.NetworkInterceptHelper; import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; @@ -153,8 +152,8 @@ public void showBlockAction(Player player, Location location, int action, int st @Override public void showTabListHeaderFooter(Player player, String header, String footer) { - Component cHeader = Handler.componentToNMS(FormattedTextHelper.parse(header, ChatColor.WHITE)); - Component cFooter = Handler.componentToNMS(FormattedTextHelper.parse(footer, ChatColor.WHITE)); + Component cHeader = Handler.parseNMSComponent(header, PaperAPITools.BaseColor.WHITE); + Component cFooter = Handler.parseNMSComponent(footer, PaperAPITools.BaseColor.WHITE); send(player, new ClientboundTabListPacket(cHeader, cFooter)); } @@ -162,10 +161,10 @@ public void showTabListHeaderFooter(Player player, String header, String footer) public void showTitle(Player player, String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { send(player, new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks)); if (title != null) { - send(player, new ClientboundSetTitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)))); + send(player, new ClientboundSetTitleTextPacket(Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE))); } if (subtitle != null) { - send(player, new ClientboundSetSubtitleTextPacket(Handler.componentToNMS(FormattedTextHelper.parse(subtitle, ChatColor.WHITE)))); + send(player, new ClientboundSetSubtitleTextPacket(Handler.parseNMSComponent(subtitle, PaperAPITools.BaseColor.WHITE))); } } @@ -246,7 +245,7 @@ public void sendRename(Player player, Entity entity, String name, boolean listMo return; } List> list = List.of( - createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(name, ChatColor.WHITE)))), + createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.parseNMSComponent(name, PaperAPITools.BaseColor.WHITE))), createEntityData(ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true) ); send(player, new ClientboundSetEntityDataPacket(entity.getEntityId(), list)); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java index c3ee8fcced..e825520d53 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/helpers/PlayerHelperImpl.java @@ -17,7 +17,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.objects.LocationTag; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.entity.DenizenEntityType; import com.denizenscript.denizen.utilities.entity.FakeEntity; import com.denizenscript.denizencore.objects.Mechanism; @@ -26,8 +26,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.ints.IntList; -import net.md_5.bungee.api.ChatColor; -import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; @@ -377,7 +375,7 @@ public void setSkinLayers(Player player, byte flags) { @Override public void setBossBarTitle(BossBar bar, String title) { - ((CraftBossBar) bar).getHandle().name = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + ((CraftBossBar) bar).getHandle().name = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); ((CraftBossBar) bar).getHandle().broadcast(ClientboundBossEventPacket::createUpdateNamePacket); } @@ -435,7 +433,7 @@ public void sendPlayerInfoAddPacket(Player player, EnumSet edit profile.getProperties().put("textures", new Property("textures", texture, signature)); } // TODO: 1.21.3: Player list order and hat visibility support - ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(display, ChatColor.WHITE)), true, player.getPlayerListOrder(), null); + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(id, profile, listed, latency, gameMode == null ? null : GameType.byId(gameMode.getValue()), display == null ? null : Handler.parseNMSComponent(display, PaperAPITools.BaseColor.WHITE), true, player.getPlayerListOrder(), null); PacketHelperImpl.send(player, ProfileEditorImpl.createInfoPacket(actions, List.of(entry))); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java index 2f25a8878d..2cf2538dba 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/ProfileEditorImpl.java @@ -8,12 +8,11 @@ import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.ReflectionHelper; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; @@ -97,7 +96,7 @@ public static ClientboundPlayerInfoUpdatePacket processPlayerInfoUpdatePacket(De modifiedProfile.getProperties().putAll(Denizen.supportsPaper ? entry.profile().getProperties() : baseProfile.getProperties()); } String listRename = RenameCommand.getCustomNameFor(entry.profileId(), networkManager.player.getBukkitEntity(), true); - Component displayName = listRename != null ? Handler.componentToNMS(FormattedTextHelper.parse(listRename, ChatColor.WHITE)) : entry.displayName(); + Component displayName = listRename != null ? Handler.parseNMSComponent(listRename, PaperAPITools.BaseColor.WHITE) : entry.displayName(); ClientboundPlayerInfoUpdatePacket.Entry modifiedEntry = new ClientboundPlayerInfoUpdatePacket.Entry(entry.profileId(), modifiedProfile, entry.listed(), entry.latency(), entry.gameMode(), displayName, entry.showHat(), entry.listOrder(), entry.chatSession()); modifiedEntries.add(modifiedEntry); } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/SidebarImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/SidebarImpl.java index e765aa1487..36322954cb 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/SidebarImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/SidebarImpl.java @@ -3,9 +3,8 @@ import com.denizenscript.denizen.nms.abstracts.Sidebar; import com.denizenscript.denizen.nms.v1_21.Handler; import com.denizenscript.denizen.nms.v1_21.helpers.PacketHelperImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.numbers.StyledFormat; import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; @@ -47,7 +46,7 @@ public class SidebarImpl extends Sidebar { public SidebarImpl(Player player) { super(player); - Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + Component chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1 = new Objective(dummyScoreboard, "dummy_1", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); this.obj2 = new Objective(dummyScoreboard, "dummy_2", dummyCriteria, chatComponentTitle, ObjectiveCriteria.RenderType.INTEGER, false, StyledFormat.SIDEBAR_DEFAULT); } @@ -55,7 +54,7 @@ public SidebarImpl(Player player) { @Override protected void setDisplayName(String title) { if (this.obj1 != null) { - Component chatComponentTitle = Handler.componentToNMS(FormattedTextHelper.parse(title, ChatColor.WHITE)); + Component chatComponentTitle = Handler.parseNMSComponent(title, PaperAPITools.BaseColor.WHITE); this.obj1.setDisplayName(chatComponentTitle); this.obj2.setDisplayName(chatComponentTitle); } @@ -77,7 +76,7 @@ public void sendUpdate() { String lineId = ids[i]; PlayerTeam team = new PlayerTeam(dummyScoreboard, lineId); team.getPlayers().add(lineId); - team.setPlayerPrefix(Handler.componentToNMS(FormattedTextHelper.parse(line, ChatColor.WHITE))); + team.setPlayerPrefix(Handler.parseNMSComponent(line, PaperAPITools.BaseColor.WHITE)); generatedTeams.add(team); PacketHelperImpl.send(player, ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); PacketHelperImpl.send(player, new ClientboundSetScorePacket(lineId, obj1.getName(), this.scores[i], Optional.empty(), Optional.of(StyledFormat.SIDEBAR_DEFAULT))); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java index 0f3ef55965..623e14bbbe 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/ActionBarEventPacketHandlers.java @@ -1,10 +1,9 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.handlers.packet; import com.denizenscript.denizen.events.player.PlayerReceivesActionbarScriptEvent; -import com.denizenscript.denizen.nms.v1_21.Handler; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; import com.denizenscript.denizen.objects.PlayerTag; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.objects.core.ElementTag; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; @@ -22,9 +21,9 @@ public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNe return actionbarPacket; } event.reset(); - Component actionbarText = actionbarPacket.text(); - event.message = new ElementTag(FormattedTextHelper.stringify(Handler.componentToSpigot(actionbarText)), true); - event.rawJson = new ElementTag(CraftChatMessage.toJSON(actionbarText), true); + String rawJson = CraftChatMessage.toJSON(actionbarPacket.text()); + event.message = new ElementTag(PaperAPITools.instance.parseJsonToText(rawJson), true); + event.rawJson = new ElementTag(rawJson, true); event.system = new ElementTag(false); event.player = PlayerTag.mirrorBukkitPlayer(networkManager.player.getBukkitEntity()); event = (PlayerReceivesActionbarScriptEvent) event.triggerNow(); @@ -32,7 +31,7 @@ public static ClientboundSetActionBarTextPacket processActionbarPacket(DenizenNe return null; } if (event.modified) { - return new ClientboundSetActionBarTextPacket(Handler.componentToNMS(event.altMessageDetermination)); + return new ClientboundSetActionBarTextPacket(CraftChatMessage.fromJSON(event.rawJson.asString())); } return actionbarPacket; } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java index cd8abd286c..f016edd476 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/DenizenPacketHandlerPacketHandlers.java @@ -8,6 +8,7 @@ import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import org.bukkit.craftbukkit.v1_21_R5.util.CraftChatMessage; public class DenizenPacketHandlerPacketHandlers { @@ -37,7 +38,7 @@ else if (packet instanceof ClientboundPlayerChatPacket playerChatPacket) { return null; } if (result.modified) { - return new ClientboundSystemChatPacket(result.altMessageDetermination, isActionbar); + return new ClientboundSystemChatPacket(CraftChatMessage.fromJSON(result.rawJson.asString()), isActionbar); } } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/EntityMetadataPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/EntityMetadataPacketHandlers.java index ee538c2b83..a25e8e87d2 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/EntityMetadataPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/EntityMetadataPacketHandlers.java @@ -7,9 +7,8 @@ import com.denizenscript.denizen.scripts.commands.entity.InvisibleCommand; import com.denizenscript.denizen.scripts.commands.entity.RenameCommand; import com.denizenscript.denizen.scripts.commands.entity.SneakCommand; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.debugging.Debug; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; @@ -61,7 +60,7 @@ else if (nameToApply == null || (dataValue.id() != 2 && dataValue.id() != 3)) { data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_FLAGS, flags)); } if (nameToApply != null) { - data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.componentToNMS(FormattedTextHelper.parse(nameToApply, ChatColor.WHITE))))); + data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME, Optional.of(Handler.parseNMSComponent(nameToApply, PaperAPITools.BaseColor.WHITE)))); data.add(SynchedEntityData.DataValue.create(PacketHelperImpl.ENTITY_DATA_ACCESSOR_CUSTOM_NAME_VISIBLE, true)); } return new ClientboundSetEntityDataPacket(metadataPacket.id(), data); diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java index a23de7900f..79ef4b71f6 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/handlers/packet/TablistUpdateEventPacketHandlers.java @@ -4,13 +4,12 @@ import com.denizenscript.denizen.nms.v1_21.Handler; import com.denizenscript.denizen.nms.v1_21.impl.ProfileEditorImpl; import com.denizenscript.denizen.nms.v1_21.impl.network.handlers.DenizenNetworkManagerImpl; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.google.common.base.Joiner; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatColor; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; @@ -80,7 +79,7 @@ public static Packet processTablistPacket(DenizenNetwo } String modeText = update.gameMode() == null ? null : update.gameMode().name(); PlayerReceivesTablistUpdateScriptEvent.TabPacketData data = new PlayerReceivesTablistUpdateScriptEvent.TabPacketData(mode, profile.getId(), update.listed(), profile.getName(), - update.displayName() == null ? null : FormattedTextHelper.stringify(Handler.componentToSpigot(update.displayName())), modeText, texture, signature, update.latency()); + update.displayName() == null ? null : Handler.stringifyNMSComponent(update.displayName()), modeText, texture, signature, update.latency()); PlayerReceivesTablistUpdateScriptEvent.fire(networkManager.player.getBukkitEntity(), data); if (data.modified) { if (!isOverriding) { @@ -98,7 +97,7 @@ public static Packet processTablistPacket(DenizenNetwo newProfile.getProperties().put("textures", new Property("textures", data.texture, data.signature)); } ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(newProfile.getId(), newProfile, data.isListed, data.latency, data.gamemode == null ? null : GameType.byName(CoreUtilities.toLowerCase(data.gamemode)), - data.display == null ? null : Handler.componentToNMS(FormattedTextHelper.parse(data.display, ChatColor.WHITE)), update.showHat(), update.listOrder(), update.chatSession()); + data.display == null ? null : Handler.parseNMSComponent(data.display, PaperAPITools.BaseColor.WHITE), update.showHat(), update.listOrder(), update.chatSession()); networkManager.oldManager.send(ProfileEditorImpl.createInfoPacket(infoPacket.actions(), Collections.singletonList(entry))); } } diff --git a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java index 56ec98bb64..8ec7c2b23e 100644 --- a/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java +++ b/v1_21/src/main/java/com/denizenscript/denizen/nms/v1_21/impl/network/packets/PacketOutChatImpl.java @@ -1,7 +1,7 @@ package com.denizenscript.denizen.nms.v1_21.impl.network.packets; import com.denizenscript.denizen.nms.interfaces.packets.PacketOutChat; -import com.denizenscript.denizen.utilities.FormattedTextHelper; +import com.denizenscript.denizen.utilities.PaperAPITools; import net.md_5.bungee.chat.ComponentSerializer; import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; @@ -18,14 +18,14 @@ public class PacketOutChatImpl extends PacketOutChat { public PacketOutChatImpl(ClientboundSystemChatPacket internal) { systemPacket = internal; rawJson = CraftChatMessage.toJSON(internal.content()); - message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); isOverlayActionbar = internal.overlay(); } public PacketOutChatImpl(ClientboundPlayerChatPacket internal) { playerPacket = internal; rawJson = ComponentSerializer.toString(internal.body().content()); - message = FormattedTextHelper.stringify(FormattedTextHelper.parseJson(rawJson)); + message = PaperAPITools.instance.parseJsonToText(rawJson); } @Override