From bb470fc74241f6ed1e33cd612fb56f6f83ccb8a2 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Sun, 16 Jan 2022 16:30:28 -0500 Subject: [PATCH 01/11] First test This test was designed to maintain compatibility with Spigot. --- build.gradle | 7 +- src/main/java/ch/njol/skript/Skript.java | 15 +- .../njol/skript/classes/data/JavaClasses.java | 4 +- .../ch/njol/skript/command/ScriptCommand.java | 16 +- .../ch/njol/skript/effects/EffActionBar.java | 78 ---- .../ch/njol/skript/effects/EffMessage.java | 166 --------- .../ch/njol/skript/effects/EffSendTitle.java | 117 ------ .../njol/skript/expressions/ExprColoured.java | 108 ------ ...r.java => ExprPlayerListHeaderFooter.java} | 95 ++--- .../chat/expressions/ExprPrefixSuffix.java | 3 +- .../ch/njol/skript/lang/VariableString.java | 256 +++++-------- src/main/java/ch/njol/skript/util/Utils.java | 3 + .../njol/skript/util/chat/ChatMessages.java | 1 + .../skript/variables/FlatFileStorage.java | 3 +- .../skript/chat/ChatRegistration.java | 129 +++++++ .../skript/chat/elements}/EffBroadcast.java | 73 ++-- .../skript/chat/elements/EffMessage.java | 124 +++++++ .../skript/chat/elements/EffSendTitle.java | 142 ++++++++ .../skript/chat/elements/ExprColoured.java | 134 +++++++ .../skript/chat/elements/package-info.java | 23 ++ .../skriptlang/skript/chat/package-info.java | 23 ++ .../skript/chat/util/CodeConverter.java | 60 ++++ .../skript/chat/util/ComponentHandler.java | 338 ++++++++++++++++++ .../skript/chat/util/package-info.java | 23 ++ 24 files changed, 1177 insertions(+), 764 deletions(-) delete mode 100644 src/main/java/ch/njol/skript/effects/EffActionBar.java delete mode 100644 src/main/java/ch/njol/skript/effects/EffMessage.java delete mode 100644 src/main/java/ch/njol/skript/effects/EffSendTitle.java delete mode 100644 src/main/java/ch/njol/skript/expressions/ExprColoured.java rename src/main/java/ch/njol/skript/expressions/{ExprPlayerlistHeaderFooter.java => ExprPlayerListHeaderFooter.java} (53%) create mode 100644 src/main/java/io/skriptlang/skript/chat/ChatRegistration.java rename src/main/java/{ch/njol/skript/effects => io/skriptlang/skript/chat/elements}/EffBroadcast.java (54%) create mode 100644 src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java create mode 100644 src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java create mode 100644 src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java create mode 100644 src/main/java/io/skriptlang/skript/chat/elements/package-info.java create mode 100644 src/main/java/io/skriptlang/skript/chat/package-info.java create mode 100644 src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java create mode 100644 src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java create mode 100644 src/main/java/io/skriptlang/skript/chat/util/package-info.java diff --git a/build.gradle b/build.gradle index d934002f5e8..5fa4f1633ec 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,9 @@ allprojects { dependencies { shadow group: 'io.papermc', name: 'paperlib', version: '1.0.6' implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.17.1-R0.1-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.0.2-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.10.0-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.10.0-SNAPSHOT' implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.600' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT' @@ -76,10 +79,8 @@ tasks.withType(ShadowJar) { configurations = [ project.configurations.shadow ] - dependencies { - include(dependency('io.papermc:paperlib')) - } relocate 'io.papermc.lib', 'ch.njol.skript.paperlib' + relocate 'net.kyori', 'ch.njol.skript.kyori' manifest { attributes( 'Name': 'ch/njol/skript', diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index ee2c119899c..126248cd059 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -54,6 +54,8 @@ import java.util.zip.ZipFile; import ch.njol.skript.lang.Section; +import io.skriptlang.skript.chat.ChatRegistration; +import io.skriptlang.skript.chat.util.ComponentHandler; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -501,6 +503,7 @@ public void onEnable() { try { getAddonInstance().loadClasses("ch.njol.skript", "conditions", "effects", "events", "expressions", "entity", "sections"); + new ChatRegistration().register(getAddonInstance()); // TODO remove eventually } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); setEnabled(false); @@ -1759,13 +1762,13 @@ static void logEx(final String... lines) { // public void onLanguageChange() { // final String s = Language.get_("skript.prefix"); // if (s != null) -// SKRIPT_PREFIX = Utils.replaceEnglishChatStyles(s) + ChatColor.RESET + " "; +// SKRIPT_PREFIX = ComponentHandler.toLegacyString(s) + ChatColor.RESET + " "; // } // }); // } public static void info(final CommandSender sender, final String info) { - sender.sendMessage(SKRIPT_PREFIX + Utils.replaceEnglishChatStyles(info)); + sender.sendMessage(SKRIPT_PREFIX + ComponentHandler.toLegacyString(info)); } /** @@ -1774,11 +1777,11 @@ public static void info(final CommandSender sender, final String info) { * @see #adminBroadcast(String) */ public static void broadcast(final String message, final String permission) { - Bukkit.broadcast(SKRIPT_PREFIX + Utils.replaceEnglishChatStyles(message), permission); + Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message), permission); } public static void adminBroadcast(final String message) { - Bukkit.broadcast(SKRIPT_PREFIX + Utils.replaceEnglishChatStyles(message), "skript.admin"); + Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message), "skript.admin"); } /** @@ -1788,11 +1791,11 @@ public static void adminBroadcast(final String message) { * @param info */ public static void message(final CommandSender sender, final String info) { - sender.sendMessage(Utils.replaceEnglishChatStyles(info)); + sender.sendMessage(ComponentHandler.toLegacyString(info)); } public static void error(final CommandSender sender, final String error) { - sender.sendMessage(SKRIPT_PREFIX + ChatColor.DARK_RED + Utils.replaceEnglishChatStyles(error)); + sender.sendMessage(SKRIPT_PREFIX + ChatColor.DARK_RED + ComponentHandler.toLegacyString(error)); } /** diff --git a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java index 9f87be66e39..0437e0fc5f1 100644 --- a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java @@ -29,9 +29,9 @@ import ch.njol.skript.localization.Message; import ch.njol.skript.localization.RegexMessage; import ch.njol.skript.registrations.Classes; -import ch.njol.skript.util.Utils; import ch.njol.util.StringUtils; import ch.njol.yggdrasil.Fields; +import io.skriptlang.skript.chat.util.ComponentHandler; import org.eclipse.jdt.annotation.Nullable; import java.util.regex.Pattern; @@ -573,7 +573,7 @@ public String parse(String s, ParseContext context) { case SCRIPT: case EVENT: if (VariableString.isQuotedCorrectly(s, true)) - return Utils.replaceChatStyles("" + s.substring(1, s.length() - 1).replace("\"\"", "\"")); + return ComponentHandler.toLegacyString("" + s.substring(1, s.length() - 1).replace("\"\"", "\"")); return null; case COMMAND: return s; diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index 007cbec8871..24fa53435d5 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -32,6 +32,7 @@ import java.util.Set; import java.util.UUID; +import io.skriptlang.skript.chat.util.ComponentHandler; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -69,9 +70,6 @@ import ch.njol.skript.util.Date; import ch.njol.skript.util.EmptyStacktraceException; import ch.njol.skript.util.Timespan; -import ch.njol.skript.util.Utils; -import ch.njol.skript.util.chat.BungeeConverter; -import ch.njol.skript.util.chat.MessageComponent; import ch.njol.skript.variables.Variables; import ch.njol.util.StringUtils; import ch.njol.util.Validate; @@ -153,8 +151,8 @@ public ScriptCommand(final File script, final String name, final String pattern, this.aliases = aliases; activeAliases = new ArrayList<>(aliases); - this.description = Utils.replaceEnglishChatStyles(description); - this.usage = Utils.replaceEnglishChatStyles(usage); + this.description = ComponentHandler.toLegacyString(description); + this.usage = ComponentHandler.toLegacyString(usage); this.executableBy = executableBy; @@ -211,13 +209,7 @@ public boolean execute(final CommandSender sender, final String commandLabel, fi final ScriptCommandEvent event = new ScriptCommandEvent(ScriptCommand.this, sender); if (!permission.isEmpty() && !sender.hasPermission(permission)) { - if (sender instanceof Player) { - List components = - permissionMessage.getMessageComponents(event); - ((Player) sender).spigot().sendMessage(BungeeConverter.convert(components)); - } else { - sender.sendMessage(permissionMessage.getSingle(event)); - } + ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parseFromSingleExpression(event, permissionMessage)); return false; } diff --git a/src/main/java/ch/njol/skript/effects/EffActionBar.java b/src/main/java/ch/njol/skript/effects/EffActionBar.java deleted file mode 100644 index 980e7d7974c..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffActionBar.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.effects; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.util.chat.BungeeConverter; -import ch.njol.skript.util.chat.ChatMessages; -import ch.njol.util.Kleenean; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.BaseComponent; - -@Name("Action Bar") -@Description("Sends an action bar message to the given player(s).") -@Examples("send action bar \"Hello player!\" to player") -@Since("2.3") -public class EffActionBar extends Effect { - - static { - Skript.registerEffect(EffActionBar.class, "send [the] action bar [with text] %string% to %players%"); - } - - @SuppressWarnings("null") - private Expression message; - - @SuppressWarnings("null") - private Expression recipients; - - @SuppressWarnings({"unchecked", "null"}) - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final SkriptParser.ParseResult parser) { - message = (Expression) exprs[0]; - recipients = (Expression) exprs[1]; - return true; - } - - @SuppressWarnings("deprecation") - @Override - protected void execute(final Event e) { - String msg = message.getSingle(e); - assert msg != null; - BaseComponent[] components = BungeeConverter.convert(ChatMessages.parseToArray(msg)); - for (Player player : recipients.getArray(e)) - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, components); - } - - @Override - public String toString(final @Nullable Event e, final boolean debug) { - return "send action bar " + message.toString(e, debug) + " to " + recipients.toString(e, debug); - } - -} \ No newline at end of file diff --git a/src/main/java/ch/njol/skript/effects/EffMessage.java b/src/main/java/ch/njol/skript/effects/EffMessage.java deleted file mode 100644 index c6769c722e4..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffMessage.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.effects; - -import java.util.List; -import java.util.UUID; - -import ch.njol.skript.registrations.Classes; -import ch.njol.skript.util.LiteralUtils; -import ch.njol.skript.util.chat.MessageComponent; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.ExprColoured; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionList; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.VariableString; -import ch.njol.skript.util.chat.BungeeConverter; -import ch.njol.skript.util.chat.ChatMessages; -import ch.njol.util.Kleenean; -import net.md_5.bungee.api.chat.BaseComponent; - -@Name("Message") -@Description({"Sends a message to the given player. Only styles written", - "in given string or in formatted expressions will be parsed.", - "Adding an optional sender allows the messages to be sent as if a specific player sent them.", - "This is useful with Minecraft 1.16.4's new chat ignore system, in which players can choose to ignore other players,", - "but for this to work, the message needs to be sent from a player."}) -@Examples({"message \"A wild %player% appeared!\"", - "message \"This message is a distraction. Mwahaha!\"", - "send \"Your kill streak is %{kill streak::%uuid of player%}%.\" to player", - "if the targeted entity exists:", - "\tmessage \"You're currently looking at a %type of the targeted entity%!\"", - "on chat:", - "\tcancel event", - "\tsend \"[%player%] >> %message%\" to all players from player"}) -@RequiredPlugins("Minecraft 1.16.4+ for optional sender") -@Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") -public class EffMessage extends Effect { - - private static final boolean SUPPORTS_SENDER = Skript.classExists("org.bukkit.command.CommandSender$Spigot") && - Skript.methodExists(CommandSender.Spigot.class, "sendMessage", UUID.class, BaseComponent.class); - - static { - if (SUPPORTS_SENDER) - Skript.registerEffect(EffMessage.class, "(message|send [message[s]]) %objects% [to %commandsenders%] [from %-player%]"); - else - Skript.registerEffect(EffMessage.class, "(message|send [message[s]]) %objects% [to %commandsenders%]"); - } - - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression[] messages; - - /** - * Used for {@link EffMessage#toString(Event, boolean)} - */ - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; - - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression recipients; - - @Nullable - private Expression sender; - - @SuppressWarnings({"unchecked", "null"}) - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) { - messageExpr = LiteralUtils.defendExpression(exprs[0]); - - messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[] {messageExpr}; - recipients = (Expression) exprs[1]; - if (SUPPORTS_SENDER) - sender = (Expression) exprs[2]; - return LiteralUtils.canInitSafely(messageExpr); - } - - @Override - protected void execute(Event e) { - Player sender = this.sender != null ? this.sender.getSingle(e) : null; - - CommandSender[] commandSenders = recipients.getArray(e); - - for (Expression message : messages) { - - Object[] messageArray = null; - List messageComponents = null; - - for (CommandSender receiver : commandSenders) { - if (receiver instanceof Player && message instanceof VariableString) { - if (messageComponents == null) - messageComponents = ((VariableString) message).getMessageComponents(e); - } else { - if (messageArray == null) - messageArray = message.getArray(e); - } - - if (receiver instanceof Player) { // Can use JSON formatting - if (message instanceof VariableString) { // Process formatting that is safe - sendMessage((Player) receiver, sender, - BungeeConverter.convert(messageComponents) - ); - } else if (message instanceof ExprColoured && ((ExprColoured) message).isUnsafeFormat()) { // Manually marked as trusted - for (Object object : messageArray) { - sendMessage((Player) receiver, sender, BungeeConverter.convert(ChatMessages.parse((String) object))); - } - } else { // It is just a string, no idea if it comes from a trusted source -> don't parse anything - for (Object object : messageArray) { - List components = ChatMessages.fromParsedString(toString(object)); - sendMessage((Player) receiver, sender, BungeeConverter.convert(components)); - } - } - } else { // Not a player, send plain text with legacy formatting - for (Object object : messageArray) { - receiver.sendMessage(toString(object)); - } - } - } - } - } - - private void sendMessage(Player receiver, @Nullable Player sender, BaseComponent... components) { - if (SUPPORTS_SENDER && sender != null) - receiver.spigot().sendMessage(sender.getUniqueId(), components); - else - receiver.spigot().sendMessage(components); - } - - private String toString(Object object) { - return object instanceof String ? (String) object : Classes.toString(object); - } - - @Override - public String toString(@Nullable Event e, boolean debug) { - return "send " + messageExpr.toString(e, debug) + " to " + recipients.toString(e, debug) + - (sender != null ? " from " + sender.toString(e, debug) : ""); - } - -} diff --git a/src/main/java/ch/njol/skript/effects/EffSendTitle.java b/src/main/java/ch/njol/skript/effects/EffSendTitle.java deleted file mode 100644 index fb2e0465eae..00000000000 --- a/src/main/java/ch/njol/skript/effects/EffSendTitle.java +++ /dev/null @@ -1,117 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.effects; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.lang.Effect; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.Timespan; -import ch.njol.util.Kleenean; - -@Name("Title - Send") -@Description({"Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above.", - "Note: if no input is given for the title/subtitle or the times," + - "it will keep the ones from the last title sent, use the reset title effect to restore the default values."}) -@Examples({"send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", - "send title \"Hi %player%\" to player", "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", - "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", - "send subtitle \"Party!\" to all players"}) -@Since("2.3") -public class EffSendTitle extends Effect { - - private final static boolean TIME_SUPPORTED = Skript.methodExists(Player.class,"sendTitle", String.class, String.class, int.class, int.class, int.class); - - static { - if (TIME_SUPPORTED) - Skript.registerEffect(EffSendTitle.class, - "send title %string% [with subtitle %-string%] [to %players%] [for %-timespan%] [with fade[(-| )]in %-timespan%] [(and|with) fade[(-| )]out %-timespan%]", - "send subtitle %string% [to %players%] [for %-timespan%] [with fade[(-| )]in %-timespan%] [(and|with) fade[(-| )]out %-timespan%]"); - else - Skript.registerEffect(EffSendTitle.class, - "send title %string% [with subtitle %-string%] [to %players%]", - "send subtitle %string% [to %players%]"); - - } - - @Nullable - private Expression title; - @Nullable - private Expression subtitle; - @SuppressWarnings("null") - private Expression recipients; - @Nullable - private Expression fadeIn, stay, fadeOut; - - @SuppressWarnings({"unchecked", "null"}) - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) { - title = matchedPattern == 0 ? (Expression) exprs[0] : null; - subtitle = (Expression) exprs[1 - matchedPattern]; - recipients = (Expression) exprs[2 - matchedPattern]; - if (TIME_SUPPORTED) { - stay = (Expression) exprs[3 - matchedPattern]; - fadeIn = (Expression) exprs[4 - matchedPattern]; - fadeOut = (Expression) exprs[5 - matchedPattern]; - } - return true; - } - - @SuppressWarnings("null") - @Override - protected void execute(final Event e) { - String title = this.title != null ? this.title.getSingle(e) : "", - sub = subtitle != null ? subtitle.getSingle(e) : null; - - if (TIME_SUPPORTED) { - int in = fadeIn != null ? (int) fadeIn.getSingle(e).getTicks_i() : -1, - stay = this.stay != null ? (int) this.stay.getSingle(e).getTicks_i() : -1, - out = fadeOut != null ? (int) fadeOut.getSingle(e).getTicks_i() : -1; - - for (Player p : recipients.getArray(e)) - p.sendTitle(title, sub, in, stay, out); - } else { - for (Player p : recipients.getArray(e)) - p.sendTitle(title, sub); - } - } - - // TODO: util method to simplify this - @Override - public String toString(final @Nullable Event e, final boolean debug) { - String title = this.title != null ? this.title.toString(e, debug) : "", - sub = subtitle != null ? subtitle.toString(e, debug) : "", - in = fadeIn != null ? fadeIn.toString(e, debug) : "", - stay = this.stay != null ? this.stay.toString(e, debug) : "", - out = fadeOut != null ? this.fadeOut.toString(e, debug) : ""; - return ("send title " + title + - sub == "" ? "" : " with subtitle " + sub) + " to " + - recipients.toString(e, debug) + (TIME_SUPPORTED ? - " for " + stay + " with fade in " + in + " and fade out" + out : ""); - } - -} diff --git a/src/main/java/ch/njol/skript/expressions/ExprColoured.java b/src/main/java/ch/njol/skript/expressions/ExprColoured.java deleted file mode 100644 index 279a00d5ed1..00000000000 --- a/src/main/java/ch/njol/skript/expressions/ExprColoured.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.expressions; - -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.classes.Converter; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.PropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.Utils; -import ch.njol.skript.util.chat.ChatMessages; -import ch.njol.util.Kleenean; - -@Name("Coloured / Uncoloured") -@Description({"Parses <colour>s and, optionally, chat styles in a message or removes", - "any colours and chat styles from the message. Parsing all", - "chat styles requires this expression to be used in same line with", - "the send effect."}) -@Examples({"on chat:", - " set message to coloured message # Safe; only colors get parsed", - "command /fade <player>:", - " trigger:", - " set display name of the player-argument to uncoloured display name of the player-argument", - "command /format <text>:", - " trigger:", - " message formatted text-argument # Safe, because we're sending to whoever used this command"}) -@Since("2.0") -public class ExprColoured extends PropertyExpression { - static { - Skript.registerExpression(ExprColoured.class, String.class, ExpressionType.COMBINED, - "(colo[u]r-|colo[u]red )%strings%", - "(format-|formatted )%strings%", - "(un|non)[-](colo[u]r-|colo[u]red |format-|formatted )%strings%"); - } - - /** - * If colors should be parsed. - */ - boolean color; - - /** - * If all styles should be parsed whenever possible. - */ - boolean format; - - @SuppressWarnings({"unchecked", "null"}) - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { - setExpr((Expression) exprs[0]); - color = matchedPattern <= 1; // colored and formatted - format = matchedPattern == 1; - return true; - } - - @Override - protected String[] get(final Event e, final String[] source) { - return get(source, new Converter() { - @Override - public String convert(final String s) { - return color ? Utils.replaceChatStyles(s) : "" + ChatMessages.stripStyles(s); - } - }); - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - public String toString(final @Nullable Event e, final boolean debug) { - return (color ? "" : "un") + "coloured " + getExpr().toString(e, debug); - } - - /** - * If parent of this expression should try to parse all styles instead of - * just colors. This is unsafe to do with untrusted user input. - * @return If unsafe formatting was requested in script. - */ - public boolean isUnsafeFormat() { - return format; - } - -} diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlayerlistHeaderFooter.java b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java similarity index 53% rename from src/main/java/ch/njol/skript/expressions/ExprPlayerlistHeaderFooter.java rename to src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java index abbc1327694..c8dc302014c 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprPlayerlistHeaderFooter.java +++ b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java @@ -18,90 +18,91 @@ */ package ch.njol.skript.expressions; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.classes.Changer; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.expressions.base.SimplePropertyExpression; import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; @Name("Player List Header and Footer") @Description("The message above and below the player list in the tab menu.") -@Examples({"set all players' tab list header to \"Welcome to the Server!\"", - "send \"%the player's tab list header%\" to player", - "reset all players' tab list header"}) +@Examples({ + "set all players' tab list header to \"Welcome to the Server!\"", + "send \"%the player's tab list header%\" to player", + "reset all players' tab list header" +}) @Since("2.4") -@RequiredPlugins("Minecraft 1.13 or newer") -public class ExprPlayerlistHeaderFooter extends SimplePropertyExpression { - +public class ExprPlayerListHeaderFooter extends SimplePropertyExpression { + static { - if (Skript.methodExists(Player.class, "setPlayerListHeaderFooter", String.class, String.class)) //This method is only present if the header and footer methods we use are - PropertyExpression.register(ExprPlayerlistHeaderFooter.class, String.class, "(player|tab)[ ]list (header|1¦footer) [(text|message)]", "players"); + PropertyExpression.register(ExprPlayerListHeaderFooter.class, String.class, "(player|tab)[ ]list (header|1¦footer) [(text|message)]", "players"); } - - private static final int HEADER = 0, FOOTER = 1; - - private int mark; - + + private boolean isHeader; + @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - mark = parseResult.mark; + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + isHeader = parseResult.mark == 0; return super.init(exprs, matchedPattern, isDelayed, parseResult); } - - @Nullable + @Override + @Nullable public String convert(Player player) { - if (mark == HEADER) - return player.getPlayerListHeader(); - else if (mark == FOOTER) - return player.getPlayerListFooter(); - assert false; - return null; + return isHeader ? player.getPlayerListHeader() : player.getPlayerListFooter(); } - + @Override @Nullable - public Class[] acceptChange(Changer.ChangeMode mode) { + public Class[] acceptChange(ChangeMode mode) { switch (mode) { case SET: case DELETE: case RESET: - return CollectionUtils.array(String.class); + return CollectionUtils.array(String[].class, Component.class); + default: + return null; } - return null; } - + @Override - public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { - final String text = delta == null ? "" : (String) delta[0]; - for (Player player : getExpr().getArray(e)) { - if (mark == HEADER) { - player.setPlayerListHeader(text); - } else if (mark == FOOTER) { - player.setPlayerListFooter(text); - } + public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { + Component component; + if (delta == null) { + component = Component.empty(); + } else if (delta[0] instanceof Component) { + component = (Component) delta[0]; + } else { + component = ComponentHandler.parse(String.join("\n", (String[]) delta), false); + } + Audience audience = ComponentHandler.audienceFrom(getExpr().getArray(e)); + if (isHeader) { + audience.sendPlayerListHeader(component); + } else { + audience.sendPlayerListFooter(component); } } - + @Override public Class getReturnType() { return String.class; } - + @Override protected String getPropertyName() { - return "player list " + (mark == HEADER ? "header" : mark == FOOTER ? "footer" : ""); + return "player list " + (isHeader ? "header" : "footer"); } + } diff --git a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java index b36fa02718e..2fc5ff4bff7 100644 --- a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java +++ b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.hooks.chat.expressions; +import io.skriptlang.skript.chat.util.ComponentHandler; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -59,7 +60,7 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final @Override public String convert(final Player p) { - return Utils.replaceChatStyles(prefix ? "" + VaultHook.chat.getPlayerPrefix(p) : "" + VaultHook.chat.getPlayerSuffix(p)); + return ComponentHandler.toLegacyString(prefix ? "" + VaultHook.chat.getPlayerPrefix(p) : "" + VaultHook.chat.getPlayerSuffix(p)); } @Override diff --git a/src/main/java/ch/njol/skript/lang/VariableString.java b/src/main/java/ch/njol/skript/lang/VariableString.java index ee4712df2e1..aade214a3b4 100644 --- a/src/main/java/ch/njol/skript/lang/VariableString.java +++ b/src/main/java/ch/njol/skript/lang/VariableString.java @@ -20,24 +20,21 @@ import ch.njol.skript.Skript; import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.expressions.ExprColoured; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.log.BlockingLogHandler; import ch.njol.skript.log.RetainingLogHandler; import ch.njol.skript.log.SkriptLogger; import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.StringMode; -import ch.njol.skript.util.Utils; -import ch.njol.skript.util.chat.ChatMessages; -import ch.njol.skript.util.chat.MessageComponent; import ch.njol.util.Checker; import ch.njol.util.Kleenean; import ch.njol.util.StringUtils; import ch.njol.util.coll.CollectionUtils; import ch.njol.util.coll.iterator.SingleItemIterator; -import org.bukkit.ChatColor; +import io.skriptlang.skript.chat.elements.ExprColoured; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.text.Component; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -57,20 +54,16 @@ public class VariableString implements Expression { @Nullable private final Object[] string; - @Nullable - private Object[] stringUnformatted; - private final boolean isSimple; + @Nullable private final String simple; @Nullable - private final String simpleUnformatted; + private final Component simpleComponent; + @Nullable + private final String simpleResolved; + + private final boolean isSimple; private final StringMode mode; - - /** - * Message components that this string consists of. Only simple parts have - * been evaluated here. - */ - private final MessageComponent[] components; /** * Creates a new VariableString which does not contain variables. @@ -78,14 +71,13 @@ public class VariableString implements Expression { */ private VariableString(String s) { isSimple = true; - simpleUnformatted = s.replace("%%", "%"); // This doesn't contain variables, so this wasn't done in newInstance! - simple = Utils.replaceChatStyles(simpleUnformatted); + simple = s.replace("%%", "%"); // This doesn't contain variables, so this wasn't done in newInstance! + simpleComponent = ComponentHandler.parse(s); + simpleResolved = ComponentHandler.toLegacyString(simpleComponent); orig = simple; string = null; mode = StringMode.MESSAGE; - - components = new MessageComponent[] {ChatMessages.plainText(simpleUnformatted)}; } /** @@ -96,31 +88,15 @@ private VariableString(String s) { */ private VariableString(String orig, Object[] string, StringMode mode) { this.orig = orig; - this.string = new Object[string.length]; - this.stringUnformatted = new Object[string.length]; - - // Construct unformatted string and components - List components = new ArrayList<>(string.length); - for (int i = 0; i < string.length; i++) { - Object o = string[i]; - if (o instanceof String) { - this.string[i] = Utils.replaceChatStyles((String) o); - components.addAll(ChatMessages.parse((String) o)); - } else { - this.string[i] = o; - components.add(null); // Not known parse-time - } - - // For unformatted string, don't format stuff - this.stringUnformatted[i] = o; - } - this.components = components.toArray(new MessageComponent[0]); + + this.string = string; this.mode = mode; isSimple = false; simple = null; - simpleUnformatted = null; + simpleComponent = null; + simpleResolved = null; } /** @@ -351,157 +327,56 @@ public static VariableString[] makeStringsFromQuoted(List args) { /** * Parses all expressions in the string and returns it. * If this is a simple string, the event may be null. + * + * Simple formatting (colors) will be processed. * * @param e Event to pass to the expressions. * @return The input string with all expressions replaced. + * @see #toString(boolean, Event) */ public String toString(@Nullable Event e) { - if (isSimple) { - assert simple != null; - return simple; - } - - if (e == null) { - throw new IllegalArgumentException("Event may not be null in non-simple VariableStrings!"); - } - - Object[] string = this.string; - assert string != null; - StringBuilder b = new StringBuilder(); - for (Object o : string) { - if (o instanceof Expression) { - b.append(Classes.toString(((Expression) o).getArray(e), true, mode)); - } else { - b.append(o); - } - } - return b.toString(); + return toString(true, e); } - + /** * Parses all expressions in the string and returns it. - * Does not parse formatting codes! + * If this is a simple string, the event may be null. + * + * @param format Whether simple formatting (colors) should be processed. * @param e Event to pass to the expressions. * @return The input string with all expressions replaced. */ - public String toUnformattedString(Event e) { + public String toString(boolean format, @Nullable Event e) { if (isSimple) { - assert simpleUnformatted != null; - return simpleUnformatted; + if (format) { + assert simpleResolved != null; + return simpleResolved; + } else { + assert simple != null; + return simple; + } } - Object[] string = this.stringUnformatted; + + if (e == null) { + throw new IllegalArgumentException("Event may not be null in non-simple VariableStrings!"); + } + + Object[] string = this.string; assert string != null; StringBuilder b = new StringBuilder(); for (Object o : string) { if (o instanceof Expression) { + boolean escape = !(o instanceof ExprColoured) && format; + if (escape) + b.append("
");
 				b.append(Classes.toString(((Expression) o).getArray(e), true, mode));
+				if (escape)
+					b.append("
"); } else { b.append(o); } } - return b.toString(); - } - - /** - * Gets message components from this string. Formatting is parsed only - * in simple parts for security reasons. - * @param e Currently running event. - * @return Message components. - */ - public List getMessageComponents(Event e) { - if (isSimple) { // Trusted, constant string in a script - assert simpleUnformatted != null; - return ChatMessages.parse(simpleUnformatted); - } - - // Parse formating - Object[] string = this.stringUnformatted; - assert string != null; - List message = new ArrayList<>(components.length); // At least this much space - int stringPart = -1; - MessageComponent previous = null; - for (MessageComponent component : components) { - if (component == null) { // This component holds place for variable part - // Go over previous expression part (stringPart >= 0) or take first part (stringPart == 0) - stringPart++; - if (previous != null) { // Also jump over literal part - stringPart++; - } - Object o = string[stringPart]; - previous = null; - - // Convert it to plain text - String text = null; - if (o instanceof ExprColoured && ((ExprColoured) o).isUnsafeFormat()) { // Special case: user wants to process formatting - String unformatted = Classes.toString(((ExprColoured) o).getArray(e), true, mode); - if (unformatted != null) { - message.addAll(ChatMessages.parse(unformatted)); - } - continue; - } else if (o instanceof Expression) { - text = Classes.toString(((Expression) o).getArray(e), true, mode); - } - - assert text != null; - List components = ChatMessages.fromParsedString(text); - if (!message.isEmpty()) { // Copy styles from previous component - int startSize = message.size(); - for (int i = 0; i < components.size(); i++) { - MessageComponent plain = components.get(i); - ChatMessages.copyStyles(message.get(startSize + i - 1), plain); - message.add(plain); - } - } else { - message.addAll(components); - } - } else { - MessageComponent componentCopy = component.copy(); - if (!message.isEmpty()) { // Copy styles from previous component - ChatMessages.copyStyles(message.get(message.size() - 1), componentCopy); - } - message.add(componentCopy); - previous = componentCopy; - } - } - - return message; - } - - /** - * Gets message components from this string. Formatting is parsed - * everywhere, which is a potential security risk. - * @param e Currently running event. - * @return Message components. - */ - public List getMessageComponentsUnsafe(Event e) { - if (isSimple) { // Trusted, constant string in a script - assert simpleUnformatted != null; - return ChatMessages.parse(simpleUnformatted); - } - - return ChatMessages.parse(toUnformattedString(e)); - } - - /** - * Parses all expressions in the string and returns it in chat JSON format. - * - * @param e Event to pass to the expressions. - * @return The input string with all expressions replaced. - */ - public String toChatString(Event e) { - return ChatMessages.toJson(getMessageComponents(e)); - } - - @Nullable - private static ChatColor getLastColor(CharSequence s) { - for (int i = s.length() - 2; i >= 0; i--) { - if (s.charAt(i) == ChatColor.COLOR_CHAR) { - ChatColor c = ChatColor.getByChar(s.charAt(i + 1)); - if (c != null && (c.isColor() || c == ChatColor.RESET)) - return c; - } - } - return null; + return format ? ComponentHandler.toLegacyString(b.toString()) : b.toString(); } @Override @@ -531,6 +406,18 @@ public String toString(@Nullable Event e, boolean debug) { b.append('"'); return b.toString(); } + + public Component getAsComponent(@Nullable Event e) { + if (isSimple) { + assert simpleComponent != null; + return simpleComponent; + } + + if (e == null) + throw new IllegalArgumentException("Event may not be null in non-simple VariableStrings!"); + + return ComponentHandler.parse(toString(false, e)); + } public String getDefaultVariableName() { if (isSimple) { @@ -610,13 +497,40 @@ public boolean check(Event e, Checker c, boolean negated) { public boolean check(Event e, Checker c) { return SimpleExpression.check(getAll(e), c, false, false); } - - @SuppressWarnings("unchecked") + @Override @Nullable + @SuppressWarnings("unchecked") public Expression getConvertedExpression(Class... to) { if (CollectionUtils.containsSuperclass(to, String.class)) return (Expression) this; + if (CollectionUtils.containsSuperclass(to, Component.class)) + return new SimpleExpression() { + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + throw new UnsupportedOperationException(); + } + + @Override + protected @Nullable R[] get(Event e) { + return (R[]) new Component[]{getAsComponent(e)}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return (Class) Component.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return VariableString.this.toString(e, debug); + } + }; return null; } diff --git a/src/main/java/ch/njol/skript/util/Utils.java b/src/main/java/ch/njol/skript/util/Utils.java index 8a46dab7d06..7769f0b2f21 100644 --- a/src/main/java/ch/njol/skript/util/Utils.java +++ b/src/main/java/ch/njol/skript/util/Utils.java @@ -511,7 +511,9 @@ public static String getChatStyle(final String s) { * * @param message * @return message with localised chat styles converted to Minecraft's format + * @deprecated Use {@link io.skriptlang.skript.chat.util.ComponentHandler#toLegacyString(String)} */ + @Deprecated public static String replaceChatStyles(final String message) { if (message.isEmpty()) return message; @@ -549,6 +551,7 @@ public String run(final Matcher m) { * * @param message * @return message with english chat styles converted to Minecraft's format + * @deprecated Use {@link io.skriptlang.skript.chat.util.ComponentHandler#toLegacyString(String)} */ public static String replaceEnglishChatStyles(final String message) { if (message.isEmpty()) diff --git a/src/main/java/ch/njol/skript/util/chat/ChatMessages.java b/src/main/java/ch/njol/skript/util/chat/ChatMessages.java index b68718abefe..a91309a627d 100644 --- a/src/main/java/ch/njol/skript/util/chat/ChatMessages.java +++ b/src/main/java/ch/njol/skript/util/chat/ChatMessages.java @@ -592,4 +592,5 @@ public static String stripStyles(String text) { assert plain != null; return plain; } + } diff --git a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java index 534c8378f64..c5e0808e79d 100644 --- a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java +++ b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java @@ -34,6 +34,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.skriptlang.skript.chat.util.ComponentHandler; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; @@ -141,7 +142,7 @@ protected boolean load_i(final SectionNode n) { continue; } if (d instanceof String && update2_0_beta3) { - d = Utils.replaceChatStyles((String) d); + d = ComponentHandler.toLegacyString((String) d); } Variables.variableLoaded("" + split[0], d, this); } diff --git a/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java b/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java new file mode 100644 index 00000000000..ea90693d66b --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java @@ -0,0 +1,129 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat; + +import ch.njol.skript.SkriptAddon; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.registrations.Classes; +import ch.njol.skript.registrations.Converters; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.text.Component; + +import java.io.IOException; + +import static io.skriptlang.skript.chat.util.ComponentHandler.registerPlaceholder; + +public class ChatRegistration { + + public void register(SkriptAddon addon) { + + try { + addon.loadClasses("io.skriptlang.skript.chat.elements"); + } catch (IOException e) { + e.printStackTrace(); + } + + Converters.registerConverter(String.class, Component.class, ComponentHandler::parse); + Converters.registerConverter(Component.class, String.class, ComponentHandler::toLegacyString); + + Classes.registerClass(new ClassInfo<>(Component.class, "component") + .user("components?") + .name("Component") + .since("INSERT VERSION") + .parser(new Parser() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(Component component, int flags) { + return ComponentHandler.toLegacyString(component); + } + + @Override + public String toVariableNameString(Component component) { + return "component:" + component; + } + }) + ); + + // Just to initialize it now + ComponentHandler.getAdventure(); + + registerPlaceholder("dark_cyan", ""); + registerPlaceholder("dark_turquoise", ""); + registerPlaceholder("dark cyan", ""); + registerPlaceholder("dark turquoise", ""); + registerPlaceholder("cyan", ""); + + registerPlaceholder("purple", ""); + + registerPlaceholder("dark_yellow", ""); + registerPlaceholder("dark yellow", ""); + registerPlaceholder("orange", ""); + + registerPlaceholder("light_grey", ""); + registerPlaceholder("light_gray", ""); + registerPlaceholder("light grey", ""); + registerPlaceholder("light gray", ""); + registerPlaceholder("silver", ""); + + registerPlaceholder("dark_silver", ""); + registerPlaceholder("dark silver", ""); + + registerPlaceholder("light_blue", ""); + registerPlaceholder("light blue", ""); + registerPlaceholder("indigo", ""); + + registerPlaceholder("light_green", ""); + registerPlaceholder("lime_green", ""); + registerPlaceholder("light green", ""); + registerPlaceholder("lime green", ""); + registerPlaceholder("lime", ""); + + registerPlaceholder("light_cyan", ""); + registerPlaceholder("light_aqua", ""); + registerPlaceholder("light cyan", ""); + registerPlaceholder("light aqua", ""); + registerPlaceholder("turquoise", ""); + + registerPlaceholder("light_red", ""); + registerPlaceholder("light red", ""); + + registerPlaceholder("pink", ""); + registerPlaceholder("magenta", ""); + + registerPlaceholder("light_yellow", ""); + registerPlaceholder("light yellow", ""); + + registerPlaceholder("underline", ""); + + registerPlaceholder(tag -> { + if (tag.startsWith("unicode:u") && tag.length() == 13) { + return Component.text(("\\" + tag.substring(8)).toCharArray()[0]); + } + return null; + }); + + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffBroadcast.java b/src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java similarity index 54% rename from src/main/java/ch/njol/skript/effects/EffBroadcast.java rename to src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java index 869a37e93f7..72c184d576b 100644 --- a/src/main/java/ch/njol/skript/effects/EffBroadcast.java +++ b/src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java @@ -16,25 +16,17 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.effects; +package io.skriptlang.skript.chat.elements; import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.ExprColoured; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionList; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.VariableString; -import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.LiteralUtils; -import ch.njol.skript.util.chat.BungeeConverter; -import ch.njol.skript.util.chat.ChatMessages; import ch.njol.util.Kleenean; -import net.md_5.bungee.api.chat.BaseComponent; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.audience.Audience; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.command.CommandSender; @@ -44,69 +36,46 @@ import java.util.ArrayList; import java.util.List; -@Name("Broadcast") -@Description("Broadcasts a message to the server.") -@Examples({ - "broadcast \"Welcome %player% to the server!\"", - "broadcast \"Woah! It's a message!\"" -}) -@Since("1.0, 2.6 (broadcasting objects), INSERT VERSION (using advanced formatting)") public class EffBroadcast extends Effect { - static { - Skript.registerEffect(EffBroadcast.class, "broadcast %objects% [(to|in) %-worlds%]"); - } - - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression messageExpr; // Used in toString @Nullable private Expression worlds; - @SuppressWarnings("unchecked") + static { + Skript.registerEffect(EffBroadcast.class, "broadcast %objects% [(to|in) %-worlds%]"); + } + @Override + @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { messageExpr = LiteralUtils.defendExpression(exprs[0]); messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[] {messageExpr}; + ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; worlds = (Expression) exprs[1]; return LiteralUtils.canInitSafely(messageExpr); } - + @Override - @SuppressWarnings("deprecation") - public void execute(Event e) { - List receivers = new ArrayList<>(); + protected void execute(Event e) { + List recipients = new ArrayList<>(); if (worlds == null) { - receivers.addAll(Bukkit.getOnlinePlayers()); - receivers.add(Bukkit.getConsoleSender()); + recipients.addAll(Bukkit.getOnlinePlayers()); + recipients.add(Bukkit.getConsoleSender()); } else { for (World world : worlds.getArray(e)) - receivers.addAll(world.getPlayers()); - } - - for (Expression message : messages) { - if (message instanceof VariableString) { - BaseComponent[] components = BungeeConverter.convert(((VariableString) message).getMessageComponents(e)); - receivers.forEach(receiver -> receiver.spigot().sendMessage(components)); - } else if (message instanceof ExprColoured && ((ExprColoured) message).isUnsafeFormat()) { // Manually marked as trusted - for (Object realMessage : message.getArray(e)) { - BaseComponent[] components = BungeeConverter.convert(ChatMessages.parse((String) realMessage)); - receivers.forEach(receiver -> receiver.spigot().sendMessage(components)); - } - } else { - for (Object messageObject : message.getArray(e)) { - String realMessage = messageObject instanceof String ? (String) messageObject : Classes.toString(messageObject); - receivers.forEach(receiver -> receiver.sendMessage(realMessage)); - } - } + recipients.addAll(world.getPlayers()); } + Audience audience = ComponentHandler.audienceFrom(recipients); + ComponentHandler.parseFromExpressions(e, messages).forEach(audience::sendMessage); } - + @Override public String toString(@Nullable Event e, boolean debug) { return "broadcast " + messageExpr.toString(e, debug) + (worlds == null ? "" : " to " + worlds.toString(e, debug)); } - + } diff --git a/src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java b/src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java new file mode 100644 index 00000000000..8ff0811a01c --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java @@ -0,0 +1,124 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionList; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.LiteralUtils; +import ch.njol.util.Kleenean; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.identity.Identity; +import net.kyori.adventure.text.Component; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.List; + +@Name("Send Message") +@Description({ + "Sends a message to the given player. Only styles written", + "in given string or in formatted expressions will be parsed.", + "Adding an optional sender allows the messages to be sent as if a specific player sent them.", + "This is useful with Minecraft 1.16.4's new chat ignore system, in which players can choose to ignore other players,", + "but for this to work, the message needs to be sent from a player." +}) +@Examples({ + "message \"A wild %player% appeared!\"", + "message \"This message is a distraction. Mwahaha!\"", + "send \"Your kill streak is %{kill streak::%uuid of player%}%.\" to player", + "if the targeted entity exists:", + "\tmessage \"You're currently looking at a %type of the targeted entity%!\"", + "on chat:", + "\tcancel event", + "\tsend \"[%player%] >> %message%\" to all players from player" +}) +@RequiredPlugins("Minecraft 1.16.4+ for optional sender") +@Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") +public class EffMessage extends Effect { + + static { + Skript.registerEffect(EffMessage.class, + "(message|send [the] [message[s]]) %objects% [to %commandsenders%] [from %-player%]", + "send [the] action bar [with text] %objects% [to %commandsenders%]" + ); + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression[] messages; + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression messageExpr; // Used in toString + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression recipients; + + @Nullable + private Expression sender; + + boolean isChatMessage; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + isChatMessage = matchedPattern == 0; + messageExpr = LiteralUtils.defendExpression(exprs[0]); + messages = messageExpr instanceof ExpressionList ? + ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; + recipients = (Expression) exprs[1]; + if (isChatMessage) + sender = (Expression) exprs[2]; + return LiteralUtils.canInitSafely(messageExpr); + } + + @Override + protected void execute(Event e) { + long start = System.nanoTime(); + Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); + + List components = ComponentHandler.parseFromExpressions(e, messages); + + if (isChatMessage) { + Player from = sender != null ? sender.getSingle(e) : null; + Identity identity = from != null ? Identity.identity(from.getUniqueId()) : Identity.nil(); + for (Component component : components) + audience.sendMessage(identity, component); + } else { + components.forEach(audience::sendActionBar); + } + System.out.println("TIME TO EXECUTE SEND MESSAGE: " + (1. * (System.nanoTime() - start) / 1000000.)); + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + if (isChatMessage) + return "send " + messageExpr.toString(e, debug) + " to " + recipients.toString(e, debug) + + (sender != null ? " from " + sender.toString(e, debug) : ""); + return "send action bar " + messageExpr.toString(e, debug) + " to " + recipients.toString(e, debug); + } + +} diff --git a/src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java b/src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java new file mode 100644 index 00000000000..1501a045c2f --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java @@ -0,0 +1,142 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.Timespan; +import ch.njol.util.Kleenean; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.title.Title; +import net.kyori.adventure.title.Title.Times; +import net.kyori.adventure.util.Ticks; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.time.Duration; + +@Name("Send Title") +@Description({ + "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above.", + "Note: if no input is given for the title/subtitle or the times, " + + "it will keep the ones from the last title sent, use the reset title effect to restore the default values." +}) +@Examples({ + "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", + "send title \"Hi %player%\" to player", "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", + "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", + "send subtitle \"Party!\" to all players" +}) +@Since("2.3, INSERT VERSION (sending objects)") +public class EffSendTitle extends Effect { + + static { + Skript.registerEffect(EffSendTitle.class, + "send title %object% [with subtitle %-object%] [to %commandsenders%] [for %-timespan%] [with fade[(-| )]in %-timespan%] [(and|with) fade[(-| )]out %-timespan%]", + "send subtitle %object% [to %commandsenders%] [for %-timespan%] [with fade[(-| )]in %-timespan%] [(and|with) fade[(-| )]out %-timespan%]" + ); + } + + @Nullable + private Expression title; + @Nullable + private Expression subtitle; + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression recipients; + @Nullable + private Expression fadeIn, stay, fadeOut; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + title = matchedPattern == 0 ? exprs[0] : null; + subtitle = exprs[1 - matchedPattern]; + recipients = (Expression) exprs[2 - matchedPattern]; + stay = (Expression) exprs[3 - matchedPattern]; + fadeIn = (Expression) exprs[4 - matchedPattern]; + fadeOut = (Expression) exprs[5 - matchedPattern]; + return true; + } + + @Override + protected void execute(Event e) { + Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); + + Timespan fadeIn = this.fadeIn != null ? this.fadeIn.getSingle(e) : null; + Timespan stay = this.stay != null ? this.stay.getSingle(e) : null; + Timespan fadeOut = this.fadeOut != null ? this.fadeOut.getSingle(e) : null; + + // From Title#DEFAULT_TIMES + Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Ticks.duration(10); + Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Ticks.duration(70); + Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Ticks.duration(20); + + Times times = Times.of(fadeInDuration, stayDuration, fadeOutDuration); + Title title = Title.title(ComponentHandler.parseFromSingleExpression(e, this.title), ComponentHandler.parseFromSingleExpression(e, this.subtitle), times); + + audience.showTitle(title); + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + StringBuilder builder = new StringBuilder(); + if (title != null) { + builder.append("send title ").append(title.toString(e, debug)); + if (subtitle != null) + builder.append(" with subtitle ").append(subtitle.toString(e, debug)); + } else { + assert subtitle != null; + builder.append("send subtitle ").append(subtitle.toString(e, debug)); + } + + builder.append(" to ").append(recipients.toString(e, debug)); + + if (stay != null) { + builder.append(" for ").append(stay.toString(e, debug)); + } else { + builder.append(" for 70 ticks"); + } + if (fadeIn != null) { + builder.append(" with fade in ").append(fadeIn.toString(e, debug)); + } else { + builder.append(" with fade in 10 ticks"); + } + if (fadeOut != null) { + builder.append(" with fade out ").append(fadeOut.toString(e, debug)); + } else { + if (fadeIn != null) { + builder.append(" and"); + } else { + builder.append(" with"); + } + builder.append(" fade out 20 ticks"); + } + + return builder.toString(); + } + +} diff --git a/src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java b/src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java new file mode 100644 index 00000000000..faeb81acebc --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java @@ -0,0 +1,134 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionList; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.VariableString; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.text.Component; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +@Name("Coloured / Uncoloured") +@Description({ + "Parses <colour>s and, optionally, chat styles in a message or removes", + "any colours and chat styles from the message. Parsing all", + "chat styles requires this expression to be used in same line with", + "the send effect." +}) +@Examples({ + "on chat:", + "\tset message to coloured message # Safe; only colors get parsed", + "command /fade <player>:", + "\ttrigger:", + "\t\tset display name of the player-argument to uncoloured display name of the player-argument", + "command /format <text>:", + "\ttrigger:", + "\t\tmessage formatted text-argument # Safe, because we're sending to whoever used this command" +}) +@Since("2.0") +public class ExprColoured extends SimpleExpression { + + static { + Skript.registerExpression(ExprColoured.class, Component.class, ExpressionType.COMBINED, + "(colo[u]r-|colo[u]red )%strings%", + "(format-|formatted )%strings%", + "(un|non)[-](colo[u]r-|colo[u]red |1¦format-|1¦formatted )%strings%" + ); + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression strings; + + // Whether colors should be parsed + boolean color; + // Whether all formatting should be parsed + boolean format; + // Whether all formatting should be removed + boolean unformatted; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + strings = (Expression) exprs[0]; + color = matchedPattern <= 1; // colored and formatted + format = matchedPattern == 1; + unformatted = parseResult.mark == 1; + return true; + } + + @Override + @Nullable + @SuppressWarnings("unchecked") + protected Component[] get(Event e) { + long start = System.nanoTime(); + List components = new ArrayList<>(); + + Expression[] expressions = strings instanceof ExpressionList ? + (Expression[]) ((ExpressionList) strings).getExpressions() : new Expression[]{strings}; + + for (Expression expr : expressions) { + if (expr instanceof VariableString) { // Avoid unnecessary parsing + // Although a VariableString may already be parsed into a component, we have to do this again because it's colored. + components.add(getComponent(((VariableString) expr).toString(false, e))); + } else { + for (String string : expr.getArray(e)) + components.add(getComponent(string)); + } + } + System.out.println("Finished Coloring: " + (1. * (System.nanoTime() - start) / 1000000.)); + + return components.toArray(new Component[0]); + } + + private Component getComponent(String string) { + return color ? ComponentHandler.parse(string, !format) : ComponentHandler.plain(ComponentHandler.stripFormatting(string, unformatted)); + } + + @Override + public boolean isSingle() { + return strings.isSingle(); + } + + @Override + public Class getReturnType() { + return Component.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + if (format) + return "formatted " + strings.toString(e, debug); + return (color ? "" : "un") + "coloured " + strings.toString(e, debug); + } + +} diff --git a/src/main/java/io/skriptlang/skript/chat/elements/package-info.java b/src/main/java/io/skriptlang/skript/chat/elements/package-info.java new file mode 100644 index 00000000000..1106edbf370 --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/elements/package-info.java @@ -0,0 +1,23 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package io.skriptlang.skript.chat.elements; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/io/skriptlang/skript/chat/package-info.java b/src/main/java/io/skriptlang/skript/chat/package-info.java new file mode 100644 index 00000000000..132155a8421 --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/package-info.java @@ -0,0 +1,23 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package io.skriptlang.skript.chat; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java b/src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java new file mode 100644 index 00000000000..9c35296a312 --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java @@ -0,0 +1,60 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat.util; + +import org.eclipse.jdt.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +class CodeConverter { + + private static final Map CODE_MAP = new HashMap<>(); + + static { + CODE_MAP.put('0', "black"); + CODE_MAP.put('1', "dark_blue"); + CODE_MAP.put('2', "dark_green"); + CODE_MAP.put('3', "dark_aqua"); + CODE_MAP.put('4', "dark_red"); + CODE_MAP.put('5', "dark_purple"); + CODE_MAP.put('6', "gold"); + CODE_MAP.put('7', "gray"); + CODE_MAP.put('8', "dark_gray"); + CODE_MAP.put('9', "blue"); + CODE_MAP.put('a', "green"); + CODE_MAP.put('b', "aqua"); + CODE_MAP.put('c', "red"); + CODE_MAP.put('d', "light_purple"); + CODE_MAP.put('e', "yellow"); + CODE_MAP.put('f', "white"); + + CODE_MAP.put('o', "italic"); + CODE_MAP.put('l', "bold"); + CODE_MAP.put('m', "strikethrough"); + CODE_MAP.put('n', "underlined"); + CODE_MAP.put('k', "obfuscated"); + } + + @Nullable + public static String getColor(char code) { + return CODE_MAP.get(code); + } + +} diff --git a/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java b/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java new file mode 100644 index 00000000000..a56b7759a0a --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java @@ -0,0 +1,338 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package io.skriptlang.skript.chat.util; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.VariableString; +import ch.njol.skript.registrations.Classes; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.placeholder.PlaceholderResolver; +import net.kyori.adventure.text.minimessage.placeholder.Replacement; +import net.kyori.adventure.text.minimessage.transformation.TransformationRegistry; +import net.kyori.adventure.text.minimessage.transformation.TransformationType; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class ComponentHandler { + + private static final Map> PLACEHOLDERS = new HashMap<>(); + + /** + * Registers a simple key-value placeholder with Skript's message parsers. + * See https://docs.adventure.kyori.net/minimessage.html#placeholder for details. + * @param tag The tag to be replaced. + * @param result The output to replace the input. + * @see #registerPlaceholder(Function) + */ + public static void registerPlaceholder(String tag, String result) { + PLACEHOLDERS.put(tag, Replacement.raw(result)); + } + + /** + * Unregisters a tag from Skript's message parsers. + * @param tag The tag to unregister. + */ + public static void unregisterPlaceholder(String tag) { + PLACEHOLDERS.remove(tag); + } + + private static final List> PLACEHOLDER_RESOLVERS = new ArrayList<>(); + + /** + * Registers a resolver with Skript's message parsers. + * See https://docs.adventure.kyori.net/minimessage.html#placeholder-resolver for details. + * @param resolver The resolver to register. + */ + public static void registerPlaceholder(Function resolver) { + PLACEHOLDER_RESOLVERS.add(resolver); + } + + /** + * Unregisters a resolver from Skript's message parsers. + * @param resolver The resolver to unregister. + */ + public static void unregisterPlaceholder(Function resolver) { + PLACEHOLDER_RESOLVERS.remove(resolver); + } + + // The normal parser will process any proper tags + private static final MiniMessage parser = MiniMessage.builder() + .parsingErrorMessageConsumer(list -> { + // Do nothing - this is to avoid errors being printed to console for malformed formatting + }) + .placeholderResolver(PlaceholderResolver.builder() + .dynamic(tag -> { + Replacement simpleReplacement = PLACEHOLDERS.get(tag); + if (simpleReplacement != null) + return simpleReplacement; + + for (Function resolver : PLACEHOLDER_RESOLVERS) { + ComponentLike result = resolver.apply(tag); + if (result != null) + return Replacement.component(result); + } + return null; + }) + .build() + ) + .build(); + + // The safe parser only parses color/decoration/formatting related tags + @SuppressWarnings("unchecked") + private static final MiniMessage safeParser = MiniMessage.builder() + .parsingErrorMessageConsumer(list -> { + // Do nothing - this is to avoid errors being printed to console for malformed formatting + }) + .placeholderResolver(PlaceholderResolver.builder() + .dynamic(tag -> { + Replacement simpleReplacement = PLACEHOLDERS.get(tag); + if (simpleReplacement != null) + return simpleReplacement; + + for (Function resolver : PLACEHOLDER_RESOLVERS) { + ComponentLike result = resolver.apply(tag); + if (result != null) + return Replacement.component(result); + } + return null; + }) + .build() + ) + .transformations( + TransformationRegistry.builder().clear().add( + TransformationType.COLOR, TransformationType.DECORATION, TransformationType.RAINBOW, + TransformationType.GRADIENT, TransformationType.FONT + ).build() + ) + .build(); + + /** + * Parses a string using one of the MiniMessage parsers. + * @param message The message to parse. Will be parsed with the safe parser by default. + * @return An adventure component from the parsed message. + * @see #parse(Object, boolean) + */ + public static Component parse(Object message) { + return parse(message, true); + } + + /** + * Parses a string using one of the MiniMessage parsers. + * @param message The message to parse. + * @param safe Whether only color/decoration/formatting related tags should be parsed. + * @return An adventure component from the parsed message. + */ + public static Component parse(Object message, boolean safe) { + String realMessage = message instanceof String ? (String) message : Classes.toString(message); + System.out.println("CALLED: " + realMessage); + + if (realMessage.contains("&") || realMessage.contains("§")) { + System.out.println("CALLED LEGACY PARSING"); + long start = System.nanoTime(); + StringBuilder reconstructedMessage = new StringBuilder(); + char[] messageChars = realMessage.toCharArray(); + int length = messageChars.length; + for (int i = 0; i < length; i++) { + char current = messageChars[i]; + char next = (i + 1 != length) ? messageChars[i + 1] : ' '; + boolean isCode = current == '&' || current == '§'; + if (isCode && next == 'x') { // Try to parse as hex -> &x&1&2&3&4&5&6 + reconstructedMessage.append("<#"); + for (int i2 = i + 3; i2 < i + 14; i2 += 2) // Isolate the specific numbers + reconstructedMessage.append(messageChars[i2]); + reconstructedMessage.append('>'); + i += 13; // Skip to the end + } else if (isCode) { + String color = CodeConverter.getColor(next); + if (color != null) { // This is a valid code + reconstructedMessage.append('<').append(color).append('>'); + i++; // Skip to the end + } else { // Not a valid color :( + reconstructedMessage.append(current); + } + } else { + reconstructedMessage.append(current); + } + } + realMessage = reconstructedMessage.toString(); + System.out.println("FINISHED LEGACY PARSING: " + (1. * (System.nanoTime() - start) / 1000000.)); + } + + return safe ? safeParser.deserialize(realMessage) : parser.deserialize(realMessage); + } + + /** + * Constructs a list of components from the given expressions. + * @param e The event to get expression values with. + * @param expressions The expressions to parse from. + * @return A list of components parsed from the stringified expressions. + * @see #parseFromSingleExpression(Event, Expression) + */ + public static List parseFromExpressions(Event e, Expression... expressions) { + List components = new ArrayList<>(); + for (Expression expression : expressions) { + if (expression instanceof VariableString) { // Get the unformatted string since we'll be formatting it here + components.add(((VariableString) expression).getAsComponent(e)); + } else { // Might not be safe, only parse formatting + for (Object messageObject : expression.getArray(e)) { + if (messageObject instanceof Component) { // No point in doing anything + components.add((Component) messageObject); + } else { + components.add(parse(messageObject, true)); + } + } + } + } + return components; + } + + /** + * Constructs a component from the given expression. + * @param e The event to get expression values with. + * @param expression The expression to parse from. + * @return A component parsed from the stringified expression. + * Will return an empty component if the provided expression is null. + * @see #parseFromExpressions(Event, Expression[]) + */ + public static Component parseFromSingleExpression(Event e, @Nullable Expression expression) { + if (expression != null && expression.isSingle()) { + if (expression instanceof VariableString) + return ((VariableString) expression).getAsComponent(e); + Object object = expression.getSingle(e); + if (object != null) { + if (object instanceof Component) + return (Component) object; + return ComponentHandler.parse(object, true); + } + } + return Component.empty(); + } + + /** + * Creates a plain text component from an object. + * @param message The message to create a component from. + * @return An unprocessed component from the given message. + */ + public static Component plain(Object message) { + return Component.text(message instanceof String ? (String) message : Classes.toString(message)); + } + + /** + * Strips all formatting from a string. + * @param string The string to strip formatting from. + * @param all Whether ALL formatting should be stripped. + * If true, tags like keybinds will also be converted into their plain text form. + * If false, they will be left unparsed. + * @return The stripped string. + */ + public static String stripFormatting(String string, boolean all) { + return stripFormatting(parse(string, !all)); + } + + /** + * Strips all formatting from a component. + * @param component The component to strip formatting from. + * @return A stripped string from a component. + */ + public static String stripFormatting(Component component) { + return PlainTextComponentSerializer.plainText().serialize(component); + } + + /** + * Converts a string into a legacy formatted string. + * @param string The string to convert. + * @return The legacy string. + */ + public static String toLegacyString(String string) { + return toLegacyString(string, false); + } + + /** + * Converts a string into a legacy formatted string. + * @param string The string to convert. + * @param processFormatting Whether formatting should be processed before conversion. + * @return The legacy string. + */ + public static String toLegacyString(String string, boolean processFormatting) { + return toLegacyString(parse(string, !processFormatting)); + } + + /** + * Converts a component into a legacy formatted string. + * @param component The component to convert. + * @return The legacy string. + */ + public static String toLegacyString(Component component) { + return BukkitComponentSerializer.legacy().serialize(component); + } + + private static BukkitAudiences adventure = null; // Can't set here as we need an instance of Skript + + public static BukkitAudiences getAdventure() { + if (adventure == null) + adventure = BukkitAudiences.create(Skript.getInstance()); + return adventure; + } + + /** + * Constructs an audience from command senders. + * @param senders The members of this audience. + * @return An audience consisting of the provided command senders. + */ + @SuppressWarnings("ConstantConditions") + public static Audience audienceFrom(Collection senders) { + List bukkitAudiences = new ArrayList<>(); + for (CommandSender sender : senders) { + if (sender instanceof Audience) { // On paper, a CommandSender is an Audience + bukkitAudiences.add(sender); + } else { + bukkitAudiences.add(getAdventure().sender(sender)); + } + } + return Audience.audience(bukkitAudiences); + } + + /** + * Constructs an audience from command senders. + * @param senders The members of this audience. + * @return An audience consisting of the provided command senders. + */ + public static Audience audienceFrom(CommandSender... senders) { + List bukkitAudiences = new ArrayList<>(); + for (CommandSender sender : senders) + bukkitAudiences.add(getAdventure().sender(sender)); + return Audience.audience(bukkitAudiences); + } + +} diff --git a/src/main/java/io/skriptlang/skript/chat/util/package-info.java b/src/main/java/io/skriptlang/skript/chat/util/package-info.java new file mode 100644 index 00000000000..0829fafa717 --- /dev/null +++ b/src/main/java/io/skriptlang/skript/chat/util/package-info.java @@ -0,0 +1,23 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package io.skriptlang.skript.chat.util; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; From 16f34e3a38d01658268f90946a2a99a56152cd4a Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Sat, 5 Mar 2022 23:00:02 -0500 Subject: [PATCH 02/11] Update to MiniMessage 4.11 SNAPSHOT Also includes improvements and fixes to current changes --- build.gradle | 6 +- src/main/java/ch/njol/skript/Skript.java | 13 +- .../njol/skript/classes/data/JavaClasses.java | 2 +- .../ch/njol/skript/command/ScriptCommand.java | 31 ++- .../chat/expressions/ExprPrefixSuffix.java | 2 +- .../ch/njol/skript/lang/VariableString.java | 11 +- .../skript/variables/FlatFileStorage.java | 2 +- .../skript/chat/ChatRegistration.java | 29 +-- .../skript/chat/util/ComponentHandler.java | 178 ++++++++++-------- 9 files changed, 140 insertions(+), 134 deletions(-) diff --git a/build.gradle b/build.gradle index 2b7d3e68543..b61efc2cbc8 100644 --- a/build.gradle +++ b/build.gradle @@ -27,10 +27,10 @@ allprojects { dependencies { shadow group: 'io.papermc', name: 'paperlib', version: '1.0.6' - implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.17.1-R0.1-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.0.2-SNAPSHOT' + implementation (group: 'io.papermc.paper', name: 'paper-api', version: '1.17.1-R0.1-SNAPSHOT') + shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.11.0-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.1.0-SNAPSHOT' shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.10.0-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.10.0-SNAPSHOT' implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.600' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT' diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 126248cd059..d208a949753 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -56,6 +56,8 @@ import ch.njol.skript.lang.Section; import io.skriptlang.skript.chat.ChatRegistration; import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -1755,6 +1757,7 @@ static void logEx(final String... lines) { } public static String SKRIPT_PREFIX = ChatColor.GRAY + "[" + ChatColor.GOLD + "Skript" + ChatColor.GRAY + "]" + ChatColor.RESET + " "; + public static Component SKRIPT_PREFIX_COMPONENT = ComponentHandler.parse("[Skript] "); // static { // Language.addListener(new LanguageChangeListener() { @@ -1768,7 +1771,7 @@ static void logEx(final String... lines) { // } public static void info(final CommandSender sender, final String info) { - sender.sendMessage(SKRIPT_PREFIX + ComponentHandler.toLegacyString(info)); + ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(info))); } /** @@ -1777,11 +1780,11 @@ public static void info(final CommandSender sender, final String info) { * @see #adminBroadcast(String) */ public static void broadcast(final String message, final String permission) { - Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message), permission); + Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message, false), permission); } public static void adminBroadcast(final String message) { - Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message), "skript.admin"); + Bukkit.broadcast(SKRIPT_PREFIX + ComponentHandler.toLegacyString(message, false), "skript.admin"); } /** @@ -1791,11 +1794,11 @@ public static void adminBroadcast(final String message) { * @param info */ public static void message(final CommandSender sender, final String info) { - sender.sendMessage(ComponentHandler.toLegacyString(info)); + ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parse(info)); } public static void error(final CommandSender sender, final String error) { - sender.sendMessage(SKRIPT_PREFIX + ChatColor.DARK_RED + ComponentHandler.toLegacyString(error)); + ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(error).color(NamedTextColor.DARK_RED))); } /** diff --git a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java index 0437e0fc5f1..f79c908324d 100644 --- a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java @@ -573,7 +573,7 @@ public String parse(String s, ParseContext context) { case SCRIPT: case EVENT: if (VariableString.isQuotedCorrectly(s, true)) - return ComponentHandler.toLegacyString("" + s.substring(1, s.length() - 1).replace("\"\"", "\"")); + return ComponentHandler.toLegacyString("" + s.substring(1, s.length() - 1).replace("\"\"", "\""), false); return null; case COMMAND: return s; diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index 24fa53435d5..999c0a334fa 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -33,6 +33,7 @@ import java.util.UUID; import io.skriptlang.skript.chat.util.ComponentHandler; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -88,14 +89,14 @@ public class ScriptCommand implements TabExecutor { private List activeAliases; private String permission; private final VariableString permissionMessage; - private final String description; + private final Component description; @Nullable private final Timespan cooldown; private final Expression cooldownMessage; private final String cooldownBypass; @Nullable private final Expression cooldownStorage; - final String usage; + private final Component usage; final Trigger trigger; @@ -151,8 +152,8 @@ public ScriptCommand(final File script, final String name, final String pattern, this.aliases = aliases; activeAliases = new ArrayList<>(aliases); - this.description = ComponentHandler.toLegacyString(description); - this.usage = ComponentHandler.toLegacyString(usage); + this.description = ComponentHandler.parse(description); + this.usage = ComponentHandler.parse(usage); this.executableBy = executableBy; @@ -161,24 +162,20 @@ public ScriptCommand(final File script, final String name, final String pattern, trigger = new Trigger(script, "command /" + name, new SimpleEvent(), items); - bukkitCommand = setupBukkitCommand(); - } - - private PluginCommand setupBukkitCommand() { try { - final Constructor c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + Constructor c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); c.setAccessible(true); - final PluginCommand bukkitCommand = c.newInstance(name, Skript.getInstance()); - bukkitCommand.setAliases(aliases); + PluginCommand bukkitCommand = c.newInstance(name, Skript.getInstance()); + bukkitCommand.setAliases(this.aliases); bukkitCommand.setDescription(description); - bukkitCommand.setLabel(label); - bukkitCommand.setPermission(permission); + bukkitCommand.setLabel(this.label); + bukkitCommand.setPermission(this.permission); // We can only set the message if it's simple (doesn't contains expressions) - if (permissionMessage.isSimple()) - bukkitCommand.setPermissionMessage(permissionMessage.toString(null)); + if (this.permissionMessage.isSimple()) + bukkitCommand.setPermissionMessage(this.permissionMessage.toString(null)); bukkitCommand.setUsage(usage); bukkitCommand.setExecutor(this); - return bukkitCommand; + this.bukkitCommand = bukkitCommand; } catch (final Exception e) { Skript.outdatedError(e); throw new EmptyStacktraceException(); @@ -283,7 +280,7 @@ boolean execute2(final ScriptCommandEvent event, final CommandSender sender, fin } public void sendHelp(final CommandSender sender) { - if (!description.isEmpty()) + if (!Component.IS_NOT_EMPTY.test(description)) sender.sendMessage(description); sender.sendMessage(ChatColor.GOLD + "Usage" + ChatColor.RESET + ": " + usage); } diff --git a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java index 2fc5ff4bff7..d837fba887b 100644 --- a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java +++ b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java @@ -60,7 +60,7 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final @Override public String convert(final Player p) { - return ComponentHandler.toLegacyString(prefix ? "" + VaultHook.chat.getPlayerPrefix(p) : "" + VaultHook.chat.getPlayerSuffix(p)); + return ComponentHandler.toLegacyString(prefix ? "" + VaultHook.chat.getPlayerPrefix(p) : "" + VaultHook.chat.getPlayerSuffix(p), false); } @Override diff --git a/src/main/java/ch/njol/skript/lang/VariableString.java b/src/main/java/ch/njol/skript/lang/VariableString.java index aade214a3b4..316309cb544 100644 --- a/src/main/java/ch/njol/skript/lang/VariableString.java +++ b/src/main/java/ch/njol/skript/lang/VariableString.java @@ -72,7 +72,7 @@ public class VariableString implements Expression { private VariableString(String s) { isSimple = true; simple = s.replace("%%", "%"); // This doesn't contain variables, so this wasn't done in newInstance! - simpleComponent = ComponentHandler.parse(s); + simpleComponent = ComponentHandler.parse(s, false); simpleResolved = ComponentHandler.toLegacyString(simpleComponent); orig = simple; @@ -367,16 +367,15 @@ public String toString(boolean format, @Nullable Event e) { for (Object o : string) { if (o instanceof Expression) { boolean escape = !(o instanceof ExprColoured) && format; + String expression = Classes.toString(((Expression) o).getArray(e), true, mode); if (escape) - b.append("
");
-				b.append(Classes.toString(((Expression) o).getArray(e), true, mode));
-				if (escape)
-					b.append("
"); + ComponentHandler.escape(expression); + b.append(expression); } else { b.append(o); } } - return format ? ComponentHandler.toLegacyString(b.toString()) : b.toString(); + return format ? ComponentHandler.toLegacyString(b.toString(), false) : b.toString(); } @Override diff --git a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java index c5e0808e79d..6956a1f5577 100644 --- a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java +++ b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java @@ -142,7 +142,7 @@ protected boolean load_i(final SectionNode n) { continue; } if (d instanceof String && update2_0_beta3) { - d = ComponentHandler.toLegacyString((String) d); + d = ComponentHandler.toLegacyString((String) d, false); } Variables.variableLoaded("" + split[0], d, this); } diff --git a/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java b/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java index ea90693d66b..1b49d774c53 100644 --- a/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java +++ b/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java @@ -26,8 +26,13 @@ import ch.njol.skript.registrations.Converters; import io.skriptlang.skript.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.Tag.Argument; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.apache.commons.lang.StringEscapeUtils; import java.io.IOException; +import java.nio.charset.StandardCharsets; import static io.skriptlang.skript.chat.util.ComponentHandler.registerPlaceholder; @@ -71,58 +76,44 @@ public String toVariableNameString(Component component) { registerPlaceholder("dark_cyan", ""); registerPlaceholder("dark_turquoise", ""); - registerPlaceholder("dark cyan", ""); - registerPlaceholder("dark turquoise", ""); registerPlaceholder("cyan", ""); registerPlaceholder("purple", ""); registerPlaceholder("dark_yellow", ""); - registerPlaceholder("dark yellow", ""); registerPlaceholder("orange", ""); registerPlaceholder("light_grey", ""); registerPlaceholder("light_gray", ""); - registerPlaceholder("light grey", ""); - registerPlaceholder("light gray", ""); registerPlaceholder("silver", ""); registerPlaceholder("dark_silver", ""); - registerPlaceholder("dark silver", ""); registerPlaceholder("light_blue", ""); - registerPlaceholder("light blue", ""); registerPlaceholder("indigo", ""); registerPlaceholder("light_green", ""); registerPlaceholder("lime_green", ""); - registerPlaceholder("light green", ""); - registerPlaceholder("lime green", ""); registerPlaceholder("lime", ""); registerPlaceholder("light_cyan", ""); registerPlaceholder("light_aqua", ""); - registerPlaceholder("light cyan", ""); - registerPlaceholder("light aqua", ""); registerPlaceholder("turquoise", ""); registerPlaceholder("light_red", ""); - registerPlaceholder("light red", ""); + registerPlaceholder("pink", ""); registerPlaceholder("magenta", ""); registerPlaceholder("light_yellow", ""); - registerPlaceholder("light yellow", ""); registerPlaceholder("underline", ""); - registerPlaceholder(tag -> { - if (tag.startsWith("unicode:u") && tag.length() == 13) { - return Component.text(("\\" + tag.substring(8)).toCharArray()[0]); - } - return null; - }); + ComponentHandler.registerResolver(TagResolver.resolver("unicode", (argumentQueue, context) -> { + String unicode = argumentQueue.popOr("A unicode tag must have an argument of the unicode").value(); + return Tag.selfClosingInserting(Component.text(StringEscapeUtils.unescapeJava("\\" + unicode))); + })); } diff --git a/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java b/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java index a56b7759a0a..fbf91be48bb 100644 --- a/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java +++ b/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java @@ -26,115 +26,112 @@ import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.placeholder.PlaceholderResolver; -import net.kyori.adventure.text.minimessage.placeholder.Replacement; -import net.kyori.adventure.text.minimessage.transformation.TransformationRegistry; -import net.kyori.adventure.text.minimessage.transformation.TransformationType; +import net.kyori.adventure.text.minimessage.ParsingException; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; public class ComponentHandler { - private static final Map> PLACEHOLDERS = new HashMap<>(); + private static final Map SIMPLE_PLACEHOLDERS = new HashMap<>(); + private static final List RESOLVERS = new ArrayList<>(); /** * Registers a simple key-value placeholder with Skript's message parsers. - * See https://docs.adventure.kyori.net/minimessage.html#placeholder for details. - * @param tag The tag to be replaced. - * @param result The output to replace the input. - * @see #registerPlaceholder(Function) + * @param tag The name/key of the placeholder. + * @param result The result/value of the placeholder. */ public static void registerPlaceholder(String tag, String result) { - PLACEHOLDERS.put(tag, Replacement.raw(result)); + SIMPLE_PLACEHOLDERS.put(tag, Tag.preProcessParsed(result)); } /** - * Unregisters a tag from Skript's message parsers. - * @param tag The tag to unregister. + * Unregisters a simple key-value placeholder from Skript's message parsers. + * @param tag The name of the placeholder to unregister. */ public static void unregisterPlaceholder(String tag) { - PLACEHOLDERS.remove(tag); + SIMPLE_PLACEHOLDERS.remove(tag); } - private static final List> PLACEHOLDER_RESOLVERS = new ArrayList<>(); - /** - * Registers a resolver with Skript's message parsers. - * See https://docs.adventure.kyori.net/minimessage.html#placeholder-resolver for details. - * @param resolver The resolver to register. + * Registers a TagResolver with Skript's message parsers. + * @param resolver The TagResolver to register. */ - public static void registerPlaceholder(Function resolver) { - PLACEHOLDER_RESOLVERS.add(resolver); + public static void registerResolver(TagResolver resolver) { + RESOLVERS.add(resolver); } /** - * Unregisters a resolver from Skript's message parsers. - * @param resolver The resolver to unregister. + * Unregisters a TagResolver from Skript's message parsers. + * @param resolver The TagResolver to unregister. */ - public static void unregisterPlaceholder(Function resolver) { - PLACEHOLDER_RESOLVERS.remove(resolver); + public static void unregisterResolver(TagResolver resolver) { + RESOLVERS.remove(resolver); } + private static final TagResolver SKRIPT_TAG_RESOLVER = new TagResolver() { + @Override + @Nullable + public Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + Tag simple = SIMPLE_PLACEHOLDERS.get(name); + if (simple != null) + return simple; + for (TagResolver resolver : RESOLVERS) { + Tag resolved = resolver.resolve(name, arguments, ctx); + if (resolved != null) + return resolved; + } + return null; + } + + @Override + public boolean has(@NotNull String name) { + if (SIMPLE_PLACEHOLDERS.containsKey(name)) + return true; + for (TagResolver resolver : RESOLVERS) { + if (resolver.has(name)) + return true; + } + return false; + } + }; + // The normal parser will process any proper tags private static final MiniMessage parser = MiniMessage.builder() - .parsingErrorMessageConsumer(list -> { - // Do nothing - this is to avoid errors being printed to console for malformed formatting - }) - .placeholderResolver(PlaceholderResolver.builder() - .dynamic(tag -> { - Replacement simpleReplacement = PLACEHOLDERS.get(tag); - if (simpleReplacement != null) - return simpleReplacement; - - for (Function resolver : PLACEHOLDER_RESOLVERS) { - ComponentLike result = resolver.apply(tag); - if (result != null) - return Replacement.component(result); - } - return null; - }) + .strict(false) + .tags(TagResolver.builder() + .resolver(StandardTags.defaults()) + .resolver(SKRIPT_TAG_RESOLVER) .build() ) .build(); // The safe parser only parses color/decoration/formatting related tags - @SuppressWarnings("unchecked") private static final MiniMessage safeParser = MiniMessage.builder() - .parsingErrorMessageConsumer(list -> { - // Do nothing - this is to avoid errors being printed to console for malformed formatting - }) - .placeholderResolver(PlaceholderResolver.builder() - .dynamic(tag -> { - Replacement simpleReplacement = PLACEHOLDERS.get(tag); - if (simpleReplacement != null) - return simpleReplacement; - - for (Function resolver : PLACEHOLDER_RESOLVERS) { - ComponentLike result = resolver.apply(tag); - if (result != null) - return Replacement.component(result); - } - return null; - }) + .strict(false) + .tags(TagResolver.builder() + .resolvers( + StandardTags.color(), StandardTags.decorations(), StandardTags.font(), + StandardTags.gradient(), StandardTags.rainbow(), StandardTags.newline(), + StandardTags.reset(), StandardTags.transition() + ) + .resolver(SKRIPT_TAG_RESOLVER) .build() ) - .transformations( - TransformationRegistry.builder().clear().add( - TransformationType.COLOR, TransformationType.DECORATION, TransformationType.RAINBOW, - TransformationType.GRADIENT, TransformationType.FONT - ).build() - ) .build(); /** @@ -155,7 +152,10 @@ public static Component parse(Object message) { */ public static Component parse(Object message, boolean safe) { String realMessage = message instanceof String ? (String) message : Classes.toString(message); - System.out.println("CALLED: " + realMessage); + + if (realMessage.isEmpty()) { + return Component.empty(); + } if (realMessage.contains("&") || realMessage.contains("§")) { System.out.println("CALLED LEGACY PARSING"); @@ -189,6 +189,21 @@ public static Component parse(Object message, boolean safe) { System.out.println("FINISHED LEGACY PARSING: " + (1. * (System.nanoTime() - start) / 1000000.)); } + // Really annoying backwards compatibility check + realMessage = realMessage.replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", ""); + return safe ? safeParser.deserialize(realMessage) : parser.deserialize(realMessage); } @@ -248,12 +263,20 @@ public static Component plain(Object message) { return Component.text(message instanceof String ? (String) message : Classes.toString(message)); } + /** + * Escapes all tags known to Skript in the given string. + * @param string The string to escape tags in. + * @return The string with tags escaped. + */ + public static String escape(String string) { + return parser.escapeTags(string); + } + /** * Strips all formatting from a string. * @param string The string to strip formatting from. - * @param all Whether ALL formatting should be stripped. - * If true, tags like keybinds will also be converted into their plain text form. - * If false, they will be left unparsed. + * @param all Whether ALL formatting/tags should be stripped. + * If false, only safe tags like colors and decorations will be stripped. * @return The stripped string. */ public static String stripFormatting(String string, boolean all) { @@ -272,20 +295,12 @@ public static String stripFormatting(Component component) { /** * Converts a string into a legacy formatted string. * @param string The string to convert. + * @param all Whether ALL formatting/tags should be converted to a legacy format. + * If false, only safe tags like colors and decorations will be converted. * @return The legacy string. */ - public static String toLegacyString(String string) { - return toLegacyString(string, false); - } - - /** - * Converts a string into a legacy formatted string. - * @param string The string to convert. - * @param processFormatting Whether formatting should be processed before conversion. - * @return The legacy string. - */ - public static String toLegacyString(String string, boolean processFormatting) { - return toLegacyString(parse(string, !processFormatting)); + public static String toLegacyString(String string, boolean all) { + return toLegacyString(parse(string, !all)); } /** @@ -297,6 +312,7 @@ public static String toLegacyString(Component component) { return BukkitComponentSerializer.legacy().serialize(component); } + @Nullable private static BukkitAudiences adventure = null; // Can't set here as we need an instance of Skript public static BukkitAudiences getAdventure() { From c10ec7d664ae3ace9a7d67fd8a7714e4b11cdf8c Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Sat, 23 Jul 2022 18:10:34 -0400 Subject: [PATCH 03/11] Refactoring and branch updates --- build.gradle | 4 +- src/main/java/ch/njol/skript/Skript.java | 7 +-- .../njol/skript/classes/data/JavaClasses.java | 2 +- .../ch/njol/skript/command/ScriptCommand.java | 2 +- .../chat/expressions/ExprPrefixSuffix.java | 3 +- .../ch/njol/skript/lang/VariableString.java | 4 +- src/main/java/ch/njol/skript/util/Utils.java | 5 +- .../skript/variables/FlatFileStorage.java | 3 +- .../skript/bukkit/chat/ChatModule.java} | 56 +++++++++---------- .../bukkit}/chat/elements/EffBroadcast.java | 4 +- .../bukkit}/chat/elements/EffMessage.java | 5 +- .../bukkit}/chat/elements/EffSendTitle.java | 5 +- .../bukkit}/chat/elements/ExprColoured.java | 4 +- .../bukkit/chat/elements}/package-info.java | 2 +- .../skript/bukkit}/chat/package-info.java | 2 +- .../bukkit}/chat/util/CodeConverter.java | 2 +- .../bukkit}/chat/util/ComponentHandler.java | 3 +- .../bukkit/chat/util}/package-info.java | 2 +- 18 files changed, 56 insertions(+), 59 deletions(-) rename src/main/java/{io/skriptlang/skript/chat/ChatRegistration.java => org/skriptlang/skript/bukkit/chat/ChatModule.java} (60%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/elements/EffBroadcast.java (96%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/elements/EffMessage.java (96%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/elements/EffSendTitle.java (96%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/elements/ExprColoured.java (97%) rename src/main/java/{io/skriptlang/skript/chat/util => org/skriptlang/skript/bukkit/chat/elements}/package-info.java (94%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/package-info.java (95%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/util/CodeConverter.java (97%) rename src/main/java/{io/skriptlang/skript => org/skriptlang/skript/bukkit}/chat/util/ComponentHandler.java (99%) rename src/main/java/{io/skriptlang/skript/chat/elements => org/skriptlang/skript/bukkit/chat/util}/package-info.java (95%) diff --git a/build.gradle b/build.gradle index 854b82b33df..b5ce7ed1b8f 100644 --- a/build.gradle +++ b/build.gradle @@ -26,8 +26,8 @@ dependencies { shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.0' implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.19-R0.1-SNAPSHOT' shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.11.0-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.1.0-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.10.0-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.1.1-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.11.0-SNAPSHOT' implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.600' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' implementation group: 'com.sk89q.worldguard', name: 'worldguard-legacy', version: '7.0.0-SNAPSHOT' diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index f495522b134..3d0f634dbbf 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -53,8 +53,8 @@ import java.util.zip.ZipFile; import ch.njol.skript.lang.Section; -import io.skriptlang.skript.chat.ChatRegistration; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.ChatModule; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bstats.bukkit.Metrics; @@ -102,7 +102,6 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionInfo; import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.Section; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptEventInfo; import ch.njol.skript.lang.Statement; @@ -510,7 +509,7 @@ public void onEnable() { try { getAddonInstance().loadClasses("ch.njol.skript", "conditions", "effects", "events", "expressions", "entity", "sections"); - new ChatRegistration().register(getAddonInstance()); // TODO remove eventually + new ChatModule().register(getAddonInstance()); // TODO remove eventually } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); setEnabled(false); diff --git a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java index f79c908324d..407328fa944 100644 --- a/src/main/java/ch/njol/skript/classes/data/JavaClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/JavaClasses.java @@ -31,7 +31,7 @@ import ch.njol.skript.registrations.Classes; import ch.njol.util.StringUtils; import ch.njol.yggdrasil.Fields; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import org.eclipse.jdt.annotation.Nullable; import java.util.regex.Pattern; diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index c0eece87791..15b823a1f3e 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -33,7 +33,7 @@ import java.util.Set; import java.util.UUID; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.ChatColor; diff --git a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java index d837fba887b..da8244f85a1 100644 --- a/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java +++ b/src/main/java/ch/njol/skript/hooks/chat/expressions/ExprPrefixSuffix.java @@ -18,7 +18,7 @@ */ package ch.njol.skript.hooks.chat.expressions; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -32,7 +32,6 @@ import ch.njol.skript.hooks.VaultHook; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.Utils; import ch.njol.util.Kleenean; /** diff --git a/src/main/java/ch/njol/skript/lang/VariableString.java b/src/main/java/ch/njol/skript/lang/VariableString.java index 5ed431e11d5..7ec46e7e3bd 100644 --- a/src/main/java/ch/njol/skript/lang/VariableString.java +++ b/src/main/java/ch/njol/skript/lang/VariableString.java @@ -33,8 +33,8 @@ import ch.njol.util.StringUtils; import ch.njol.util.coll.CollectionUtils; import ch.njol.util.coll.iterator.SingleItemIterator; -import io.skriptlang.skript.chat.elements.ExprColoured; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.elements.ExprColoured; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; diff --git a/src/main/java/ch/njol/skript/util/Utils.java b/src/main/java/ch/njol/skript/util/Utils.java index b99cdb6ce45..ee33c9e14c2 100644 --- a/src/main/java/ch/njol/skript/util/Utils.java +++ b/src/main/java/ch/njol/skript/util/Utils.java @@ -52,6 +52,7 @@ import ch.njol.util.StringUtils; import ch.njol.util.coll.CollectionUtils; import net.md_5.bungee.api.ChatColor; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; /** * Utility class. @@ -481,7 +482,7 @@ public static String getChatStyle(final String s) { * * @param message * @return message with localised chat styles converted to Minecraft's format - * @deprecated Use {@link io.skriptlang.skript.chat.util.ComponentHandler#toLegacyString(String)} + * @deprecated Use {@link ComponentHandler#toLegacyString(String)} */ @Deprecated public static String replaceChatStyles(final String message) { @@ -521,7 +522,7 @@ public String run(final Matcher m) { * * @param message * @return message with english chat styles converted to Minecraft's format - * @deprecated Use {@link io.skriptlang.skript.chat.util.ComponentHandler#toLegacyString(String)} + * @deprecated Use {@link ComponentHandler#toLegacyString(String)} */ public static String replaceEnglishChatStyles(final String message) { if (message.isEmpty()) diff --git a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java index da128e04f84..9b6a0077779 100644 --- a/src/main/java/ch/njol/skript/variables/FlatFileStorage.java +++ b/src/main/java/ch/njol/skript/variables/FlatFileStorage.java @@ -34,7 +34,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; @@ -45,7 +45,6 @@ import ch.njol.skript.util.ExceptionUtils; import ch.njol.skript.util.FileUtils; import ch.njol.skript.util.Task; -import ch.njol.skript.util.Utils; import ch.njol.skript.util.Version; import ch.njol.util.NotifyingReference; diff --git a/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java similarity index 60% rename from src/main/java/io/skriptlang/skript/chat/ChatRegistration.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java index 1b49d774c53..81f0dc6031c 100644 --- a/src/main/java/io/skriptlang/skript/chat/ChatRegistration.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat; +package org.skriptlang.skript.bukkit.chat; import ch.njol.skript.SkriptAddon; import ch.njol.skript.classes.ClassInfo; @@ -24,19 +24,15 @@ import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; import ch.njol.skript.registrations.Converters; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.Tag; -import net.kyori.adventure.text.minimessage.tag.Tag.Argument; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import org.apache.commons.lang.StringEscapeUtils; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import static io.skriptlang.skript.chat.util.ComponentHandler.registerPlaceholder; - -public class ChatRegistration { +public class ChatModule { public void register(SkriptAddon addon) { @@ -74,41 +70,41 @@ public String toVariableNameString(Component component) { // Just to initialize it now ComponentHandler.getAdventure(); - registerPlaceholder("dark_cyan", ""); - registerPlaceholder("dark_turquoise", ""); - registerPlaceholder("cyan", ""); + ComponentHandler.registerPlaceholder("dark_cyan", ""); + ComponentHandler.registerPlaceholder("dark_turquoise", ""); + ComponentHandler.registerPlaceholder("cyan", ""); - registerPlaceholder("purple", ""); + ComponentHandler.registerPlaceholder("purple", ""); - registerPlaceholder("dark_yellow", ""); - registerPlaceholder("orange", ""); + ComponentHandler.registerPlaceholder("dark_yellow", ""); + ComponentHandler.registerPlaceholder("orange", ""); - registerPlaceholder("light_grey", ""); - registerPlaceholder("light_gray", ""); - registerPlaceholder("silver", ""); + ComponentHandler.registerPlaceholder("light_grey", ""); + ComponentHandler.registerPlaceholder("light_gray", ""); + ComponentHandler.registerPlaceholder("silver", ""); - registerPlaceholder("dark_silver", ""); + ComponentHandler.registerPlaceholder("dark_silver", ""); - registerPlaceholder("light_blue", ""); - registerPlaceholder("indigo", ""); + ComponentHandler.registerPlaceholder("light_blue", ""); + ComponentHandler.registerPlaceholder("indigo", ""); - registerPlaceholder("light_green", ""); - registerPlaceholder("lime_green", ""); - registerPlaceholder("lime", ""); + ComponentHandler.registerPlaceholder("light_green", ""); + ComponentHandler.registerPlaceholder("lime_green", ""); + ComponentHandler.registerPlaceholder("lime", ""); - registerPlaceholder("light_cyan", ""); - registerPlaceholder("light_aqua", ""); - registerPlaceholder("turquoise", ""); + ComponentHandler.registerPlaceholder("light_cyan", ""); + ComponentHandler.registerPlaceholder("light_aqua", ""); + ComponentHandler.registerPlaceholder("turquoise", ""); - registerPlaceholder("light_red", ""); + ComponentHandler.registerPlaceholder("light_red", ""); - registerPlaceholder("pink", ""); - registerPlaceholder("magenta", ""); + ComponentHandler.registerPlaceholder("pink", ""); + ComponentHandler.registerPlaceholder("magenta", ""); - registerPlaceholder("light_yellow", ""); + ComponentHandler.registerPlaceholder("light_yellow", ""); - registerPlaceholder("underline", ""); + ComponentHandler.registerPlaceholder("underline", ""); ComponentHandler.registerResolver(TagResolver.resolver("unicode", (argumentQueue, context) -> { String unicode = argumentQueue.popOr("A unicode tag must have an argument of the unicode").value(); diff --git a/src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java similarity index 96% rename from src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java index 6fea3a3e663..48453dba1f5 100644 --- a/src/main/java/io/skriptlang/skript/chat/elements/EffBroadcast.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.elements; +package org.skriptlang.skript.bukkit.chat.elements; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -29,7 +29,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import org.bukkit.Bukkit; import org.bukkit.World; diff --git a/src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java similarity index 96% rename from src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java index 8ff0811a01c..8162a047bfa 100644 --- a/src/main/java/io/skriptlang/skript/chat/elements/EffMessage.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.elements; +package org.skriptlang.skript.bukkit.chat.elements; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -30,7 +30,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; @@ -61,6 +61,7 @@ }) @RequiredPlugins("Minecraft 1.16.4+ for optional sender") @Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") +// See what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffMessage extends Effect { static { diff --git a/src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java similarity index 96% rename from src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java index 1501a045c2f..fecd73c6d41 100644 --- a/src/main/java/io/skriptlang/skript/chat/elements/EffSendTitle.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.elements; +package org.skriptlang.skript.bukkit.chat.elements; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -28,7 +28,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.Timespan; import ch.njol.util.Kleenean; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.title.Title; import net.kyori.adventure.title.Title.Times; @@ -52,6 +52,7 @@ "send subtitle \"Party!\" to all players" }) @Since("2.3, INSERT VERSION (sending objects)") +// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4362 public class EffSendTitle extends Effect { static { diff --git a/src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/ExprColoured.java similarity index 97% rename from src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/elements/ExprColoured.java index faeb81acebc..8a76721ec37 100644 --- a/src/main/java/io/skriptlang/skript/chat/elements/ExprColoured.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/ExprColoured.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.elements; +package org.skriptlang.skript.bukkit.chat.elements; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; @@ -30,7 +30,7 @@ import ch.njol.skript.lang.VariableString; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; -import io.skriptlang.skript.chat.util.ComponentHandler; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; diff --git a/src/main/java/io/skriptlang/skript/chat/util/package-info.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/package-info.java similarity index 94% rename from src/main/java/io/skriptlang/skript/chat/util/package-info.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/elements/package-info.java index 0829fafa717..d05865be9d6 100644 --- a/src/main/java/io/skriptlang/skript/chat/util/package-info.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/package-info.java @@ -17,7 +17,7 @@ * Copyright Peter Güttinger, SkriptLang team and contributors */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package io.skriptlang.skript.chat.util; +package org.skriptlang.skript.bukkit.chat.elements; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/io/skriptlang/skript/chat/package-info.java b/src/main/java/org/skriptlang/skript/bukkit/chat/package-info.java similarity index 95% rename from src/main/java/io/skriptlang/skript/chat/package-info.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/package-info.java index 132155a8421..09d974c28f3 100644 --- a/src/main/java/io/skriptlang/skript/chat/package-info.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/package-info.java @@ -17,7 +17,7 @@ * Copyright Peter Güttinger, SkriptLang team and contributors */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package io.skriptlang.skript.chat; +package org.skriptlang.skript.bukkit.chat; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java similarity index 97% rename from src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java index 9c35296a312..d78897b440b 100644 --- a/src/main/java/io/skriptlang/skript/chat/util/CodeConverter.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.util; +package org.skriptlang.skript.bukkit.chat.util; import org.eclipse.jdt.annotation.Nullable; diff --git a/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java similarity index 99% rename from src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index fbf91be48bb..ca46b795d90 100644 --- a/src/main/java/io/skriptlang/skript/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package io.skriptlang.skript.chat.util; +package org.skriptlang.skript.bukkit.chat.util; import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; @@ -318,6 +318,7 @@ public static String toLegacyString(Component component) { public static BukkitAudiences getAdventure() { if (adventure == null) adventure = BukkitAudiences.create(Skript.getInstance()); + // TODO we might need to close this ('adventure.close()') return adventure; } diff --git a/src/main/java/io/skriptlang/skript/chat/elements/package-info.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/package-info.java similarity index 95% rename from src/main/java/io/skriptlang/skript/chat/elements/package-info.java rename to src/main/java/org/skriptlang/skript/bukkit/chat/util/package-info.java index 1106edbf370..605ab1b7c18 100644 --- a/src/main/java/io/skriptlang/skript/chat/elements/package-info.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/package-info.java @@ -17,7 +17,7 @@ * Copyright Peter Güttinger, SkriptLang team and contributors */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package io.skriptlang.skript.chat.elements; +package org.skriptlang.skript.bukkit.chat.util; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; From a6566f3616c774ee2f40954df327fa1c30e5831c Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Sat, 23 Jul 2022 20:10:48 -0400 Subject: [PATCH 04/11] Make this experiment use Paper's integration This results in much faster execution times comparable to the current system. However, it also means that Spigot is no longer supported, and versions below 1.17 won't work. (Paper 1.17+ only now) --- build.gradle | 16 ++- src/main/java/ch/njol/skript/Skript.java | 6 +- .../ch/njol/skript/command/ScriptCommand.java | 2 +- .../ch/njol/skript/expressions/ExprName.java | 134 ++++++++---------- .../ch/njol/skript/expressions/ExprNamed.java | 50 ++++--- .../ExprPlayerListHeaderFooter.java | 41 +++--- .../skript/bukkit/chat/ChatModule.java | 18 ++- .../bukkit/chat/elements/EffBroadcast.java | 29 ++-- .../bukkit/chat/elements/EffMessage.java | 25 ++-- .../bukkit/chat/elements/EffSendTitle.java | 40 +++--- .../bukkit/chat/util/ComponentHandler.java | 56 ++------ .../environments/java8/paper-1.13.2.json | 17 --- .../environments/java8/paper-1.14.4.json | 17 --- .../environments/java8/paper-1.15.2.json | 17 --- .../environments/java8/paper-1.16.5.json | 17 --- 15 files changed, 201 insertions(+), 284 deletions(-) delete mode 100644 src/test/skript/environments/java8/paper-1.13.2.json delete mode 100644 src/test/skript/environments/java8/paper-1.14.4.json delete mode 100644 src/test/skript/environments/java8/paper-1.15.2.json delete mode 100644 src/test/skript/environments/java8/paper-1.16.5.json diff --git a/build.gradle b/build.gradle index b5ce7ed1b8f..59c5ef55a73 100644 --- a/build.gradle +++ b/build.gradle @@ -25,8 +25,7 @@ dependencies { shadow group: 'io.papermc', name: 'paperlib', version: '1.0.7' shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.0' implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.19-R0.1-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.11.0-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.1.1-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-text-serializer-legacy', version: '4.11.0-SNAPSHOT' shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.11.0-SNAPSHOT' implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.600' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' @@ -75,9 +74,15 @@ tasks.withType(ShadowJar) { configurations = [ project.configurations.shadow ] + dependencies { + include(dependency('io.papermc:paperlib')) + include(dependency('org.bstats:bstats-bukkit')) + include(dependency('org.bstats:bstats-base')) + include(dependency('net.kyori:adventure-text-serializer-legacy')) + include(dependency('net.kyori:adventure-text-serializer-plain')) + } relocate 'io.papermc.lib', 'ch.njol.skript.paperlib' relocate 'org.bstats', 'ch.njol.skript.bstats' - relocate 'net.kyori', 'ch.njol.skript.kyori' manifest { attributes( 'Name': 'ch/njol/skript', @@ -187,7 +192,7 @@ void createTestTask(String name, String environments, boolean devMode, int javaV def latestEnv = 'java17/paper-1.19.json' def latestJava = 17 -def oldestJava = 8 +def oldestJava = 17 tasks.withType(JavaCompile).configureEach { options.compilerArgs += ["-source", "" + oldestJava, "-target", "" + oldestJava] @@ -196,11 +201,10 @@ tasks.withType(JavaCompile).configureEach { // Register different Skript testing tasks createTestTask('quickTest', 'src/test/skript/environments/' + latestEnv, false, latestJava, false) createTestTask('skriptTestJava17', 'src/test/skript/environments/java17', false, latestJava, false) -createTestTask('skriptTestJava8', 'src/test/skript/environments/java8', false, oldestJava, false) createTestTask('skriptTestDev', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), true, Integer.parseInt(project.property('testEnvJavaVersion') == null ? latestJava : project.property('testEnvJavaVersion')), false) -tasks.register('skriptTest') {dependsOn skriptTestJava8, skriptTestJava17} +tasks.register('skriptTest') {dependsOn skriptTestJava17} createTestTask('genDocs', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), false, Integer.parseInt(project.property('testEnvJavaVersion') == null ? latestJava : project.property('testEnvJavaVersion')), true) diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 3d0f634dbbf..bcf0241149a 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -1742,7 +1742,7 @@ static void logEx(final String... lines) { // } public static void info(final CommandSender sender, final String info) { - ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(info))); + sender.sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(info))); } /** @@ -1765,11 +1765,11 @@ public static void adminBroadcast(final String message) { * @param info */ public static void message(final CommandSender sender, final String info) { - ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parse(info)); + sender.sendMessage(ComponentHandler.parse(info)); } public static void error(final CommandSender sender, final String error) { - ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(error).color(NamedTextColor.DARK_RED))); + sender.sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(error).color(NamedTextColor.DARK_RED))); } /** diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index 15b823a1f3e..a14e59d5906 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -207,7 +207,7 @@ public boolean execute(final CommandSender sender, final String commandLabel, fi final ScriptCommandEvent event = new ScriptCommandEvent(ScriptCommand.this, sender); if (!permission.isEmpty() && !sender.hasPermission(permission)) { - ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parseFromSingleExpression(event, permissionMessage)); + sender.sendMessage(ComponentHandler.parseFromSingleExpression(event, permissionMessage)); return false; } diff --git a/src/main/java/ch/njol/skript/expressions/ExprName.java b/src/main/java/ch/njol/skript/expressions/ExprName.java index c0c26f40e8c..831dd0e44ad 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprName.java +++ b/src/main/java/ch/njol/skript/expressions/ExprName.java @@ -18,12 +18,21 @@ */ package ch.njol.skript.expressions; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.List; - +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.Aliases; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.Nameable; @@ -41,21 +50,8 @@ import org.bukkit.inventory.meta.ItemMeta; import org.eclipse.jdt.annotation.Nullable; -import ch.njol.skript.Skript; -import ch.njol.skript.aliases.Aliases; -import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.slot.Slot; -import ch.njol.util.Kleenean; -import ch.njol.util.coll.CollectionUtils; -import net.md_5.bungee.api.ChatColor; +import java.util.ArrayList; +import java.util.List; @Name("Name / Display Name / Tab List Name") @Description({"Represents the Minecraft account, display or tab list name of a player, or the custom name of an item, entity, block, inventory, or gamerule.", @@ -99,24 +95,14 @@ " set the player's tab list name to \"<green>%player's name%\"", "set the name of the player's tool to \"Legendary Sword of Awesomeness\""}) @Since("before 2.1, 2.2-dev20 (inventory name), 2.4 (non-living entity support, changeable inventory name)") -public class ExprName extends SimplePropertyExpression { - - @Nullable - static final MethodHandle TITLE_METHOD; - static final boolean HAS_GAMERULES; +public class ExprName extends SimplePropertyExpression { static { - HAS_GAMERULES = Skript.classExists("org.bukkit.GameRule"); - register(ExprName.class, String.class, "(1¦name[s]|2¦(display|nick|chat|custom)[ ]name[s])", "offlineplayers/entities/blocks/itemtypes/inventories/slots" - + (HAS_GAMERULES ? "/gamerules" : "")); - register(ExprName.class, String.class, "(3¦(player|tab)[ ]list name[s])", "players"); - - // Get the old method for getting the name of an inventory. - MethodHandle _METHOD = null; - try { - _METHOD = MethodHandles.lookup().findVirtual(Inventory.class, "getTitle", MethodType.methodType(String.class)); - } catch (IllegalAccessException | NoSuchMethodException ignored) {} - TITLE_METHOD = _METHOD; + register(ExprName.class, Component.class, + "(1:name[s]|2:(display|nick|chat|custom)[ ]name[s])", + "offlineplayers/entities/blocks/itemtypes/inventories/slots/gamerules" + ); + register(ExprName.class, Component.class, "(3:(player|tab)[ ]list name[s])", "players"); } /* @@ -137,51 +123,45 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override @Nullable - public String convert(Object o) { + public Component convert(Object o) { if (o instanceof OfflinePlayer && ((OfflinePlayer) o).isOnline()) o = ((OfflinePlayer) o).getPlayer(); if (o instanceof Player) { switch (mark) { case 1: - return ((Player) o).getName(); + return ((Player) o).name(); case 2: - return ((Player) o).getDisplayName(); + return ((Player) o).displayName(); case 3: - return ((Player) o).getPlayerListName(); + return ((Player) o).playerListName(); } } else if (o instanceof OfflinePlayer) { - return mark == 1 ? ((OfflinePlayer) o).getName() : null; + if (mark != 1) + return null; + String name = ((OfflinePlayer) o).getName(); + return name != null ? Component.text(name) : null; } else if (o instanceof Entity) { - return ((Entity) o).getCustomName(); + return ((Entity) o).customName(); } else if (o instanceof Block) { BlockState state = ((Block) o).getState(); if (state instanceof Nameable) - return ((Nameable) state).getCustomName(); + return ((Nameable) state).customName(); } else if (o instanceof ItemType) { ItemMeta m = ((ItemType) o).getItemMeta(); - return m.hasDisplayName() ? m.getDisplayName() : null; + return m.hasDisplayName() ? m.displayName() : null; } else if (o instanceof Inventory) { - if (TITLE_METHOD != null) { - try { - return (String) TITLE_METHOD.invoke(o); - } catch (Throwable e) { - Skript.exception(e); - return null; - } - } else { - if (!((Inventory) o).getViewers().isEmpty()) - return ((Inventory) o).getViewers().get(0).getOpenInventory().getTitle(); - return null; - } + if (!((Inventory) o).getViewers().isEmpty()) + return ((Inventory) o).getViewers().get(0).getOpenInventory().title(); + return null; } else if (o instanceof Slot) { ItemStack is = ((Slot) o).getItem(); if (is != null && is.hasItemMeta()) { ItemMeta m = is.getItemMeta(); - return m.hasDisplayName() ? m.getDisplayName() : null; + return m.hasDisplayName() ? m.displayName() : null; } - } else if (HAS_GAMERULES && o instanceof GameRule) { - return ((GameRule) o).getName(); + } else if (o instanceof GameRule) { + return Component.text(((GameRule) o).getName()); } return null; } @@ -194,26 +174,26 @@ public Class[] acceptChange(ChangeMode mode) { Skript.error("Can't change the Minecraft name of a player. Change the 'display name' or 'tab list name' instead."); return null; } - return CollectionUtils.array(String.class); + return CollectionUtils.array(Component.class); } return null; } @Override public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { - String name = delta != null ? (String) delta[0] : null; + Component name = delta != null ? (Component) delta[0] : null; for (Object o : getExpr().getArray(e)) { if (o instanceof Player) { switch (mark) { case 2: - ((Player) o).setDisplayName(name != null ? name + ChatColor.RESET : ((Player) o).getName()); + ((Player) o).displayName(name); break; - case 3: // Null check not necessary. This method will use the player's name if 'name' is null. - ((Player) o).setPlayerListName(name); + case 3: + ((Player) o).playerListName(name); break; } } else if (o instanceof Entity) { - ((Entity) o).setCustomName(name); + ((Entity) o).customName(name); if (mark == 2 || mode == ChangeMode.RESET) // Using "display name" ((Entity) o).setCustomNameVisible(name != null); if (o instanceof LivingEntity) @@ -221,13 +201,13 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { } else if (o instanceof Block) { BlockState state = ((Block) o).getState(); if (state instanceof Nameable) { - ((Nameable) state).setCustomName(name); + ((Nameable) state).customName(name); state.update(); } } else if (o instanceof ItemType) { ItemType i = (ItemType) o; ItemMeta m = i.getItemMeta(); - m.setDisplayName(name); + m.displayName(name); i.setItemMeta(m); } else if (o instanceof Inventory) { Inventory inv = (Inventory) o; @@ -241,7 +221,7 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { if (!type.isCreatable()) return; if (name == null) - name = type.getDefaultTitle(); + name = type.defaultTitle(); Inventory copy; if (type == InventoryType.CHEST) { @@ -256,7 +236,7 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { ItemStack is = s.getItem(); if (is != null && !AIR.isOfType(is)) { ItemMeta m = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); - m.setDisplayName(name); + m.displayName(name); is.setItemMeta(m); s.setItem(is); } @@ -265,17 +245,19 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { } @Override - public Class getReturnType() { - return String.class; + public Class getReturnType() { + return Component.class; } @Override protected String getPropertyName() { switch (mark) { - case 1: return "name"; - case 2: return "display name"; - case 3: return "tablist name"; - default: return "name"; + case 2: + return "display name"; + case 3: + return "tablist name"; + default: + return "name"; } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprNamed.java b/src/main/java/ch/njol/skript/expressions/ExprNamed.java index c01724bb7f2..2a7a6e1f9f7 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprNamed.java +++ b/src/main/java/ch/njol/skript/expressions/ExprNamed.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.expressions; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.inventory.InventoryType; @@ -39,42 +40,45 @@ import ch.njol.skript.util.Getter; import ch.njol.util.Kleenean; -/** - * @author Peter Güttinger - */ @Name("Named Item/Inventory") -@Description("Directly names an item/inventory, useful for defining a named item/inventory in a script. " + - "If you want to (re)name existing items/inventories you can either use this expression or use set name of <item/inventory> to <text>.") -@Examples({"give a diamond sword of sharpness 100 named \"<gold>Excalibur\" to the player", - "set tool of player to the player's tool named \"<gold>Wand\"", - "set the name of the player's tool to \"<gold>Wand\"", - "open hopper inventory named \"Magic Hopper\" to player"}) +@Description({ + "Directly names an item/inventory, useful for defining a named item/inventory in a script.", + "If you want to (re)name existing items/inventories you can either use this expression or " + + "use set name of <item/inventory> to <text>." +}) +@Examples({ + "give a diamond sword of sharpness 100 named \"<gold>Excalibur\" to the player", + "set tool of player to the player's tool named \"<gold>Wand\"", + "set the name of the player's tool to \"<gold>Wand\"", + "open hopper inventory named \"Magic Hopper\" to player" +}) @Since("2.0, 2.2-dev34 (inventories)") public class ExprNamed extends PropertyExpression { + static { Skript.registerExpression(ExprNamed.class, Object.class, ExpressionType.PROPERTY, - "%itemtype/inventorytype% (named|with name[s]) %string%"); + "%itemtype/inventorytype% (named|with name[s]) %component%" + ); } - @SuppressWarnings("null") - private Expression name; - - @SuppressWarnings({"unchecked", "null"}) + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression name; + @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { setExpr(exprs[0]); - name = (Expression) exprs[1]; + name = (Expression) exprs[1]; return true; } @Override protected Object[] get(final Event e, final Object[] source) { - String name = this.name.getSingle(e); + Component name = this.name.getSingle(e); if (name == null) return get(source, obj -> obj); // No name provided, do nothing return get(source, new Getter() { @Override - @Nullable public Object get(Object obj) { if (obj instanceof InventoryType) return Bukkit.createInventory(null, (InventoryType) obj, name); @@ -83,7 +87,7 @@ public Object get(Object obj) { stack = stack.clone(); ItemMeta meta = stack.getItemMeta(); if (meta != null) { - meta.setDisplayName(name); + meta.displayName(name); stack.setItemMeta(meta); } return new ItemType(stack); @@ -91,7 +95,7 @@ public Object get(Object obj) { ItemType item = (ItemType) obj; item = item.clone(); ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(name); + meta.displayName(name); item.setItemMeta(meta); return item; } @@ -99,13 +103,13 @@ public Object get(Object obj) { } @Override - public Class getReturnType() { + public Class getReturnType() { return getExpr().getReturnType() == InventoryType.class ? Inventory.class : ItemType.class; } @Override - public String toString(final @Nullable Event e, final boolean debug) { - return getExpr().toString(e, debug) + " named " + name; + public String toString(@Nullable Event e, boolean debug) { + return getExpr().toString(e, debug) + " named " + name.toString(e, debug); } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java index c8dc302014c..40aeaf51e71 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java +++ b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java @@ -29,7 +29,6 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; -import io.skriptlang.skript.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -44,24 +43,26 @@ "reset all players' tab list header" }) @Since("2.4") -public class ExprPlayerListHeaderFooter extends SimplePropertyExpression { +public class ExprPlayerListHeaderFooter extends SimplePropertyExpression { static { - PropertyExpression.register(ExprPlayerListHeaderFooter.class, String.class, "(player|tab)[ ]list (header|1¦footer) [(text|message)]", "players"); + PropertyExpression.register(ExprPlayerListHeaderFooter.class, Component.class, + "(player|tab)[ ]list (header|:footer) [(text|message)]", "players" + ); } - private boolean isHeader; + private boolean footer; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - isHeader = parseResult.mark == 0; + footer = parseResult.hasTag("footer"); return super.init(exprs, matchedPattern, isDelayed, parseResult); } @Override @Nullable - public String convert(Player player) { - return isHeader ? player.getPlayerListHeader() : player.getPlayerListFooter(); + public Component convert(Player player) { + return footer ? player.playerListFooter() : player.playerListHeader(); } @Override @@ -71,7 +72,7 @@ public Class[] acceptChange(ChangeMode mode) { case SET: case DELETE: case RESET: - return CollectionUtils.array(String[].class, Component.class); + return CollectionUtils.array(Component[].class); default: return null; } @@ -79,30 +80,26 @@ public Class[] acceptChange(ChangeMode mode) { @Override public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { - Component component; - if (delta == null) { - component = Component.empty(); - } else if (delta[0] instanceof Component) { - component = (Component) delta[0]; + Component component = Component.empty(); + for (Object userComponent : delta) + component = component.append((Component) userComponent).append(Component.newline()); + + Audience audience = Audience.audience(getExpr().getArray(e)); + if (footer) { + audience.sendPlayerListFooter(component); } else { - component = ComponentHandler.parse(String.join("\n", (String[]) delta), false); - } - Audience audience = ComponentHandler.audienceFrom(getExpr().getArray(e)); - if (isHeader) { audience.sendPlayerListHeader(component); - } else { - audience.sendPlayerListFooter(component); } } @Override - public Class getReturnType() { - return String.class; + public Class getReturnType() { + return Component.class; } @Override protected String getPropertyName() { - return "player list " + (isHeader ? "header" : "footer"); + return "player list " + (footer ? "header" : "footer"); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java index 81f0dc6031c..d6f16121cf9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java @@ -20,9 +20,11 @@ import ch.njol.skript.SkriptAddon; import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.Comparator; import ch.njol.skript.classes.Parser; import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; +import ch.njol.skript.registrations.Comparators; import ch.njol.skript.registrations.Converters; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; @@ -37,13 +39,24 @@ public class ChatModule { public void register(SkriptAddon addon) { try { - addon.loadClasses("io.skriptlang.skript.chat.elements"); + addon.loadClasses("org.skriptlang.skript.bukkit.chat.elements"); } catch (IOException e) { e.printStackTrace(); } Converters.registerConverter(String.class, Component.class, ComponentHandler::parse); Converters.registerConverter(Component.class, String.class, ComponentHandler::toLegacyString); + Comparators.registerComparator(String.class, Component.class, new Comparator() { + @Override + public Relation compare(String o1, Component o2) { + return Relation.get(o1.equals(ComponentHandler.toLegacyString(o2))); + } + + @Override + public boolean supportsOrdering() { + return false; + } + }); Classes.registerClass(new ClassInfo<>(Component.class, "component") .user("components?") @@ -67,9 +80,6 @@ public String toVariableNameString(Component component) { }) ); - // Just to initialize it now - ComponentHandler.getAdventure(); - ComponentHandler.registerPlaceholder("dark_cyan", ""); ComponentHandler.registerPlaceholder("dark_turquoise", ""); ComponentHandler.registerPlaceholder("cyan", ""); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java index 48453dba1f5..a224eb43c11 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java @@ -29,6 +29,8 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.text.Component; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import org.bukkit.Bukkit; @@ -47,13 +49,12 @@ "broadcast \"Woah! It's a message!\"" }) @Since("1.0, 2.6 (broadcasting objects), 2.6.1 (using advanced formatting)") -// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffBroadcast extends Effect { @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; // Used in toString + private Expression messageExpr; @Nullable private Expression worlds; @@ -65,24 +66,34 @@ public class EffBroadcast extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { messageExpr = LiteralUtils.defendExpression(exprs[0]); - messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; + if (messageExpr instanceof ExpressionList) { + ExpressionList exprList = (ExpressionList) messageExpr; + if (exprList.getAnd()) { + messages = exprList.getExpressions(); + } else { + messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; + } + } else { + messages = new Expression[]{messageExpr}; + } + worlds = (Expression) exprs[1]; return LiteralUtils.canInitSafely(messageExpr); } @Override protected void execute(Event e) { - List recipients = new ArrayList<>(); if (worlds == null) { - recipients.addAll(Bukkit.getOnlinePlayers()); - recipients.add(Bukkit.getConsoleSender()); + for (Component component : ComponentHandler.parseFromExpressions(e, messages)) + Bukkit.broadcast(component); } else { + List recipients = new ArrayList<>(); for (World world : worlds.getArray(e)) recipients.addAll(world.getPlayers()); + Audience audience = Audience.audience(recipients); + for (Component component : ComponentHandler.parseFromExpressions(e, messages)) + audience.sendMessage(component); } - Audience audience = ComponentHandler.audienceFrom(recipients); - ComponentHandler.parseFromExpressions(e, messages).forEach(audience::sendMessage); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java index 8162a047bfa..42e6d841707 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java @@ -30,6 +30,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; @@ -61,7 +62,6 @@ }) @RequiredPlugins("Minecraft 1.16.4+ for optional sender") @Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") -// See what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffMessage extends Effect { static { @@ -74,7 +74,7 @@ public class EffMessage extends Effect { @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; // Used in toString + private Expression messageExpr; @SuppressWarnings("NotNullFieldNotInitialized") private Expression recipients; @@ -87,9 +87,19 @@ public class EffMessage extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { isChatMessage = matchedPattern == 0; + messageExpr = LiteralUtils.defendExpression(exprs[0]); - messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; + if (messageExpr instanceof ExpressionList) { + ExpressionList exprList = (ExpressionList) messageExpr; + if (exprList.getAnd()) { + messages = exprList.getExpressions(); + } else { + messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; + } + } else { + messages = new Expression[]{messageExpr}; + } + recipients = (Expression) exprs[1]; if (isChatMessage) sender = (Expression) exprs[2]; @@ -98,8 +108,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event e) { - long start = System.nanoTime(); - Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); + Audience audience = Audience.audience(recipients.getArray(e)); List components = ComponentHandler.parseFromExpressions(e, messages); @@ -109,9 +118,9 @@ protected void execute(Event e) { for (Component component : components) audience.sendMessage(identity, component); } else { - components.forEach(audience::sendActionBar); + for (Component component : components) + audience.sendActionBar(component); } - System.out.println("TIME TO EXECUTE SEND MESSAGE: " + (1. * (System.nanoTime() - start) / 1000000.)); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java index fecd73c6d41..38ea543313c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java @@ -41,18 +41,22 @@ @Name("Send Title") @Description({ - "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above.", - "Note: if no input is given for the title/subtitle or the times, " + - "it will keep the ones from the last title sent, use the reset title effect to restore the default values." + "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above. ", + "", + "If you're sending only the subtitle, it will be shown only if there's a title displayed at the moment, otherwise it will " + + "be sent with the next title. To show only the subtitle, use: send title \" \" with subtitle \"yourtexthere\" to player.", + "", + "Note: if no input is given for the times, it will keep the ones from the last title sent, " + + "use the reset title effect to restore the default values." }) @Examples({ - "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", - "send title \"Hi %player%\" to player", "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", - "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", - "send subtitle \"Party!\" to all players" + "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", + "send title \"Hi %player%\" to player", + "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", + "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", + "send subtitle \"Party!\" to all players" }) @Since("2.3, INSERT VERSION (sending objects)") -// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4362 public class EffSendTitle extends Effect { static { @@ -85,18 +89,17 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event e) { - Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); + Audience audience = Audience.audience(recipients.getArray(e)); Timespan fadeIn = this.fadeIn != null ? this.fadeIn.getSingle(e) : null; Timespan stay = this.stay != null ? this.stay.getSingle(e) : null; Timespan fadeOut = this.fadeOut != null ? this.fadeOut.getSingle(e) : null; - // From Title#DEFAULT_TIMES - Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Ticks.duration(10); - Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Ticks.duration(70); - Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Ticks.duration(20); + Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Title.DEFAULT_TIMES.fadeIn(); + Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Title.DEFAULT_TIMES.stay(); + Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Title.DEFAULT_TIMES.fadeOut(); - Times times = Times.of(fadeInDuration, stayDuration, fadeOutDuration); + Times times = Times.times(fadeInDuration, stayDuration, fadeOutDuration); Title title = Title.title(ComponentHandler.parseFromSingleExpression(e, this.title), ComponentHandler.parseFromSingleExpression(e, this.subtitle), times); audience.showTitle(title); @@ -119,12 +122,14 @@ public String toString(@Nullable Event e, boolean debug) { if (stay != null) { builder.append(" for ").append(stay.toString(e, debug)); } else { - builder.append(" for 70 ticks"); + long ticks = Title.DEFAULT_TIMES.stay().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" for ").append(ticks).append(" ticks"); } if (fadeIn != null) { builder.append(" with fade in ").append(fadeIn.toString(e, debug)); } else { - builder.append(" with fade in 10 ticks"); + long ticks = Title.DEFAULT_TIMES.fadeIn().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" with fade in ").append(ticks).append(" ticks"); } if (fadeOut != null) { builder.append(" with fade out ").append(fadeOut.toString(e, debug)); @@ -134,7 +139,8 @@ public String toString(@Nullable Event e, boolean debug) { } else { builder.append(" with"); } - builder.append(" fade out 20 ticks"); + long ticks = Title.DEFAULT_TIMES.fadeOut().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" fade out ").append(ticks).append(" ticks"); } return builder.toString(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index ca46b795d90..b1667375ffa 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -18,13 +18,9 @@ */ package org.skriptlang.skript.bukkit.chat.util; -import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.VariableString; import ch.njol.skript.registrations.Classes; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -33,14 +29,13 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -303,53 +298,20 @@ public static String toLegacyString(String string, boolean all) { return toLegacyString(parse(string, !all)); } + private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.builder() + .hexColors() + .hexCharacter(LegacyComponentSerializer.HEX_CHAR) + .character(LegacyComponentSerializer.SECTION_CHAR) + .useUnusualXRepeatedCharacterHexFormat() + .build(); + /** * Converts a component into a legacy formatted string. * @param component The component to convert. * @return The legacy string. */ public static String toLegacyString(Component component) { - return BukkitComponentSerializer.legacy().serialize(component); - } - - @Nullable - private static BukkitAudiences adventure = null; // Can't set here as we need an instance of Skript - - public static BukkitAudiences getAdventure() { - if (adventure == null) - adventure = BukkitAudiences.create(Skript.getInstance()); - // TODO we might need to close this ('adventure.close()') - return adventure; - } - - /** - * Constructs an audience from command senders. - * @param senders The members of this audience. - * @return An audience consisting of the provided command senders. - */ - @SuppressWarnings("ConstantConditions") - public static Audience audienceFrom(Collection senders) { - List bukkitAudiences = new ArrayList<>(); - for (CommandSender sender : senders) { - if (sender instanceof Audience) { // On paper, a CommandSender is an Audience - bukkitAudiences.add(sender); - } else { - bukkitAudiences.add(getAdventure().sender(sender)); - } - } - return Audience.audience(bukkitAudiences); - } - - /** - * Constructs an audience from command senders. - * @param senders The members of this audience. - * @return An audience consisting of the provided command senders. - */ - public static Audience audienceFrom(CommandSender... senders) { - List bukkitAudiences = new ArrayList<>(); - for (CommandSender sender : senders) - bukkitAudiences.add(getAdventure().sender(sender)); - return Audience.audience(bukkitAudiences); + return LEGACY_SERIALIZER.serialize(component); } } diff --git a/src/test/skript/environments/java8/paper-1.13.2.json b/src/test/skript/environments/java8/paper-1.13.2.json deleted file mode 100644 index e6efb949c03..00000000000 --- a/src/test/skript/environments/java8/paper-1.13.2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.13.2", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.13.2", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar" - ] -} diff --git a/src/test/skript/environments/java8/paper-1.14.4.json b/src/test/skript/environments/java8/paper-1.14.4.json deleted file mode 100644 index 1e2972dd84c..00000000000 --- a/src/test/skript/environments/java8/paper-1.14.4.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.14.4", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.14.4", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar" - ] -} diff --git a/src/test/skript/environments/java8/paper-1.15.2.json b/src/test/skript/environments/java8/paper-1.15.2.json deleted file mode 100644 index 08a849ff98d..00000000000 --- a/src/test/skript/environments/java8/paper-1.15.2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.15.2", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.15.2", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar", "--nogui" - ] -} diff --git a/src/test/skript/environments/java8/paper-1.16.5.json b/src/test/skript/environments/java8/paper-1.16.5.json deleted file mode 100644 index 690a180c001..00000000000 --- a/src/test/skript/environments/java8/paper-1.16.5.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.16.5", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.16.5", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar", "--nogui" - ] -} From ffe1f1a7f1fdfb74b419d04d838fac210ea7fb30 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Sat, 23 Jul 2022 20:15:18 -0400 Subject: [PATCH 05/11] It actually only supports Paper 1.19 --- .github/workflows/java-17-builds.yml | 2 +- .github/workflows/java-8-builds.yml | 30 ------------------- .../environments/java17/paper-1.17.1.json | 17 ----------- .../environments/java17/paper-1.18.2.json | 17 ----------- 4 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 .github/workflows/java-8-builds.yml delete mode 100644 src/test/skript/environments/java17/paper-1.17.1.json delete mode 100644 src/test/skript/environments/java17/paper-1.18.2.json diff --git a/.github/workflows/java-17-builds.yml b/.github/workflows/java-17-builds.yml index 4fca18351a0..c427d981cdf 100644 --- a/.github/workflows/java-17-builds.yml +++ b/.github/workflows/java-17-builds.yml @@ -1,4 +1,4 @@ -name: Java 17 CI (MC 1.17+) +name: Java 17 CI (MC 1.19+) on: [push, pull_request] diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-8-builds.yml deleted file mode 100644 index 0b466c141a4..00000000000 --- a/.github/workflows/java-8-builds.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Java 8 CI (MC 1.13-1.16) - -on: [push, pull_request] - -jobs: - build: - if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'adopt' - cache: gradle - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Build Skript - run: ./gradlew nightlyRelease - - name: Run test scripts - run: ./gradlew clean skriptTestJava8 - - name: Upload Nightly Build - uses: actions/upload-artifact@v3 - if: success() - with: - name: skript-nightly - path: build/libs/Skript-nightly.jar diff --git a/src/test/skript/environments/java17/paper-1.17.1.json b/src/test/skript/environments/java17/paper-1.17.1.json deleted file mode 100644 index 720eba10ef5..00000000000 --- a/src/test/skript/environments/java17/paper-1.17.1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.17.1", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.17.1", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar", "--nogui" - ] -} diff --git a/src/test/skript/environments/java17/paper-1.18.2.json b/src/test/skript/environments/java17/paper-1.18.2.json deleted file mode 100644 index 406bdd99c06..00000000000 --- a/src/test/skript/environments/java17/paper-1.18.2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "paper-1.18.2", - "resources": [ - {"source": "server.properties.generic", "target": "server.properties"} - ], - "paperDownloads": [ - { - "version": "1.18.2", - "target": "paperclip.jar" - } - ], - "skriptTarget": "plugins/Skript.jar", - "commandLine": [ - "-Dcom.mojang.eula.agree=true", - "-jar", "paperclip.jar", "--nogui" - ] -} From e831c137382ae8c1318d21acaf7092550bda6fb3 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Mon, 25 Jul 2022 21:48:54 -0400 Subject: [PATCH 06/11] Revert "It actually only supports Paper 1.19" This reverts commit ffe1f1a7f1fdfb74b419d04d838fac210ea7fb30. --- .github/workflows/java-17-builds.yml | 2 +- .github/workflows/java-8-builds.yml | 30 +++++++++++++++++++ .../environments/java17/paper-1.17.1.json | 17 +++++++++++ .../environments/java17/paper-1.18.2.json | 17 +++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/java-8-builds.yml create mode 100644 src/test/skript/environments/java17/paper-1.17.1.json create mode 100644 src/test/skript/environments/java17/paper-1.18.2.json diff --git a/.github/workflows/java-17-builds.yml b/.github/workflows/java-17-builds.yml index c427d981cdf..4fca18351a0 100644 --- a/.github/workflows/java-17-builds.yml +++ b/.github/workflows/java-17-builds.yml @@ -1,4 +1,4 @@ -name: Java 17 CI (MC 1.19+) +name: Java 17 CI (MC 1.17+) on: [push, pull_request] diff --git a/.github/workflows/java-8-builds.yml b/.github/workflows/java-8-builds.yml new file mode 100644 index 00000000000..0b466c141a4 --- /dev/null +++ b/.github/workflows/java-8-builds.yml @@ -0,0 +1,30 @@ +name: Java 8 CI (MC 1.13-1.16) + +on: [push, pull_request] + +jobs: + build: + if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + cache: gradle + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build Skript + run: ./gradlew nightlyRelease + - name: Run test scripts + run: ./gradlew clean skriptTestJava8 + - name: Upload Nightly Build + uses: actions/upload-artifact@v3 + if: success() + with: + name: skript-nightly + path: build/libs/Skript-nightly.jar diff --git a/src/test/skript/environments/java17/paper-1.17.1.json b/src/test/skript/environments/java17/paper-1.17.1.json new file mode 100644 index 00000000000..720eba10ef5 --- /dev/null +++ b/src/test/skript/environments/java17/paper-1.17.1.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.17.1", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.17.1", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar", "--nogui" + ] +} diff --git a/src/test/skript/environments/java17/paper-1.18.2.json b/src/test/skript/environments/java17/paper-1.18.2.json new file mode 100644 index 00000000000..406bdd99c06 --- /dev/null +++ b/src/test/skript/environments/java17/paper-1.18.2.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.18.2", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.18.2", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar", "--nogui" + ] +} From 0bc16b94f60cfd0192966e5ce05582ce6cc3c8c0 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Mon, 25 Jul 2022 21:49:01 -0400 Subject: [PATCH 07/11] Revert "Make this experiment use Paper's integration" This reverts commit a6566f3616c774ee2f40954df327fa1c30e5831c. --- build.gradle | 16 +-- src/main/java/ch/njol/skript/Skript.java | 6 +- .../ch/njol/skript/command/ScriptCommand.java | 2 +- .../ch/njol/skript/expressions/ExprName.java | 134 ++++++++++-------- .../ch/njol/skript/expressions/ExprNamed.java | 50 +++---- .../ExprPlayerListHeaderFooter.java | 41 +++--- .../skript/bukkit/chat/ChatModule.java | 18 +-- .../bukkit/chat/elements/EffBroadcast.java | 29 ++-- .../bukkit/chat/elements/EffMessage.java | 25 ++-- .../bukkit/chat/elements/EffSendTitle.java | 40 +++--- .../bukkit/chat/util/ComponentHandler.java | 56 ++++++-- .../environments/java8/paper-1.13.2.json | 17 +++ .../environments/java8/paper-1.14.4.json | 17 +++ .../environments/java8/paper-1.15.2.json | 17 +++ .../environments/java8/paper-1.16.5.json | 17 +++ 15 files changed, 284 insertions(+), 201 deletions(-) create mode 100644 src/test/skript/environments/java8/paper-1.13.2.json create mode 100644 src/test/skript/environments/java8/paper-1.14.4.json create mode 100644 src/test/skript/environments/java8/paper-1.15.2.json create mode 100644 src/test/skript/environments/java8/paper-1.16.5.json diff --git a/build.gradle b/build.gradle index 59c5ef55a73..b5ce7ed1b8f 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,8 @@ dependencies { shadow group: 'io.papermc', name: 'paperlib', version: '1.0.7' shadow group: 'org.bstats', name: 'bstats-bukkit', version: '3.0.0' implementation group: 'io.papermc.paper', name: 'paper-api', version: '1.19-R0.1-SNAPSHOT' - shadow group: 'net.kyori', name: 'adventure-text-serializer-legacy', version: '4.11.0-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-text-minimessage', version: '4.11.0-SNAPSHOT' + shadow group: 'net.kyori', name: 'adventure-platform-bukkit', version: '4.1.1-SNAPSHOT' shadow group: 'net.kyori', name: 'adventure-text-serializer-plain', version: '4.11.0-SNAPSHOT' implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.2.600' implementation group: 'com.google.code.findbugs', name: 'findbugs', version: '3.0.1' @@ -74,15 +75,9 @@ tasks.withType(ShadowJar) { configurations = [ project.configurations.shadow ] - dependencies { - include(dependency('io.papermc:paperlib')) - include(dependency('org.bstats:bstats-bukkit')) - include(dependency('org.bstats:bstats-base')) - include(dependency('net.kyori:adventure-text-serializer-legacy')) - include(dependency('net.kyori:adventure-text-serializer-plain')) - } relocate 'io.papermc.lib', 'ch.njol.skript.paperlib' relocate 'org.bstats', 'ch.njol.skript.bstats' + relocate 'net.kyori', 'ch.njol.skript.kyori' manifest { attributes( 'Name': 'ch/njol/skript', @@ -192,7 +187,7 @@ void createTestTask(String name, String environments, boolean devMode, int javaV def latestEnv = 'java17/paper-1.19.json' def latestJava = 17 -def oldestJava = 17 +def oldestJava = 8 tasks.withType(JavaCompile).configureEach { options.compilerArgs += ["-source", "" + oldestJava, "-target", "" + oldestJava] @@ -201,10 +196,11 @@ tasks.withType(JavaCompile).configureEach { // Register different Skript testing tasks createTestTask('quickTest', 'src/test/skript/environments/' + latestEnv, false, latestJava, false) createTestTask('skriptTestJava17', 'src/test/skript/environments/java17', false, latestJava, false) +createTestTask('skriptTestJava8', 'src/test/skript/environments/java8', false, oldestJava, false) createTestTask('skriptTestDev', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), true, Integer.parseInt(project.property('testEnvJavaVersion') == null ? latestJava : project.property('testEnvJavaVersion')), false) -tasks.register('skriptTest') {dependsOn skriptTestJava17} +tasks.register('skriptTest') {dependsOn skriptTestJava8, skriptTestJava17} createTestTask('genDocs', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), false, Integer.parseInt(project.property('testEnvJavaVersion') == null ? latestJava : project.property('testEnvJavaVersion')), true) diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index bcf0241149a..3d0f634dbbf 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -1742,7 +1742,7 @@ static void logEx(final String... lines) { // } public static void info(final CommandSender sender, final String info) { - sender.sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(info))); + ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(info))); } /** @@ -1765,11 +1765,11 @@ public static void adminBroadcast(final String message) { * @param info */ public static void message(final CommandSender sender, final String info) { - sender.sendMessage(ComponentHandler.parse(info)); + ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parse(info)); } public static void error(final CommandSender sender, final String error) { - sender.sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(error).color(NamedTextColor.DARK_RED))); + ComponentHandler.audienceFrom(sender).sendMessage(SKRIPT_PREFIX_COMPONENT.append(ComponentHandler.parse(error).color(NamedTextColor.DARK_RED))); } /** diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index a14e59d5906..15b823a1f3e 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -207,7 +207,7 @@ public boolean execute(final CommandSender sender, final String commandLabel, fi final ScriptCommandEvent event = new ScriptCommandEvent(ScriptCommand.this, sender); if (!permission.isEmpty() && !sender.hasPermission(permission)) { - sender.sendMessage(ComponentHandler.parseFromSingleExpression(event, permissionMessage)); + ComponentHandler.audienceFrom(sender).sendMessage(ComponentHandler.parseFromSingleExpression(event, permissionMessage)); return false; } diff --git a/src/main/java/ch/njol/skript/expressions/ExprName.java b/src/main/java/ch/njol/skript/expressions/ExprName.java index 831dd0e44ad..c0c26f40e8c 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprName.java +++ b/src/main/java/ch/njol/skript/expressions/ExprName.java @@ -18,21 +18,12 @@ */ package ch.njol.skript.expressions; -import ch.njol.skript.Skript; -import ch.njol.skript.aliases.Aliases; -import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.slot.Slot; -import ch.njol.util.Kleenean; -import ch.njol.util.coll.CollectionUtils; -import net.kyori.adventure.text.Component; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; + import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.Nameable; @@ -50,8 +41,21 @@ import org.bukkit.inventory.meta.ItemMeta; import org.eclipse.jdt.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.Aliases; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import net.md_5.bungee.api.ChatColor; @Name("Name / Display Name / Tab List Name") @Description({"Represents the Minecraft account, display or tab list name of a player, or the custom name of an item, entity, block, inventory, or gamerule.", @@ -95,14 +99,24 @@ " set the player's tab list name to \"<green>%player's name%\"", "set the name of the player's tool to \"Legendary Sword of Awesomeness\""}) @Since("before 2.1, 2.2-dev20 (inventory name), 2.4 (non-living entity support, changeable inventory name)") -public class ExprName extends SimplePropertyExpression { +public class ExprName extends SimplePropertyExpression { + + @Nullable + static final MethodHandle TITLE_METHOD; + static final boolean HAS_GAMERULES; static { - register(ExprName.class, Component.class, - "(1:name[s]|2:(display|nick|chat|custom)[ ]name[s])", - "offlineplayers/entities/blocks/itemtypes/inventories/slots/gamerules" - ); - register(ExprName.class, Component.class, "(3:(player|tab)[ ]list name[s])", "players"); + HAS_GAMERULES = Skript.classExists("org.bukkit.GameRule"); + register(ExprName.class, String.class, "(1¦name[s]|2¦(display|nick|chat|custom)[ ]name[s])", "offlineplayers/entities/blocks/itemtypes/inventories/slots" + + (HAS_GAMERULES ? "/gamerules" : "")); + register(ExprName.class, String.class, "(3¦(player|tab)[ ]list name[s])", "players"); + + // Get the old method for getting the name of an inventory. + MethodHandle _METHOD = null; + try { + _METHOD = MethodHandles.lookup().findVirtual(Inventory.class, "getTitle", MethodType.methodType(String.class)); + } catch (IllegalAccessException | NoSuchMethodException ignored) {} + TITLE_METHOD = _METHOD; } /* @@ -123,45 +137,51 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override @Nullable - public Component convert(Object o) { + public String convert(Object o) { if (o instanceof OfflinePlayer && ((OfflinePlayer) o).isOnline()) o = ((OfflinePlayer) o).getPlayer(); if (o instanceof Player) { switch (mark) { case 1: - return ((Player) o).name(); + return ((Player) o).getName(); case 2: - return ((Player) o).displayName(); + return ((Player) o).getDisplayName(); case 3: - return ((Player) o).playerListName(); + return ((Player) o).getPlayerListName(); } } else if (o instanceof OfflinePlayer) { - if (mark != 1) - return null; - String name = ((OfflinePlayer) o).getName(); - return name != null ? Component.text(name) : null; + return mark == 1 ? ((OfflinePlayer) o).getName() : null; } else if (o instanceof Entity) { - return ((Entity) o).customName(); + return ((Entity) o).getCustomName(); } else if (o instanceof Block) { BlockState state = ((Block) o).getState(); if (state instanceof Nameable) - return ((Nameable) state).customName(); + return ((Nameable) state).getCustomName(); } else if (o instanceof ItemType) { ItemMeta m = ((ItemType) o).getItemMeta(); - return m.hasDisplayName() ? m.displayName() : null; + return m.hasDisplayName() ? m.getDisplayName() : null; } else if (o instanceof Inventory) { - if (!((Inventory) o).getViewers().isEmpty()) - return ((Inventory) o).getViewers().get(0).getOpenInventory().title(); - return null; + if (TITLE_METHOD != null) { + try { + return (String) TITLE_METHOD.invoke(o); + } catch (Throwable e) { + Skript.exception(e); + return null; + } + } else { + if (!((Inventory) o).getViewers().isEmpty()) + return ((Inventory) o).getViewers().get(0).getOpenInventory().getTitle(); + return null; + } } else if (o instanceof Slot) { ItemStack is = ((Slot) o).getItem(); if (is != null && is.hasItemMeta()) { ItemMeta m = is.getItemMeta(); - return m.hasDisplayName() ? m.displayName() : null; + return m.hasDisplayName() ? m.getDisplayName() : null; } - } else if (o instanceof GameRule) { - return Component.text(((GameRule) o).getName()); + } else if (HAS_GAMERULES && o instanceof GameRule) { + return ((GameRule) o).getName(); } return null; } @@ -174,26 +194,26 @@ public Class[] acceptChange(ChangeMode mode) { Skript.error("Can't change the Minecraft name of a player. Change the 'display name' or 'tab list name' instead."); return null; } - return CollectionUtils.array(Component.class); + return CollectionUtils.array(String.class); } return null; } @Override public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { - Component name = delta != null ? (Component) delta[0] : null; + String name = delta != null ? (String) delta[0] : null; for (Object o : getExpr().getArray(e)) { if (o instanceof Player) { switch (mark) { case 2: - ((Player) o).displayName(name); + ((Player) o).setDisplayName(name != null ? name + ChatColor.RESET : ((Player) o).getName()); break; - case 3: - ((Player) o).playerListName(name); + case 3: // Null check not necessary. This method will use the player's name if 'name' is null. + ((Player) o).setPlayerListName(name); break; } } else if (o instanceof Entity) { - ((Entity) o).customName(name); + ((Entity) o).setCustomName(name); if (mark == 2 || mode == ChangeMode.RESET) // Using "display name" ((Entity) o).setCustomNameVisible(name != null); if (o instanceof LivingEntity) @@ -201,13 +221,13 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { } else if (o instanceof Block) { BlockState state = ((Block) o).getState(); if (state instanceof Nameable) { - ((Nameable) state).customName(name); + ((Nameable) state).setCustomName(name); state.update(); } } else if (o instanceof ItemType) { ItemType i = (ItemType) o; ItemMeta m = i.getItemMeta(); - m.displayName(name); + m.setDisplayName(name); i.setItemMeta(m); } else if (o instanceof Inventory) { Inventory inv = (Inventory) o; @@ -221,7 +241,7 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { if (!type.isCreatable()) return; if (name == null) - name = type.defaultTitle(); + name = type.getDefaultTitle(); Inventory copy; if (type == InventoryType.CHEST) { @@ -236,7 +256,7 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { ItemStack is = s.getItem(); if (is != null && !AIR.isOfType(is)) { ItemMeta m = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); - m.displayName(name); + m.setDisplayName(name); is.setItemMeta(m); s.setItem(is); } @@ -245,19 +265,17 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { } @Override - public Class getReturnType() { - return Component.class; + public Class getReturnType() { + return String.class; } @Override protected String getPropertyName() { switch (mark) { - case 2: - return "display name"; - case 3: - return "tablist name"; - default: - return "name"; + case 1: return "name"; + case 2: return "display name"; + case 3: return "tablist name"; + default: return "name"; } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprNamed.java b/src/main/java/ch/njol/skript/expressions/ExprNamed.java index 2a7a6e1f9f7..c01724bb7f2 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprNamed.java +++ b/src/main/java/ch/njol/skript/expressions/ExprNamed.java @@ -18,7 +18,6 @@ */ package ch.njol.skript.expressions; -import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.inventory.InventoryType; @@ -40,45 +39,42 @@ import ch.njol.skript.util.Getter; import ch.njol.util.Kleenean; +/** + * @author Peter Güttinger + */ @Name("Named Item/Inventory") -@Description({ - "Directly names an item/inventory, useful for defining a named item/inventory in a script.", - "If you want to (re)name existing items/inventories you can either use this expression or " - + "use set name of <item/inventory> to <text>." -}) -@Examples({ - "give a diamond sword of sharpness 100 named \"<gold>Excalibur\" to the player", - "set tool of player to the player's tool named \"<gold>Wand\"", - "set the name of the player's tool to \"<gold>Wand\"", - "open hopper inventory named \"Magic Hopper\" to player" -}) +@Description("Directly names an item/inventory, useful for defining a named item/inventory in a script. " + + "If you want to (re)name existing items/inventories you can either use this expression or use set name of <item/inventory> to <text>.") +@Examples({"give a diamond sword of sharpness 100 named \"<gold>Excalibur\" to the player", + "set tool of player to the player's tool named \"<gold>Wand\"", + "set the name of the player's tool to \"<gold>Wand\"", + "open hopper inventory named \"Magic Hopper\" to player"}) @Since("2.0, 2.2-dev34 (inventories)") public class ExprNamed extends PropertyExpression { - static { Skript.registerExpression(ExprNamed.class, Object.class, ExpressionType.PROPERTY, - "%itemtype/inventorytype% (named|with name[s]) %component%" - ); + "%itemtype/inventorytype% (named|with name[s]) %string%"); } - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression name; - + @SuppressWarnings("null") + private Expression name; + + @SuppressWarnings({"unchecked", "null"}) @Override - @SuppressWarnings("unchecked") - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { setExpr(exprs[0]); - name = (Expression) exprs[1]; + name = (Expression) exprs[1]; return true; } @Override protected Object[] get(final Event e, final Object[] source) { - Component name = this.name.getSingle(e); + String name = this.name.getSingle(e); if (name == null) return get(source, obj -> obj); // No name provided, do nothing return get(source, new Getter() { @Override + @Nullable public Object get(Object obj) { if (obj instanceof InventoryType) return Bukkit.createInventory(null, (InventoryType) obj, name); @@ -87,7 +83,7 @@ public Object get(Object obj) { stack = stack.clone(); ItemMeta meta = stack.getItemMeta(); if (meta != null) { - meta.displayName(name); + meta.setDisplayName(name); stack.setItemMeta(meta); } return new ItemType(stack); @@ -95,7 +91,7 @@ public Object get(Object obj) { ItemType item = (ItemType) obj; item = item.clone(); ItemMeta meta = item.getItemMeta(); - meta.displayName(name); + meta.setDisplayName(name); item.setItemMeta(meta); return item; } @@ -103,13 +99,13 @@ public Object get(Object obj) { } @Override - public Class getReturnType() { + public Class getReturnType() { return getExpr().getReturnType() == InventoryType.class ? Inventory.class : ItemType.class; } @Override - public String toString(@Nullable Event e, boolean debug) { - return getExpr().toString(e, debug) + " named " + name.toString(e, debug); + public String toString(final @Nullable Event e, final boolean debug) { + return getExpr().toString(e, debug) + " named " + name; } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java index 40aeaf51e71..c8dc302014c 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java +++ b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java @@ -29,6 +29,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; +import io.skriptlang.skript.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -43,26 +44,24 @@ "reset all players' tab list header" }) @Since("2.4") -public class ExprPlayerListHeaderFooter extends SimplePropertyExpression { +public class ExprPlayerListHeaderFooter extends SimplePropertyExpression { static { - PropertyExpression.register(ExprPlayerListHeaderFooter.class, Component.class, - "(player|tab)[ ]list (header|:footer) [(text|message)]", "players" - ); + PropertyExpression.register(ExprPlayerListHeaderFooter.class, String.class, "(player|tab)[ ]list (header|1¦footer) [(text|message)]", "players"); } - private boolean footer; + private boolean isHeader; @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - footer = parseResult.hasTag("footer"); + isHeader = parseResult.mark == 0; return super.init(exprs, matchedPattern, isDelayed, parseResult); } @Override @Nullable - public Component convert(Player player) { - return footer ? player.playerListFooter() : player.playerListHeader(); + public String convert(Player player) { + return isHeader ? player.getPlayerListHeader() : player.getPlayerListFooter(); } @Override @@ -72,7 +71,7 @@ public Class[] acceptChange(ChangeMode mode) { case SET: case DELETE: case RESET: - return CollectionUtils.array(Component[].class); + return CollectionUtils.array(String[].class, Component.class); default: return null; } @@ -80,26 +79,30 @@ public Class[] acceptChange(ChangeMode mode) { @Override public void change(Event e, @Nullable Object[] delta, ChangeMode mode) { - Component component = Component.empty(); - for (Object userComponent : delta) - component = component.append((Component) userComponent).append(Component.newline()); - - Audience audience = Audience.audience(getExpr().getArray(e)); - if (footer) { - audience.sendPlayerListFooter(component); + Component component; + if (delta == null) { + component = Component.empty(); + } else if (delta[0] instanceof Component) { + component = (Component) delta[0]; } else { + component = ComponentHandler.parse(String.join("\n", (String[]) delta), false); + } + Audience audience = ComponentHandler.audienceFrom(getExpr().getArray(e)); + if (isHeader) { audience.sendPlayerListHeader(component); + } else { + audience.sendPlayerListFooter(component); } } @Override - public Class getReturnType() { - return Component.class; + public Class getReturnType() { + return String.class; } @Override protected String getPropertyName() { - return "player list " + (footer ? "header" : "footer"); + return "player list " + (isHeader ? "header" : "footer"); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java index d6f16121cf9..81f0dc6031c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java @@ -20,11 +20,9 @@ import ch.njol.skript.SkriptAddon; import ch.njol.skript.classes.ClassInfo; -import ch.njol.skript.classes.Comparator; import ch.njol.skript.classes.Parser; import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; -import ch.njol.skript.registrations.Comparators; import ch.njol.skript.registrations.Converters; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.text.Component; @@ -39,24 +37,13 @@ public class ChatModule { public void register(SkriptAddon addon) { try { - addon.loadClasses("org.skriptlang.skript.bukkit.chat.elements"); + addon.loadClasses("io.skriptlang.skript.chat.elements"); } catch (IOException e) { e.printStackTrace(); } Converters.registerConverter(String.class, Component.class, ComponentHandler::parse); Converters.registerConverter(Component.class, String.class, ComponentHandler::toLegacyString); - Comparators.registerComparator(String.class, Component.class, new Comparator() { - @Override - public Relation compare(String o1, Component o2) { - return Relation.get(o1.equals(ComponentHandler.toLegacyString(o2))); - } - - @Override - public boolean supportsOrdering() { - return false; - } - }); Classes.registerClass(new ClassInfo<>(Component.class, "component") .user("components?") @@ -80,6 +67,9 @@ public String toVariableNameString(Component component) { }) ); + // Just to initialize it now + ComponentHandler.getAdventure(); + ComponentHandler.registerPlaceholder("dark_cyan", ""); ComponentHandler.registerPlaceholder("dark_turquoise", ""); ComponentHandler.registerPlaceholder("cyan", ""); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java index a224eb43c11..48453dba1f5 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java @@ -29,8 +29,6 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; -import ch.njol.util.coll.CollectionUtils; -import net.kyori.adventure.text.Component; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import org.bukkit.Bukkit; @@ -49,12 +47,13 @@ "broadcast \"Woah! It's a message!\"" }) @Since("1.0, 2.6 (broadcasting objects), 2.6.1 (using advanced formatting)") +// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffBroadcast extends Effect { @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; + private Expression messageExpr; // Used in toString @Nullable private Expression worlds; @@ -66,34 +65,24 @@ public class EffBroadcast extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { messageExpr = LiteralUtils.defendExpression(exprs[0]); - if (messageExpr instanceof ExpressionList) { - ExpressionList exprList = (ExpressionList) messageExpr; - if (exprList.getAnd()) { - messages = exprList.getExpressions(); - } else { - messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; - } - } else { - messages = new Expression[]{messageExpr}; - } - + messages = messageExpr instanceof ExpressionList ? + ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; worlds = (Expression) exprs[1]; return LiteralUtils.canInitSafely(messageExpr); } @Override protected void execute(Event e) { + List recipients = new ArrayList<>(); if (worlds == null) { - for (Component component : ComponentHandler.parseFromExpressions(e, messages)) - Bukkit.broadcast(component); + recipients.addAll(Bukkit.getOnlinePlayers()); + recipients.add(Bukkit.getConsoleSender()); } else { - List recipients = new ArrayList<>(); for (World world : worlds.getArray(e)) recipients.addAll(world.getPlayers()); - Audience audience = Audience.audience(recipients); - for (Component component : ComponentHandler.parseFromExpressions(e, messages)) - audience.sendMessage(component); } + Audience audience = ComponentHandler.audienceFrom(recipients); + ComponentHandler.parseFromExpressions(e, messages).forEach(audience::sendMessage); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java index 42e6d841707..8162a047bfa 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java @@ -30,7 +30,6 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; -import ch.njol.util.coll.CollectionUtils; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; @@ -62,6 +61,7 @@ }) @RequiredPlugins("Minecraft 1.16.4+ for optional sender") @Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") +// See what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffMessage extends Effect { static { @@ -74,7 +74,7 @@ public class EffMessage extends Effect { @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; @SuppressWarnings("NotNullFieldNotInitialized") - private Expression messageExpr; + private Expression messageExpr; // Used in toString @SuppressWarnings("NotNullFieldNotInitialized") private Expression recipients; @@ -87,19 +87,9 @@ public class EffMessage extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { isChatMessage = matchedPattern == 0; - messageExpr = LiteralUtils.defendExpression(exprs[0]); - if (messageExpr instanceof ExpressionList) { - ExpressionList exprList = (ExpressionList) messageExpr; - if (exprList.getAnd()) { - messages = exprList.getExpressions(); - } else { - messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; - } - } else { - messages = new Expression[]{messageExpr}; - } - + messages = messageExpr instanceof ExpressionList ? + ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; recipients = (Expression) exprs[1]; if (isChatMessage) sender = (Expression) exprs[2]; @@ -108,7 +98,8 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event e) { - Audience audience = Audience.audience(recipients.getArray(e)); + long start = System.nanoTime(); + Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); List components = ComponentHandler.parseFromExpressions(e, messages); @@ -118,9 +109,9 @@ protected void execute(Event e) { for (Component component : components) audience.sendMessage(identity, component); } else { - for (Component component : components) - audience.sendActionBar(component); + components.forEach(audience::sendActionBar); } + System.out.println("TIME TO EXECUTE SEND MESSAGE: " + (1. * (System.nanoTime() - start) / 1000000.)); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java index 38ea543313c..fecd73c6d41 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java @@ -41,22 +41,18 @@ @Name("Send Title") @Description({ - "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above. ", - "", - "If you're sending only the subtitle, it will be shown only if there's a title displayed at the moment, otherwise it will " - + "be sent with the next title. To show only the subtitle, use: send title \" \" with subtitle \"yourtexthere\" to player.", - "", - "Note: if no input is given for the times, it will keep the ones from the last title sent, " - + "use the reset title effect to restore the default values." + "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above.", + "Note: if no input is given for the title/subtitle or the times, " + + "it will keep the ones from the last title sent, use the reset title effect to restore the default values." }) @Examples({ - "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", - "send title \"Hi %player%\" to player", - "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", - "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", - "send subtitle \"Party!\" to all players" + "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", + "send title \"Hi %player%\" to player", "send title \"Loot Drop\" with subtitle \"starts in 3 minutes\" to all players", + "send title \"Hello %player%!\" with subtitle \"Welcome to our server\" to player for 5 seconds with fadein 1 second and fade out 1 second", + "send subtitle \"Party!\" to all players" }) @Since("2.3, INSERT VERSION (sending objects)") +// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4362 public class EffSendTitle extends Effect { static { @@ -89,17 +85,18 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event e) { - Audience audience = Audience.audience(recipients.getArray(e)); + Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); Timespan fadeIn = this.fadeIn != null ? this.fadeIn.getSingle(e) : null; Timespan stay = this.stay != null ? this.stay.getSingle(e) : null; Timespan fadeOut = this.fadeOut != null ? this.fadeOut.getSingle(e) : null; - Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Title.DEFAULT_TIMES.fadeIn(); - Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Title.DEFAULT_TIMES.stay(); - Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Title.DEFAULT_TIMES.fadeOut(); + // From Title#DEFAULT_TIMES + Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Ticks.duration(10); + Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Ticks.duration(70); + Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Ticks.duration(20); - Times times = Times.times(fadeInDuration, stayDuration, fadeOutDuration); + Times times = Times.of(fadeInDuration, stayDuration, fadeOutDuration); Title title = Title.title(ComponentHandler.parseFromSingleExpression(e, this.title), ComponentHandler.parseFromSingleExpression(e, this.subtitle), times); audience.showTitle(title); @@ -122,14 +119,12 @@ public String toString(@Nullable Event e, boolean debug) { if (stay != null) { builder.append(" for ").append(stay.toString(e, debug)); } else { - long ticks = Title.DEFAULT_TIMES.stay().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; - builder.append(" for ").append(ticks).append(" ticks"); + builder.append(" for 70 ticks"); } if (fadeIn != null) { builder.append(" with fade in ").append(fadeIn.toString(e, debug)); } else { - long ticks = Title.DEFAULT_TIMES.fadeIn().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; - builder.append(" with fade in ").append(ticks).append(" ticks"); + builder.append(" with fade in 10 ticks"); } if (fadeOut != null) { builder.append(" with fade out ").append(fadeOut.toString(e, debug)); @@ -139,8 +134,7 @@ public String toString(@Nullable Event e, boolean debug) { } else { builder.append(" with"); } - long ticks = Title.DEFAULT_TIMES.fadeOut().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; - builder.append(" fade out ").append(ticks).append(" ticks"); + builder.append(" fade out 20 ticks"); } return builder.toString(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index b1667375ffa..ca46b795d90 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -18,9 +18,13 @@ */ package org.skriptlang.skript.bukkit.chat.util; +import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.VariableString; import ch.njol.skript.registrations.Classes; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -29,13 +33,14 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -298,20 +303,53 @@ public static String toLegacyString(String string, boolean all) { return toLegacyString(parse(string, !all)); } - private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.builder() - .hexColors() - .hexCharacter(LegacyComponentSerializer.HEX_CHAR) - .character(LegacyComponentSerializer.SECTION_CHAR) - .useUnusualXRepeatedCharacterHexFormat() - .build(); - /** * Converts a component into a legacy formatted string. * @param component The component to convert. * @return The legacy string. */ public static String toLegacyString(Component component) { - return LEGACY_SERIALIZER.serialize(component); + return BukkitComponentSerializer.legacy().serialize(component); + } + + @Nullable + private static BukkitAudiences adventure = null; // Can't set here as we need an instance of Skript + + public static BukkitAudiences getAdventure() { + if (adventure == null) + adventure = BukkitAudiences.create(Skript.getInstance()); + // TODO we might need to close this ('adventure.close()') + return adventure; + } + + /** + * Constructs an audience from command senders. + * @param senders The members of this audience. + * @return An audience consisting of the provided command senders. + */ + @SuppressWarnings("ConstantConditions") + public static Audience audienceFrom(Collection senders) { + List bukkitAudiences = new ArrayList<>(); + for (CommandSender sender : senders) { + if (sender instanceof Audience) { // On paper, a CommandSender is an Audience + bukkitAudiences.add(sender); + } else { + bukkitAudiences.add(getAdventure().sender(sender)); + } + } + return Audience.audience(bukkitAudiences); + } + + /** + * Constructs an audience from command senders. + * @param senders The members of this audience. + * @return An audience consisting of the provided command senders. + */ + public static Audience audienceFrom(CommandSender... senders) { + List bukkitAudiences = new ArrayList<>(); + for (CommandSender sender : senders) + bukkitAudiences.add(getAdventure().sender(sender)); + return Audience.audience(bukkitAudiences); } } diff --git a/src/test/skript/environments/java8/paper-1.13.2.json b/src/test/skript/environments/java8/paper-1.13.2.json new file mode 100644 index 00000000000..e6efb949c03 --- /dev/null +++ b/src/test/skript/environments/java8/paper-1.13.2.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.13.2", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.13.2", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar" + ] +} diff --git a/src/test/skript/environments/java8/paper-1.14.4.json b/src/test/skript/environments/java8/paper-1.14.4.json new file mode 100644 index 00000000000..1e2972dd84c --- /dev/null +++ b/src/test/skript/environments/java8/paper-1.14.4.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.14.4", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.14.4", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar" + ] +} diff --git a/src/test/skript/environments/java8/paper-1.15.2.json b/src/test/skript/environments/java8/paper-1.15.2.json new file mode 100644 index 00000000000..08a849ff98d --- /dev/null +++ b/src/test/skript/environments/java8/paper-1.15.2.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.15.2", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.15.2", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar", "--nogui" + ] +} diff --git a/src/test/skript/environments/java8/paper-1.16.5.json b/src/test/skript/environments/java8/paper-1.16.5.json new file mode 100644 index 00000000000..690a180c001 --- /dev/null +++ b/src/test/skript/environments/java8/paper-1.16.5.json @@ -0,0 +1,17 @@ +{ + "name": "paper-1.16.5", + "resources": [ + {"source": "server.properties.generic", "target": "server.properties"} + ], + "paperDownloads": [ + { + "version": "1.16.5", + "target": "paperclip.jar" + } + ], + "skriptTarget": "plugins/Skript.jar", + "commandLine": [ + "-Dcom.mojang.eula.agree=true", + "-jar", "paperclip.jar", "--nogui" + ] +} From 8da1e556e560d010d9c1d6b76de11341af4870bd Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Mon, 25 Jul 2022 23:37:49 -0400 Subject: [PATCH 08/11] Fixes and improvements --- build.gradle | 1 - .../ExprPlayerListHeaderFooter.java | 2 +- .../skript/bukkit/chat/ChatModule.java | 2 +- .../bukkit/chat/elements/EffBroadcast.java | 17 +++++++-- .../bukkit/chat/elements/EffMessage.java | 23 ++++++++---- .../bukkit/chat/elements/EffSendTitle.java | 35 ++++++++++++------- .../bukkit/chat/util/CodeConverter.java | 2 ++ .../bukkit/chat/util/ComponentHandler.java | 13 ++++--- 8 files changed, 66 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index b5ce7ed1b8f..a6371d0f76f 100644 --- a/build.gradle +++ b/build.gradle @@ -77,7 +77,6 @@ tasks.withType(ShadowJar) { ] relocate 'io.papermc.lib', 'ch.njol.skript.paperlib' relocate 'org.bstats', 'ch.njol.skript.bstats' - relocate 'net.kyori', 'ch.njol.skript.kyori' manifest { attributes( 'Name': 'ch/njol/skript', diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java index c8dc302014c..0a4d4d4e8cd 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java +++ b/src/main/java/ch/njol/skript/expressions/ExprPlayerListHeaderFooter.java @@ -29,12 +29,12 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; -import io.skriptlang.skript.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; @Name("Player List Header and Footer") @Description("The message above and below the player list in the tab menu.") diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java index 81f0dc6031c..9416bfbe0fe 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java @@ -37,7 +37,7 @@ public class ChatModule { public void register(SkriptAddon addon) { try { - addon.loadClasses("io.skriptlang.skript.chat.elements"); + addon.loadClasses("org.skriptlang.skript.bukkit.chat.elements"); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java index 48453dba1f5..63ebbbd848c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffBroadcast.java @@ -29,6 +29,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import org.bukkit.Bukkit; @@ -47,7 +48,6 @@ "broadcast \"Woah! It's a message!\"" }) @Since("1.0, 2.6 (broadcasting objects), 2.6.1 (using advanced formatting)") -// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffBroadcast extends Effect { @SuppressWarnings("NotNullFieldNotInitialized") @@ -65,8 +65,19 @@ public class EffBroadcast extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { messageExpr = LiteralUtils.defendExpression(exprs[0]); - messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; + + messageExpr = LiteralUtils.defendExpression(exprs[0]); + if (messageExpr instanceof ExpressionList) { + ExpressionList exprList = (ExpressionList) messageExpr; + if (exprList.getAnd()) { + messages = exprList.getExpressions(); + } else { + messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; + } + } else { + messages = new Expression[]{messageExpr}; + } + worlds = (Expression) exprs[1]; return LiteralUtils.canInitSafely(messageExpr); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java index 8162a047bfa..4997ae64dda 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffMessage.java @@ -30,6 +30,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; @@ -61,7 +62,6 @@ }) @RequiredPlugins("Minecraft 1.16.4+ for optional sender") @Since("1.0, 2.2-dev26 (advanced features), 2.5.2 (optional sender), 2.6 (sending objects)") -// See what might need taken from https://github.com/SkriptLang/Skript/pull/4545 public class EffMessage extends Effect { static { @@ -87,18 +87,29 @@ public class EffMessage extends Effect { @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { isChatMessage = matchedPattern == 0; + messageExpr = LiteralUtils.defendExpression(exprs[0]); - messages = messageExpr instanceof ExpressionList ? - ((ExpressionList) messageExpr).getExpressions() : new Expression[]{messageExpr}; + if (messageExpr instanceof ExpressionList) { + ExpressionList exprList = (ExpressionList) messageExpr; + if (exprList.getAnd()) { + messages = exprList.getExpressions(); + } else { + messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; + } + } else { + messages = new Expression[]{messageExpr}; + } + recipients = (Expression) exprs[1]; + if (isChatMessage) sender = (Expression) exprs[2]; + return LiteralUtils.canInitSafely(messageExpr); } @Override protected void execute(Event e) { - long start = System.nanoTime(); Audience audience = ComponentHandler.audienceFrom(recipients.getArray(e)); List components = ComponentHandler.parseFromExpressions(e, messages); @@ -109,9 +120,9 @@ protected void execute(Event e) { for (Component component : components) audience.sendMessage(identity, component); } else { - components.forEach(audience::sendActionBar); + for (Component component : components) + audience.sendActionBar(component); } - System.out.println("TIME TO EXECUTE SEND MESSAGE: " + (1. * (System.nanoTime() - start) / 1000000.)); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java index fecd73c6d41..c64400cebc6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/elements/EffSendTitle.java @@ -26,6 +26,7 @@ import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.LiteralUtils; import ch.njol.skript.util.Timespan; import ch.njol.util.Kleenean; import org.skriptlang.skript.bukkit.chat.util.ComponentHandler; @@ -42,8 +43,8 @@ @Name("Send Title") @Description({ "Sends a title/subtitle to the given player(s) with optional fadein/stay/fadeout times for Minecraft versions 1.11 and above.", - "Note: if no input is given for the title/subtitle or the times, " + - "it will keep the ones from the last title sent, use the reset title effect to restore the default values." + "Note: if no input is given for the title/subtitle or the times, " + + "it will keep the ones from the last title sent, use the reset title effect to restore the default values." }) @Examples({ "send title \"Competition Started\" with subtitle \"Have fun, Stay safe!\" to player for 5 seconds", @@ -52,7 +53,6 @@ "send subtitle \"Party!\" to all players" }) @Since("2.3, INSERT VERSION (sending objects)") -// TODO see what might need taken from https://github.com/SkriptLang/Skript/pull/4362 public class EffSendTitle extends Effect { static { @@ -74,13 +74,20 @@ public class EffSendTitle extends Effect { @Override @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - title = matchedPattern == 0 ? exprs[0] : null; + title = matchedPattern == 0 ? LiteralUtils.defendExpression(exprs[0]) : null; subtitle = exprs[1 - matchedPattern]; + if (subtitle != null) + LiteralUtils.defendExpression(exprs[1 - matchedPattern]); recipients = (Expression) exprs[2 - matchedPattern]; stay = (Expression) exprs[3 - matchedPattern]; fadeIn = (Expression) exprs[4 - matchedPattern]; fadeOut = (Expression) exprs[5 - matchedPattern]; - return true; + if (title != null) { + if (subtitle != null) + return LiteralUtils.canInitSafely(title, subtitle); + return LiteralUtils.canInitSafely(title); + } + return LiteralUtils.canInitSafely(subtitle); } @Override @@ -91,12 +98,11 @@ protected void execute(Event e) { Timespan stay = this.stay != null ? this.stay.getSingle(e) : null; Timespan fadeOut = this.fadeOut != null ? this.fadeOut.getSingle(e) : null; - // From Title#DEFAULT_TIMES - Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Ticks.duration(10); - Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Ticks.duration(70); - Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Ticks.duration(20); + Duration fadeInDuration = fadeIn != null ? Ticks.duration(fadeIn.getTicks_i()) : Title.DEFAULT_TIMES.fadeIn(); + Duration stayDuration = stay != null ? Ticks.duration(stay.getTicks_i()) : Title.DEFAULT_TIMES.stay(); + Duration fadeOutDuration = fadeOut != null ? Ticks.duration(fadeOut.getTicks_i()) : Title.DEFAULT_TIMES.fadeOut(); - Times times = Times.of(fadeInDuration, stayDuration, fadeOutDuration); + Times times = Times.times(fadeInDuration, stayDuration, fadeOutDuration); Title title = Title.title(ComponentHandler.parseFromSingleExpression(e, this.title), ComponentHandler.parseFromSingleExpression(e, this.subtitle), times); audience.showTitle(title); @@ -119,12 +125,14 @@ public String toString(@Nullable Event e, boolean debug) { if (stay != null) { builder.append(" for ").append(stay.toString(e, debug)); } else { - builder.append(" for 70 ticks"); + long ticks = Title.DEFAULT_TIMES.stay().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" for ").append(ticks).append(" ticks"); } if (fadeIn != null) { builder.append(" with fade in ").append(fadeIn.toString(e, debug)); } else { - builder.append(" with fade in 10 ticks"); + long ticks = Title.DEFAULT_TIMES.fadeIn().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" with fade in ").append(ticks).append(" ticks"); } if (fadeOut != null) { builder.append(" with fade out ").append(fadeOut.toString(e, debug)); @@ -134,7 +142,8 @@ public String toString(@Nullable Event e, boolean debug) { } else { builder.append(" with"); } - builder.append(" fade out 20 ticks"); + long ticks = Title.DEFAULT_TIMES.fadeOut().toMillis() / Ticks.SINGLE_TICK_DURATION_MS; + builder.append(" fade out ").append(ticks).append(" ticks"); } return builder.toString(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java index d78897b440b..8c3affb2ab6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/CodeConverter.java @@ -50,6 +50,8 @@ class CodeConverter { CODE_MAP.put('m', "strikethrough"); CODE_MAP.put('n', "underlined"); CODE_MAP.put('k', "obfuscated"); + + CODE_MAP.put('r', "reset"); } @Nullable diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index ca46b795d90..629c78ce6e4 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -18,6 +18,7 @@ */ package org.skriptlang.skript.bukkit.chat.util; +import ch.njol.skript.ServerPlatform; import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.VariableString; @@ -47,6 +48,9 @@ public class ComponentHandler { + private static final boolean CAN_USE_PAPER_INTEGRATION = + Skript.getServerPlatform() == ServerPlatform.BUKKIT_PAPER && Skript.isRunningMinecraft(1, 17); + private static final Map SIMPLE_PLACEHOLDERS = new HashMap<>(); private static final List RESOLVERS = new ArrayList<>(); @@ -158,15 +162,15 @@ public static Component parse(Object message, boolean safe) { } if (realMessage.contains("&") || realMessage.contains("§")) { - System.out.println("CALLED LEGACY PARSING"); - long start = System.nanoTime(); StringBuilder reconstructedMessage = new StringBuilder(); char[] messageChars = realMessage.toCharArray(); int length = messageChars.length; for (int i = 0; i < length; i++) { char current = messageChars[i]; + if (current == '§') + current = '&'; char next = (i + 1 != length) ? messageChars[i + 1] : ' '; - boolean isCode = current == '&' || current == '§'; + boolean isCode = current == '&'; if (isCode && next == 'x') { // Try to parse as hex -> &x&1&2&3&4&5&6 reconstructedMessage.append("<#"); for (int i2 = i + 3; i2 < i + 14; i2 += 2) // Isolate the specific numbers @@ -186,7 +190,6 @@ public static Component parse(Object message, boolean safe) { } } realMessage = reconstructedMessage.toString(); - System.out.println("FINISHED LEGACY PARSING: " + (1. * (System.nanoTime() - start) / 1000000.)); } // Really annoying backwards compatibility check @@ -346,6 +349,8 @@ public static Audience audienceFrom(Collection senders) { * @return An audience consisting of the provided command senders. */ public static Audience audienceFrom(CommandSender... senders) { + if (CAN_USE_PAPER_INTEGRATION) + return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); for (CommandSender sender : senders) bukkitAudiences.add(getAdventure().sender(sender)); From c1fe99cf899b8d52d70c9d6177ce2101ae3d8a56 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Tue, 26 Jul 2022 10:50:14 -0400 Subject: [PATCH 09/11] Get it building --- .../skript/expressions/ExprRawString.java | 34 +++++++++++-------- .../bukkit/chat/util/ComponentHandler.java | 2 ++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprRawString.java b/src/main/java/ch/njol/skript/expressions/ExprRawString.java index 87eca7adf88..f77b4d91a01 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprRawString.java +++ b/src/main/java/ch/njol/skript/expressions/ExprRawString.java @@ -23,7 +23,6 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionList; import ch.njol.skript.lang.ExpressionType; @@ -32,6 +31,7 @@ import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -40,8 +40,10 @@ import java.util.List; @Name("Raw String") -@Description("Returns the string without formatting (colors etc.) and without stripping them from it, " + - "e.g. raw \"&aHello There!\" would output &aHello There!") +@Description( + "Returns the string without formatting (colors etc.) and without stripping them from it, " + + "e.g. raw \"&aHello There!\" would output &aHello There!" +) @Examples("send raw \"&aThis text is unformatted!\" to all players") @Since("INSERT VERSION") public class ExprRawString extends SimpleExpression { @@ -51,21 +53,24 @@ public class ExprRawString extends SimpleExpression { } @SuppressWarnings("NotNullFieldNotInitialized") - private Expression expr; + private Expression messageExpr; @SuppressWarnings("NotNullFieldNotInitialized") private Expression[] messages; @Override @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - expr = (Expression) exprs[0]; - messages = expr instanceof ExpressionList ? - ((ExpressionList) expr).getExpressions() : new Expression[]{expr}; - for (Expression message : messages) { - if (message instanceof ExprColoured) { - Skript.error("The 'colored' expression may not be used in a 'raw string' expression"); - return false; + messageExpr = (Expression) exprs[0]; + messageExpr = LiteralUtils.defendExpression(exprs[0]); + if (messageExpr instanceof ExpressionList) { + ExpressionList exprList = (ExpressionList) messageExpr; + if (exprList.getAnd()) { + messages = exprList.getExpressions(); + } else { + messages = new Expression[]{CollectionUtils.getRandom(exprList.getExpressions())}; } + } else { + messages = new Expression[]{messageExpr}; } return true; } @@ -75,7 +80,7 @@ protected String[] get(Event e) { List strings = new ArrayList<>(); for (Expression message : messages) { if (message instanceof VariableString) { - strings.add(((VariableString) message).toUnformattedString(e)); + strings.add(((VariableString) message).toString(false, e)); continue; } strings.addAll(Arrays.asList(message.getArray(e))); @@ -85,7 +90,7 @@ protected String[] get(Event e) { @Override public boolean isSingle() { - return expr.isSingle(); + return messageExpr.isSingle(); } @Override @@ -95,6 +100,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event e, boolean debug) { - return "raw " + expr.toString(e, debug); + return "raw " + messageExpr.toString(e, debug); } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index 629c78ce6e4..5bd1e915b2d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -332,6 +332,8 @@ public static BukkitAudiences getAdventure() { */ @SuppressWarnings("ConstantConditions") public static Audience audienceFrom(Collection senders) { + if (CAN_USE_PAPER_INTEGRATION) + return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); for (CommandSender sender : senders) { if (sender instanceof Audience) { // On paper, a CommandSender is an Audience From 8700fa43a20e3fbf876d59ed7170de19855b0ff3 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Tue, 26 Jul 2022 11:25:58 -0400 Subject: [PATCH 10/11] Okay get it building for REAL! --- build.gradle | 1 + .../ch/njol/skript/lang/VariableString.java | 2 +- .../skript/bukkit/chat/ChatModule.java | 1 + .../bukkit/chat/util/ComponentHandler.java | 22 ++++++++----------- src/main/resources/lang/default.lang | 4 ++++ 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index a6371d0f76f..58c10896c47 100644 --- a/build.gradle +++ b/build.gradle @@ -77,6 +77,7 @@ tasks.withType(ShadowJar) { ] relocate 'io.papermc.lib', 'ch.njol.skript.paperlib' relocate 'org.bstats', 'ch.njol.skript.bstats' + relocate 'net.kyori', 'org.skriptlang.kyori' manifest { attributes( 'Name': 'ch/njol/skript', diff --git a/src/main/java/ch/njol/skript/lang/VariableString.java b/src/main/java/ch/njol/skript/lang/VariableString.java index 7ec46e7e3bd..1a5fbe5e40f 100644 --- a/src/main/java/ch/njol/skript/lang/VariableString.java +++ b/src/main/java/ch/njol/skript/lang/VariableString.java @@ -370,7 +370,7 @@ public String toString(boolean format, @Nullable Event e) { boolean escape = !(o instanceof ExprColoured) && format; String expression = Classes.toString(((Expression) o).getArray(e), true, mode); if (escape) - ComponentHandler.escape(expression); + expression = ComponentHandler.escape(expression); b.append(expression); } else { b.append(o); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java index 9416bfbe0fe..bae0ec87771 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/ChatModule.java @@ -70,6 +70,7 @@ public String toVariableNameString(Component component) { // Just to initialize it now ComponentHandler.getAdventure(); + // TODO maybe find a better solution idk though ComponentHandler.registerPlaceholder("dark_cyan", ""); ComponentHandler.registerPlaceholder("dark_turquoise", ""); ComponentHandler.registerPlaceholder("cyan", ""); diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index 5bd1e915b2d..a3d07e3f180 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -18,7 +18,6 @@ */ package org.skriptlang.skript.bukkit.chat.util; -import ch.njol.skript.ServerPlatform; import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.VariableString; @@ -48,8 +47,10 @@ public class ComponentHandler { - private static final boolean CAN_USE_PAPER_INTEGRATION = - Skript.getServerPlatform() == ServerPlatform.BUKKIT_PAPER && Skript.isRunningMinecraft(1, 17); + @SuppressWarnings("ConstantConditions") // only true for newer Paper versions + // TODO make sure this sends components using proper methods + // IIRC it doesn't right now - due to shading + private static final boolean COMMAND_SENDER_IS_AUDIENCE = Audience.class.isAssignableFrom(CommandSender.class); private static final Map SIMPLE_PLACEHOLDERS = new HashMap<>(); private static final List RESOLVERS = new ArrayList<>(); @@ -192,6 +193,7 @@ public static Component parse(Object message, boolean safe) { realMessage = reconstructedMessage.toString(); } + // TODO find a better solution // Really annoying backwards compatibility check realMessage = realMessage.replace("", "") .replace("", "") @@ -330,18 +332,12 @@ public static BukkitAudiences getAdventure() { * @param senders The members of this audience. * @return An audience consisting of the provided command senders. */ - @SuppressWarnings("ConstantConditions") public static Audience audienceFrom(Collection senders) { - if (CAN_USE_PAPER_INTEGRATION) + if (COMMAND_SENDER_IS_AUDIENCE) return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); - for (CommandSender sender : senders) { - if (sender instanceof Audience) { // On paper, a CommandSender is an Audience - bukkitAudiences.add(sender); - } else { - bukkitAudiences.add(getAdventure().sender(sender)); - } - } + for (CommandSender sender : senders) + bukkitAudiences.add(getAdventure().sender(sender)); return Audience.audience(bukkitAudiences); } @@ -351,7 +347,7 @@ public static Audience audienceFrom(Collection senders) { * @return An audience consisting of the provided command senders. */ public static Audience audienceFrom(CommandSender... senders) { - if (CAN_USE_PAPER_INTEGRATION) + if (COMMAND_SENDER_IS_AUDIENCE) return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); for (CommandSender sender : senders) diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 2ef13897172..615bc461a96 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -1946,3 +1946,7 @@ types: # Hooks money: money region: region¦s + + # Other API + + component: component¦s @a From 3610f77eed7c37b46900004730194904331ee03b Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Wed, 27 Jul 2022 19:28:55 -0400 Subject: [PATCH 11/11] Remove impossible check The goal here isn't possible of course, as we relocate the dependency. --- .../skript/bukkit/chat/util/ComponentHandler.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java index a3d07e3f180..1ae323b0a34 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java +++ b/src/main/java/org/skriptlang/skript/bukkit/chat/util/ComponentHandler.java @@ -47,11 +47,6 @@ public class ComponentHandler { - @SuppressWarnings("ConstantConditions") // only true for newer Paper versions - // TODO make sure this sends components using proper methods - // IIRC it doesn't right now - due to shading - private static final boolean COMMAND_SENDER_IS_AUDIENCE = Audience.class.isAssignableFrom(CommandSender.class); - private static final Map SIMPLE_PLACEHOLDERS = new HashMap<>(); private static final List RESOLVERS = new ArrayList<>(); @@ -333,8 +328,6 @@ public static BukkitAudiences getAdventure() { * @return An audience consisting of the provided command senders. */ public static Audience audienceFrom(Collection senders) { - if (COMMAND_SENDER_IS_AUDIENCE) - return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); for (CommandSender sender : senders) bukkitAudiences.add(getAdventure().sender(sender)); @@ -347,8 +340,6 @@ public static Audience audienceFrom(Collection senders) { * @return An audience consisting of the provided command senders. */ public static Audience audienceFrom(CommandSender... senders) { - if (COMMAND_SENDER_IS_AUDIENCE) - return Audience.audience(senders); List bukkitAudiences = new ArrayList<>(); for (CommandSender sender : senders) bukkitAudiences.add(getAdventure().sender(sender));