diff --git a/.idea/ButtonChat.iml b/.idea/ButtonChat.iml index 3d32cdf..28193ee 100644 --- a/.idea/ButtonChat.iml +++ b/.idea/ButtonChat.iml @@ -1,12 +1,13 @@ - + + @@ -24,11 +25,19 @@ - - - + + + + + + + + + + + - + @@ -39,5 +48,7 @@ + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 808d9b0..1d962ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ language: java jdk: - oraclejdk8 sudo: true +dist: trusty # Needed for Java 8, although we might not need Java 8 deploy: # deploy develop to the staging environment - provider: script diff --git a/pom.xml b/pom.xml index 5626ea8..987b17c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,11 @@ 4.0.0 + + com.github.TBMCPlugins.ButtonCore + CorePOM + master-SNAPSHOT + 0.0.1-SNAPSHOT The Button Minecraft Chat Plugin The Button Minecraft Chat Plugin @@ -26,18 +31,10 @@ ButtonChat - - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - org.apache.maven.plugins maven-shade-plugin - 2.4.2 + 3.2.1 package @@ -48,7 +45,6 @@ net.sourceforge.htmlcleaner:htmlcleaner - org.javassist:javassist @@ -151,14 +147,14 @@ jitpack https://jitpack.io/ - - Essentials - http://repo.ess3.net/content/repositories/essrel/ - - - Minigames - http://maven.addstar.com.au/artifactory/release - + + ess-repo + https://ci.ender.zone/plugin/repository/everything/ + + @@ -211,18 +209,26 @@ master-SNAPSHOT provided - - org.projectlombok - lombok - 1.16.16 - provided - - - org.spigotmc - spigot - 1.12.2-R0.1-SNAPSHOT - provided - + + + org.projectlombok + lombok + 1.18.10 + provided + + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + com.github.webbukkit Dynmap-Towny @@ -240,7 +246,14 @@ 4.12 test - + + + org.apache.logging.log4j + log4j-core + 2.8.1 + provided + + ButtonChat TBMCPlugins diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java deleted file mode 100644 index 6028b8a..0000000 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ /dev/null @@ -1,333 +0,0 @@ -package buttondevteam.chat; - -import buttondevteam.chat.commands.ucmds.admin.DebugCommand; -import buttondevteam.chat.components.chatonly.ChatOnlyComponent; -import buttondevteam.chat.components.fun.FunComponent; -import buttondevteam.chat.components.towny.TownyComponent; -import buttondevteam.chat.formatting.ChatFormatter; -import buttondevteam.chat.formatting.TellrawEvent; -import buttondevteam.chat.formatting.TellrawPart; -import buttondevteam.chat.formatting.TellrawSerializer; -import buttondevteam.chat.listener.PlayerListener; -import buttondevteam.core.ComponentManager; -import buttondevteam.core.component.channel.Channel; -import buttondevteam.lib.TBMCChatEvent; -import buttondevteam.lib.TBMCChatEventBase; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.Priority; -import buttondevteam.lib.chat.TellrawSerializableEnum; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; -import com.earth2me.essentials.User; -import com.google.common.collect.Lists; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.Sound; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.Objective; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -public class ChatProcessing { - private static final Pattern NULL_MENTION_PATTERN = Pattern.compile("null"); - private static final Pattern CYAN_PATTERN = Pattern.compile("cyan"); - private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\\\"); - private static final Pattern CONSOLE_PING_PATTERN = Pattern.compile("(?i)" + Pattern.quote("@console")); - private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)"); - private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)"); - public static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+"); - private static final Pattern UNDERLINED_PATTERN = Pattern.compile("_"); - private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*"); - private static final Pattern BOLD_PATTERN = Pattern.compile("\\*\\*"); - private static final Pattern CODE_PATTERN = Pattern.compile("`"); - private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)"); - private static final Pattern SOMEONE_PATTERN = Pattern.compile("@someone"); //TODO - private static final Pattern STRIKETHROUGH_PATTERN = Pattern.compile("~~"); - private static final Pattern SPOILER_PATTERN = Pattern.compile("\\|\\|"); - private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, - Color.Blue, Color.DarkPurple}; - private static final Pattern WORD_PATTERN = Pattern.compile("\\S+"); - private static boolean pingedconsole = false; - - public static final ChatFormatter ESCAPE_FORMATTER = ChatFormatter.builder().regex(ESCAPE_PATTERN).build(); - - private static ArrayList commonFormatters = Lists.newArrayList( - ChatFormatter.builder().regex(BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) - .priority(Priority.High).build(), - ChatFormatter.builder().regex(ITALIC_PATTERN).italic(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range).build(), - ChatFormatter.builder().regex(UNDERLINED_PATTERN).underlined(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range) - .build(), - ChatFormatter.builder().regex(STRIKETHROUGH_PATTERN).strikethrough(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) - .build(), - ChatFormatter.builder().regex(SPOILER_PATTERN).obfuscated(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) - .onmatch((match, cf, fs) -> { - cf.setHoverText(match); - return match; - }).build(), - ESCAPE_FORMATTER, ChatFormatter.builder().regex(NULL_MENTION_PATTERN).color(Color.DarkRed).build(), // Properly added a bug as a feature - ChatFormatter.builder().regex(CONSOLE_PING_PATTERN).color(Color.Aqua).onmatch((match, builder, section) -> { - if (!pingedconsole) { - System.out.print("\007"); - pingedconsole = true; // Will set it to false in ProcessChat - } - return match; - }).priority(Priority.High).build(), - - ChatFormatter.builder().regex(HASHTAG_PATTERN).color(Color.Blue).openlink("https://twitter.com/hashtag/$1") - .priority(Priority.High).build(), - ChatFormatter.builder().regex(CYAN_PATTERN).color(Color.Aqua).build(), // #55 - ChatFormatter.builder().regex(CODE_PATTERN).color(Color.DarkGray).removeCharCount((short) 1).type(ChatFormatter.Type.Range) - .build(), - ChatFormatter.builder().regex(MASKED_LINK_PATTERN).underlined(true).onmatch((match, builder, section) -> { - String text, link; - if (section.Matches.size() < 2 || (text = section.Matches.get(0)).length() == 0 || (link = section.Matches.get(1)).length() == 0) - return ""; - builder.setOpenlink(link); - return text; - }).type(ChatFormatter.Type.Excluder).build(), - ChatFormatter.builder().regex(URL_PATTERN).underlined(true).openlink("$1").type(ChatFormatter.Type.Excluder).build()); - private static Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) - .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) - .registerTypeAdapter(Boolean.class, new TellrawSerializer.TwBool()) - .registerTypeAdapter(boolean.class, new TellrawSerializer.TwBool()).disableHtmlEscaping().create(); - private static final String[] testPlayers = {"Koiiev", "iie", "Alisolarflare", "NorbiPeti", "Arsen_Derby_FTW", "carrot_lynx"}; - public static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized - - private ChatProcessing() { - } - - public static boolean ProcessChat(TBMCChatEvent e) { - Channel channel = e.getChannel(); - CommandSender sender = e.getSender(); - String message = e.getMessage(); - long processstart = System.nanoTime(); - Player player = (sender instanceof Player ? (Player) sender : null); - User user = PluginMain.essentials.getUser(player); - - if (player != null) { - user.updateActivity(true); //Could talk in a private channel, so broadcast - if (user.isMuted()) - return true; - } - - doFunStuff(sender, e, message); - - ChatPlayer mp; - if (player != null) - mp = TBMCPlayerBase.getPlayer(player.getUniqueId(), ChatPlayer.class); - else //Due to the online player map, getPlayer() can be more efficient than getAs() - mp = e.getUser().getAs(ChatPlayer.class); //May be null - - Color colormode = channel.Color().get(); - if (mp != null && mp.OtherColorMode != null) - colormode = mp.OtherColorMode; - if (message.startsWith(">")) - colormode = Color.Green; - // If greentext, ignore channel or player colors - - ArrayList formatters = addFormatters(colormode); - if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color - final AtomicInteger rpc = new AtomicInteger(0); - formatters.add(ChatFormatter.builder().regex(WORD_PATTERN).color(colormode).onmatch((match, cf, s) -> { - cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); - return match; - }).build()); - } - pingedconsole = false; // Will set it to true onmatch (static constructor) - final String channelidentifier = getChannelID(channel, e.getOrigin()); - - TellrawPart json = createTellraw(sender, message, player, mp, e.getUser(), channelidentifier, e.getOrigin()); - long combinetime = System.nanoTime(); - ChatFormatter.Combine(formatters, message, json); - combinetime = System.nanoTime() - combinetime; - String jsonstr = toJson(json); - if (jsonstr.length() >= 32767) { - sender.sendMessage( - "§cError: Message too long. Try shortening it, or remove hashtags and other formatting."); - return true; - } - DebugCommand.SendDebugMessage(jsonstr); - - try { - if (!channel.isGlobal()) { - Objective obj = PluginMain.SB.getObjective(channel.ID); - int score = -1; - for (Player p : Bukkit.getOnlinePlayers()) { - final int mcScore; - if (player != null - && PluginMain.essentials.getUser(p).isIgnoredPlayer(PluginMain.essentials.getUser(player))) - mcScore = -1; // Don't send the message to them - else - mcScore = VanillaUtils.getMCScoreIfChatOn(p, e); - obj.getScore(p.getName()) - .setScore(p.getUniqueId().equals(player == null ? null : player.getUniqueId()) // p.UniqueID==player?.UniqueID - ? score = mcScore : mcScore); - } - if (score == -1) // Even if the player object isn't null, it may not be in OnlinePlayers - score = e.getMCScore(sender); - if (score < 0) // Never send messages to score below 0 - sender.sendMessage("§cYou don't have permission to send this message or something went wrong"); - else { - PluginMain.Instance.getServer().dispatchCommand(PluginMain.Console, - String.format("tellraw @a[score_%s=%d,score_%s_min=%d] %s", channel.ID, score, channel.ID, - score, jsonstr)); - val tc = ComponentManager.getIfEnabled(TownyComponent.class); - if (tc != null) tc.handleSpies(channel, json, ChatProcessing::toJson); - } - } else - PluginMain.Instance.getServer().dispatchCommand(PluginMain.Console, - String.format("tellraw @a %s", jsonstr)); - } catch (Exception ex) { - TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex); - sender.sendMessage("§cAn error occured while sending the message."); - return true; - } - PluginMain.Instance.getServer().getConsoleSender() - .sendMessage(String.format("%s <%s§r> %s", channelidentifier, getSenderName(sender, player), message)); - DebugCommand.SendDebugMessage( - "-- Full ChatProcessing time: " + (System.nanoTime() - processstart) / 1000000f + " ms"); - DebugCommand.SendDebugMessage("-- ChatFormatter.Combine time: " + combinetime / 1000000f + " ms"); - return false; - } - - static String toJson(TellrawPart json) { - return gson.toJson(json); - } - - static TellrawPart createTellraw(CommandSender sender, String message, @Nullable Player player, - @Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier, - String origin) { - TellrawPart json = new TellrawPart(""); - ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Make nice API - json.addExtra( - new TellrawPart(channelidentifier) - .setHoverEvent( - TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, - new TellrawPart((MCORIGIN.equals(origin) ? "" : "From " + origin + "n") - + "Copy message").setColor(Color.Blue))) - .setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND, message))); - if (PluginMain.permission.has(sender, "tbmc.badge.diamond")) - json.addExtra(new TellrawPart("[P]").setColor(Color.Aqua).setBold(true) - .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Diamond Patreon supporter"))); - else if (PluginMain.permission.has(sender, "tbmc.badge.gold")) - json.addExtra(new TellrawPart("[P]").setColor(Color.Gold).setBold(true) - .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Gold Patreon supporter"))); - json.addExtra(new TellrawPart(" <")); - TellrawPart hovertp = new TellrawPart(""); - if (cg != null) - hovertp.addExtra(new TellrawPart(cg.getInfo(ChromaGamerBase.InfoTarget.MCHover))); - json.addExtra(new TellrawPart(getSenderName(sender, player)) - .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, hovertp))); - json.addExtra(new TellrawPart("> ")); - return json; - } - - private static String getSenderName(CommandSender sender, Player player) { - if (player == null) - return sender.getName(); - return player.getDisplayName(); - } - - static String getChannelID(Channel channel, String origin) { - return ("[" + (MCORIGIN.equals(origin) ? "" : "§8" + origin.substring(0, 1) + "§r|") + channel.DisplayName().get()) - + "]"; - } - - static ArrayList addFormatters(Color colormode) { - @SuppressWarnings("unchecked") - ArrayList formatters = (ArrayList) commonFormatters.clone(); - - formatters.add( - ChatFormatter.builder().regex(ENTIRE_MESSAGE_PATTERN).color(colormode).priority(Priority.Low).build()); - - boolean nottest; //Not assigning a default value, so that it can only be used in the if - if ((nottest = Bukkit.getOnlinePlayers().size() > 0) || Bukkit.getVersion().equals("test")) { - StringBuilder namesb = new StringBuilder("(?i)("); - if (nottest) - for (Player p : Bukkit.getOnlinePlayers()) - namesb.append(p.getName()).append("|"); - else - for (String testPlayer : testPlayers) - namesb.append(testPlayer).append("|"); - namesb.deleteCharAt(namesb.length() - 1); - namesb.append(")"); - StringBuilder nicksb = new StringBuilder("(?i)("); - boolean addNickFormatter = false; - for (Player p : Bukkit.getOnlinePlayers()) { - final String nick = PlayerListener.nicknames.inverse().get(p.getUniqueId()); - if (nick != null) { - nicksb.append(nick).append("|"); - addNickFormatter = true; //Add it even if there's only 1 player online (it was in the if) - } - } - nicksb.deleteCharAt(nicksb.length() - 1); - nicksb.append(")"); - - Consumer error = message -> { - if (PluginMain.Instance != null) - PluginMain.Instance.getLogger().warning(message); - else - System.out.println(message); - }; - - formatters.add(ChatFormatter.builder().regex(Pattern.compile(namesb.toString())).color(Color.Aqua) - .onmatch((match, builder, section) -> { - Player p = Bukkit.getPlayer(match); - Optional pn = nottest ? Optional.empty() - : Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny(); - if (nottest ? p == null : !pn.isPresent()) { - error.accept("Error: Can't find player " + match + " but was reported as online."); - return "§c" + match + "§r"; - } - ChatPlayer mpp = TBMCPlayer.getPlayer(nottest ? p.getUniqueId() : new UUID(0, 0), ChatPlayer.class); - if (nottest) { - playPingSound(p); - } - String color = String.format("§%x", (mpp.GetFlairColor() == 0x00 ? 0xb : mpp.GetFlairColor())); - return color + (nottest ? p.getName() : pn.get()) + "§r"; //Fix name casing, except when testing - }).priority(Priority.High).type(ChatFormatter.Type.Excluder).build()); - - if (addNickFormatter) - formatters.add(ChatFormatter.builder().regex((Pattern.compile(nicksb.toString()))).color(Color.Aqua) - .onmatch((match, builder, section) -> { - if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased - Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase())); - if (p == null) { - error.accept("Error: Can't find player nicknamed " - + match.toLowerCase() + " but was reported as online."); - return "§c" + match + "§r"; - } - playPingSound(p); - return PluginMain.essentials.getUser(p).getNickname(); - } - error.accept("Player nicknamed " + match.toLowerCase() - + " not found in nickname map but was reported as online."); - return "§c" + match + "§r"; - }).priority(Priority.High).type(ChatFormatter.Type.Excluder).build()); - } - return formatters; - } - - private static void playPingSound(Player p) { - if (PluginMain.Instance.notificationSound().get().length() == 0) - p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f); // TODO: Airhorn - else - p.playSound(p.getLocation(), PluginMain.Instance.notificationSound().get(), 1.0f, - PluginMain.Instance.notificationPitch().get()); - } - - static void doFunStuff(CommandSender sender, TBMCChatEventBase event, String message) { - val fc=ComponentManager.getIfEnabled(FunComponent.class); - if(fc!=null) fc.onChat(sender, event, message); - } -} diff --git a/src/main/java/buttondevteam/chat/ChatUtils.java b/src/main/java/buttondevteam/chat/ChatUtils.java new file mode 100644 index 0000000..9a3b15e --- /dev/null +++ b/src/main/java/buttondevteam/chat/ChatUtils.java @@ -0,0 +1,59 @@ +package buttondevteam.chat; + +import buttondevteam.lib.ChromaUtils; +import buttondevteam.lib.TBMCChatEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.function.Function; + +public final class ChatUtils { + public static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized + + private ChatUtils() { + } + + /** + * Dispatch a console command. + * + * @param command The command + * @param async Whether the caller is async + */ + public static void dispatchConsoleCommand(String command, boolean async) { + if (async) + Bukkit.getScheduler().runTask(PluginMain.Instance, () -> Bukkit.dispatchCommand(PluginMain.Console, command)); + else + Bukkit.dispatchCommand(PluginMain.Console, command); + } + + /** + * Returns the string between the start and end strings (exclusive). + * + * @param str The original string + * @param start The start string + * @param end The end string + * @return The result string + */ + public static Optional coolSubstring(String str, String start, String end) { + int a = str.indexOf(start) + start.length(); + int b = str.indexOf(end, a); + return a != -1 && b != -1 ? Optional.of(str.substring(a, b)) : Optional.empty(); + } + + /** + * Sends a regular (non-Markdown) chat message. Used as a fallback if the chat processing fails. + * + * @param e The chat event + * @param modifier A function that alters the message to be displayed to the player + */ + public static void sendChatMessage(TBMCChatEvent e, Function modifier) { + var str = "[" + e.getChannel().DisplayName().get() + "] <" + + ChromaUtils.getDisplayName(e.getSender()) + "> " + e.getMessage(); + str = modifier.apply(str); + for (Player p : Bukkit.getOnlinePlayers()) + if (e.shouldSendTo(p)) + p.sendMessage(str); + Bukkit.getConsoleSender().sendMessage(str); + } +} diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index ba05c44..b6095a1 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -5,10 +5,12 @@ import buttondevteam.chat.commands.SnapCommand; import buttondevteam.chat.commands.ucmds.HelpCommand; import buttondevteam.chat.commands.ucmds.HistoryCommand; import buttondevteam.chat.commands.ucmds.InfoCommand; +import buttondevteam.chat.commands.ucmds.ReloadCommand; import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.chat.components.announce.AnnouncerComponent; import buttondevteam.chat.components.appendext.AppendTextComponent; import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.formatter.FormatterComponent; import buttondevteam.chat.components.fun.FunComponent; import buttondevteam.chat.components.towncolors.TownColorComponent; import buttondevteam.chat.components.towny.TownyComponent; @@ -28,7 +30,6 @@ import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.scoreboard.Scoreboard; public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15. // A user, which flair isn't obtainable: @@ -36,8 +37,6 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15 public static PluginMain Instance; public static ConsoleCommandSender Console; - public static Scoreboard SB; - public ConfigData notificationSound() { return getIConfig().getData("notificationSound", ""); } @@ -54,11 +53,8 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15 TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerJoinLeaveListener(), this); - MainPlugin.Instance.setChatHandlerEnabled(false); //Disable Core chat handler Console = this.getServer().getConsoleSender(); - SB = getServer().getScoreboardManager().getMainScoreboard(); // Main can be detected with @a[score_...] - if (Bukkit.getPluginManager().isPluginEnabled("Towny")) Component.registerComponent(this, new TownyComponent()); @@ -73,11 +69,13 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15 Component.registerComponent(this, new AnnouncerComponent()); Component.registerComponent(this, new FunComponent()); Component.registerComponent(this, new AppendTextComponent()); + Component.registerComponent(this, new FormatterComponent()); getCommand2MC().registerCommand(new DebugCommand()); getCommand2MC().registerCommand(new HelpCommand()); getCommand2MC().registerCommand(new HistoryCommand()); getCommand2MC().registerCommand(new InfoCommand()); getCommand2MC().registerCommand(new MWikiCommand()); + getCommand2MC().registerCommand(new ReloadCommand()); getCommand2MC().registerCommand(new SnapCommand()); } diff --git a/src/main/java/buttondevteam/chat/VanillaUtils.java b/src/main/java/buttondevteam/chat/VanillaUtils.java index 68f749b..fbbdbf3 100644 --- a/src/main/java/buttondevteam/chat/VanillaUtils.java +++ b/src/main/java/buttondevteam/chat/VanillaUtils.java @@ -1,18 +1,122 @@ package buttondevteam.chat; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; - +import buttondevteam.core.MainPlugin; import buttondevteam.lib.TBMCChatEvent; import lombok.experimental.UtilityClass; -import net.minecraft.server.v1_12_R1.EntityHuman.EnumChatVisibility; +import lombok.val; +import org.bukkit.entity.Player; + +import java.util.function.BiPredicate; +import java.util.function.Predicate; @UtilityClass public class VanillaUtils { - public int getMCScoreIfChatOn(Player p, TBMCChatEvent e) { - if (!(p instanceof CraftPlayer) || ((CraftPlayer) p).getHandle().getChatFlags() == EnumChatVisibility.FULL) // Only send if client allows chat - return e.getMCScore(p); - else - return -1; + public String getGroupIfChatOn(Player p, TBMCChatEvent e) { + try { + if (isChatOn(p)) // Only send if client allows chat + return e.getGroupID(p); + else + return null; + } catch (NoClassDefFoundError ex) { + MainPlugin.Instance.getLogger().warning("Compatibility error, can't check if the chat is hidden by the player."); + return e.getGroupID(p); + } + } + + private Predicate isChatOn; + + private boolean isChatOn(Player p) { + try { + if (isChatOn == null) { + val cl = p.getClass(); + if (notCraftPlayer(cl)) return true; // p instanceof CraftPlayer + val hm = cl.getMethod("getHandle"); + val handle = hm.invoke(p); //p.getHandle() + val vpcl = handle.getClass(); + val gcfm = vpcl.getMethod("getChatFlags"); + Class encl; + try { + encl = Class.forName(handle.getClass().getPackage().getName() + ".EnumChatVisibility"); + } catch (ClassNotFoundException e) { + encl = Class.forName(handle.getClass().getPackage().getName() + ".EntityHuman$EnumChatVisibility"); + } + val ff = encl.getField("FULL"); + val full = ff.get(null); // EnumChatVisibility.FULL + isChatOn = pl -> { + try { + if (notCraftPlayer(pl.getClass())) return true; //Need to check each time + val ph = hm.invoke(pl); //pl.getHandle() + val flags = gcfm.invoke(ph); //handle.getChatFlags() + return flags == full; + } catch (Exception e) { + e.printStackTrace(); + return true; + } + }; + } + return isChatOn.test(p); + } catch (Exception e) { + e.printStackTrace(); + return true; + } + } + + /*private String version; + + public short getMCVersion() { + if (version != null) return version; + val v = ChatUtils.coolSubstring(Bukkit.getServer().getVersion().getClass().getPackage().getName(), + "org.bukkit.craftbukkit.v", "_R1").orElse("1_8").replace("_", ""); + return Short.parseShort(v); + }*/ + + private BiPredicate tellRaw; + + public boolean tellRaw(Player p, String json) { + try { + if (tellRaw == null) { + val pcl = p.getClass(); + if (notCraftPlayer(pcl)) return false; + val hm = pcl.getMethod("getHandle"); + val handle = hm.invoke(p); + val nms = handle.getClass().getPackage().getName(); + val chatcompcl = Class.forName(nms + ".IChatBaseComponent"); + val sendmsg = handle.getClass().getMethod("sendMessage", chatcompcl); + + /*val ccucl = Class.forName(nms + ".ChatComponentUtils"); + val iclcl = Class.forName(nms + ".ICommandListener"); + val encl = Class.forName(nms + ".Entity"); + val ffdm = ccucl.getMethod("filterForDisplay", iclcl, chatcompcl, encl);*/ + + val cscl = Class.forName(chatcompcl.getName() + "$ChatSerializer"); + val am = cscl.getMethod("a", String.class); + + tellRaw = (pl, jsonStr) -> { + if (notCraftPlayer(pl.getClass())) return false; + try { + val hhandle = hm.invoke(pl); + val deserialized = am.invoke(null, jsonStr); + //val filtered = ffdm.invoke(null, hhandle, deserialized, hhandle); + sendmsg.invoke(hhandle, deserialized); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + }; + } + + /*((CraftPlayer) p).getHandle().sendMessage(ChatComponentUtils + .filterForDisplay(((CraftPlayer) p).getHandle(), + IChatBaseComponent.ChatSerializer.a(json), ((CraftPlayer) p).getHandle()));*/ + return tellRaw.test(p, json); + } catch (Exception e) { + PluginMain.Instance.getLogger().warning("Could not use tellRaw: " + e.getMessage()); + return false; + } + } + + private boolean notCraftPlayer(Class cl) { + return !cl.getSimpleName().contains("CraftPlayer"); } } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/HelpCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/HelpCommand.java index 67d88c5..b7c10fa 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/HelpCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/HelpCommand.java @@ -19,7 +19,7 @@ public final class HelpCommand extends UCommandBase { public boolean def(CommandSender sender, @Command2.TextArg @Command2.OptionalArg String topicOrCommand) { if (topicOrCommand == null) { sender.sendMessage(new String[]{ - "§6---- Thorpe Help ----", + "§6---- Chroma Help ----", "Do /u help for more info", "Do /u help [subcommands] for more info about a command", "Topics:", diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java index fde4953..476ab03 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java @@ -5,7 +5,6 @@ import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import lombok.RequiredArgsConstructor; -import lombok.experimental.var; import lombok.val; import org.bukkit.command.CommandSender; diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/ReloadCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/ReloadCommand.java new file mode 100644 index 0000000..2a49259 --- /dev/null +++ b/src/main/java/buttondevteam/chat/commands/ucmds/ReloadCommand.java @@ -0,0 +1,20 @@ +package buttondevteam.chat.commands.ucmds; + +import buttondevteam.chat.PluginMain; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; +import org.bukkit.command.CommandSender; + +@CommandClass(helpText = { + "Reload", + "Reloads the config" +}, modOnly = true) +public class ReloadCommand extends UCommandBase { + @Command2.Subcommand + public void def(CommandSender sender) { + if (PluginMain.Instance.tryReloadConfig()) + sender.sendMessage("§bReloaded config"); + else + sender.sendMessage("§cFailed to reload config."); + } +} diff --git a/src/main/java/buttondevteam/chat/components/announce/AnnounceCommand.java b/src/main/java/buttondevteam/chat/components/announce/AnnounceCommand.java index 050687d..d6864d1 100644 --- a/src/main/java/buttondevteam/chat/components/announce/AnnounceCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/AnnounceCommand.java @@ -20,7 +20,7 @@ public class AnnounceCommand extends UCommandBase { }) public boolean add(CommandSender sender, @Command2.TextArg String text) { String finalmessage = text.replace('&', '§'); - component.AnnounceMessages().get().add(finalmessage); + component.announceMessages().get().add(finalmessage); sender.sendMessage("§bAnnouncement added.§r"); return true; } @@ -34,9 +34,9 @@ public class AnnounceCommand extends UCommandBase { String finalmessage1 = text.replace('&', '§'); if (index > 100) return false; - while (component.AnnounceMessages().get().size() <= index) - component.AnnounceMessages().get().add(""); - component.AnnounceMessages().get().set(index, finalmessage1); + while (component.announceMessages().get().size() <= index) + component.announceMessages().get().add(""); + component.announceMessages().get().set(index, finalmessage1); sender.sendMessage("Announcement edited."); return true; } @@ -49,10 +49,10 @@ public class AnnounceCommand extends UCommandBase { sender.sendMessage("§bList of announce messages:§r"); sender.sendMessage("§bFormat: [index] message§r"); int i = 0; - for (String message : component.AnnounceMessages().get()) + for (String message : component.announceMessages().get()) sender.sendMessage("[" + i++ + "] " + message); sender.sendMessage("§bCurrent wait time between announcements: " - + component.AnnounceTime().get() / 60 / 1000 + " minute(s)§r"); + + component.announceTime().get() / 60 / 1000 + " minute(s)§r"); return true; } @@ -61,7 +61,7 @@ public class AnnounceCommand extends UCommandBase { "This command removes an announcement" }) public boolean remove(CommandSender sender, int index) { - val msgs = component.AnnounceMessages().get(); + val msgs = component.announceMessages().get(); if (index < 0 || index > msgs.size()) return false; msgs.remove(index); sender.sendMessage("Announcement removed."); @@ -73,7 +73,7 @@ public class AnnounceCommand extends UCommandBase { "This command sets the time between the announcements" }) public boolean settime(CommandSender sender, int minutes) { - component.AnnounceTime().set(minutes * 60 * 1000); + component.announceTime().set(minutes * 60 * 1000); sender.sendMessage("Time set between announce messages to " + minutes + " minutes"); return true; } diff --git a/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java b/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java index cecc285..1d41d62 100644 --- a/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java +++ b/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java @@ -11,11 +11,11 @@ import org.bukkit.Bukkit; import java.util.ArrayList; public class AnnouncerComponent extends Component implements Runnable { - public ConfigData> AnnounceMessages() { + public ConfigData> announceMessages() { return getConfig().getData("announceMessages", new ArrayList<>(0)); } - public ConfigData AnnounceTime() { + public ConfigData announceTime() { return getConfig().getData("announceTime", 15 * 60 * 1000); } @@ -27,15 +27,15 @@ public class AnnouncerComponent extends Component implements Runnabl public void run() { while (isEnabled()) { try { - Thread.sleep(AnnounceTime().get()); + Thread.sleep(announceTime().get()); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } if (Bukkit.getOnlinePlayers().size() == 0) continue; //Don't post to Discord if nobody is on - if (AnnounceMessages().get().size() > AnnounceMessageIndex) { - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, AnnounceMessages().get().get(AnnounceMessageIndex), target); + if (announceMessages().get().size() > AnnounceMessageIndex) { + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, announceMessages().get().get(AnnounceMessageIndex), target); AnnounceMessageIndex++; - if (AnnounceMessageIndex == AnnounceMessages().get().size()) + if (AnnounceMessageIndex == announceMessages().get().size()) AnnounceMessageIndex = 0; } } diff --git a/src/main/java/buttondevteam/chat/components/chatonly/ChatOnlyComponent.java b/src/main/java/buttondevteam/chat/components/chatonly/ChatOnlyComponent.java index 7f17848..5f012dd 100644 --- a/src/main/java/buttondevteam/chat/components/chatonly/ChatOnlyComponent.java +++ b/src/main/java/buttondevteam/chat/components/chatonly/ChatOnlyComponent.java @@ -1,8 +1,8 @@ package buttondevteam.chat.components.chatonly; import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.formatting.TellrawEvent; -import buttondevteam.chat.formatting.TellrawPart; +import buttondevteam.chat.components.formatter.formatting.TellrawEvent; +import buttondevteam.chat.components.formatter.formatting.TellrawPart; import buttondevteam.core.ComponentManager; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.player.TBMCPlayer; diff --git a/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java b/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java index 8ebd6ed..1c47167 100644 --- a/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java +++ b/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java @@ -39,7 +39,7 @@ public class AcceptCommand extends UCommandBase { } if (p.FlairState().get().equals(FlairStates.NoComment) || p.UserNames().size() == 0) { player.sendMessage("§cError: You need to write your username to the reddit thread§r"); - player.sendMessage(component.FlairThreadURL().get()); + player.sendMessage(component.flairThreadURL().get()); return true; } if (username != null && !p.UserNames().contains(username)) { diff --git a/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java b/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java index a5f4878..7c8440a 100644 --- a/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java +++ b/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java @@ -23,7 +23,7 @@ import java.text.SimpleDateFormat; import java.util.*; public class FlairComponent extends Component { - ConfigData FlairThreadURL() { + ConfigData flairThreadURL() { return getConfig().getData("flairThreadURL", "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"); } @@ -54,7 +54,7 @@ public class FlairComponent extends Component { int errorcount = 0; while (isEnabled()) { try { - String body = TBMCCoreAPI.DownloadString(FlairThreadURL().get() + ".json?limit=1000"); + String body = TBMCCoreAPI.DownloadString(flairThreadURL().get() + ".json?limit=1000"); JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data") .getAsJsonObject().get("children").getAsJsonArray(); for (Object obj : json) { diff --git a/src/main/java/buttondevteam/chat/components/formatter/ChatProcessing.java b/src/main/java/buttondevteam/chat/components/formatter/ChatProcessing.java new file mode 100644 index 0000000..e94372c --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/formatter/ChatProcessing.java @@ -0,0 +1,348 @@ +package buttondevteam.chat.components.formatter; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.ChatUtils; +import buttondevteam.chat.PluginMain; +import buttondevteam.chat.VanillaUtils; +import buttondevteam.chat.commands.ucmds.admin.DebugCommand; +import buttondevteam.chat.components.chatonly.ChatOnlyComponent; +import buttondevteam.chat.components.formatter.formatting.ChatFormatter; +import buttondevteam.chat.components.formatter.formatting.TellrawEvent; +import buttondevteam.chat.components.formatter.formatting.TellrawPart; +import buttondevteam.chat.components.formatter.formatting.TellrawSerializer; +import buttondevteam.chat.components.fun.FunComponent; +import buttondevteam.chat.components.towny.TownyComponent; +import buttondevteam.chat.listener.PlayerListener; +import buttondevteam.core.ComponentManager; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.lib.TBMCChatEvent; +import buttondevteam.lib.TBMCChatEventBase; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.Color; +import buttondevteam.lib.chat.Priority; +import buttondevteam.lib.chat.TellrawSerializableEnum; +import buttondevteam.lib.player.ChromaGamerBase; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerBase; +import com.earth2me.essentials.User; +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public class ChatProcessing { + private static final Pattern NULL_MENTION_PATTERN = Pattern.compile("null"); + private static final Pattern CYAN_PATTERN = Pattern.compile("cyan"); + private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\\\"); + private static final Pattern CONSOLE_PING_PATTERN = Pattern.compile("(?i)" + Pattern.quote("@console")); + private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)"); + private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)"); + public static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+"); + private static final Pattern UNDERLINED_PATTERN = Pattern.compile("_"); + private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*"); + private static final Pattern BOLD_PATTERN = Pattern.compile("\\*\\*"); + private static final Pattern CODE_PATTERN = Pattern.compile("`"); + private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)"); + private static final Pattern SOMEONE_PATTERN = Pattern.compile("@someone"); //TODO + private static final Pattern STRIKETHROUGH_PATTERN = Pattern.compile("~~"); + private static final Pattern SPOILER_PATTERN = Pattern.compile("\\|\\|"); + private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, + Color.Blue, Color.DarkPurple}; + private static final Pattern WORD_PATTERN = Pattern.compile("\\S+"); + private static boolean pingedconsole = false; + + public static final ChatFormatter ESCAPE_FORMATTER = ChatFormatter.builder("escape", ESCAPE_PATTERN).build(); + + private static ArrayList commonFormatters = Lists.newArrayList( + ChatFormatter.builder("bold", BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) + .priority(Priority.High).build(), + ChatFormatter.builder("italic", ITALIC_PATTERN).italic(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range).build(), + ChatFormatter.builder("underlined", UNDERLINED_PATTERN).underlined(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range) + .build(), + ChatFormatter.builder("strikethrough", STRIKETHROUGH_PATTERN).strikethrough(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) + .build(), + ChatFormatter.builder("spoiler", SPOILER_PATTERN).obfuscated(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) + .onmatch((match, cf, fs) -> { + cf.setHoverText(match); + return match; + }).build(), + ESCAPE_FORMATTER, ChatFormatter.builder("nullMention", NULL_MENTION_PATTERN).color(Color.DarkRed).build(), // Properly added a bug as a feature + ChatFormatter.builder("consolePing", CONSOLE_PING_PATTERN).color(Color.Aqua).onmatch((match, builder, section) -> { + if (!pingedconsole) { + System.out.print("\007"); + pingedconsole = true; // Will set it to false in ProcessChat + } + return match; + }).priority(Priority.High).build(), + + ChatFormatter.builder("hashtag", HASHTAG_PATTERN).color(Color.Blue).openlink("https://twitter.com/hashtag/$1") + .priority(Priority.High).build(), + ChatFormatter.builder("cyan", CYAN_PATTERN).color(Color.Aqua).build(), // #55 + ChatFormatter.builder("code", CODE_PATTERN).color(Color.DarkGray).removeCharCount((short) 1).type(ChatFormatter.Type.Range) + .build(), + ChatFormatter.builder("maskedLink", MASKED_LINK_PATTERN).underlined(true).onmatch((match, builder, section) -> { + String text, link; + if (section.Matches.size() < 2 || (text = section.Matches.get(0)).length() == 0 || (link = section.Matches.get(1)).length() == 0) + return ""; + builder.setOpenlink(link); + return text; + }).type(ChatFormatter.Type.Excluder).build(), + ChatFormatter.builder("url", URL_PATTERN).underlined(true).openlink("$1").type(ChatFormatter.Type.Excluder).build()); + private static Gson gson = new GsonBuilder() + .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) + .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) + .registerTypeAdapter(Boolean.class, new TellrawSerializer.TwBool()) + .registerTypeAdapter(boolean.class, new TellrawSerializer.TwBool()).disableHtmlEscaping().create(); + private static final String[] testPlayers = {"Koiiev", "iie", "Alisolarflare", "NorbiPeti", "Arsen_Derby_FTW", "carrot_lynx"}; + + private ChatProcessing() { + } + + public static boolean ProcessChat(TBMCChatEvent e, FormatterComponent component) { + Channel channel = e.getChannel(); + CommandSender sender = e.getSender(); + String message = e.getMessage(); + long processstart = System.nanoTime(); + Player player = (sender instanceof Player ? (Player) sender : null); + User user = PluginMain.essentials.getUser(player); + + if (player != null) { + user.updateActivity(true); //Could talk in a private channel, so broadcast + if (user.isMuted()) + return true; + } + + doFunStuff(sender, e, message); + + final String channelidentifier = getChannelID(channel, e.getOrigin()); + PluginMain.Instance.getServer().getConsoleSender() + .sendMessage(String.format("%s <%s§r> %s", channelidentifier, getSenderName(sender, player), message)); + + if (Bukkit.getOnlinePlayers().size() == 0) return false; //Don't try to send to nobody (errors on 1.14) + + ChatPlayer mp; + if (player != null) + mp = TBMCPlayerBase.getPlayer(player.getUniqueId(), ChatPlayer.class); + else //Due to the online player map, getPlayer() can be more efficient than getAs() + mp = e.getUser().getAs(ChatPlayer.class); //May be null + + Color colormode = channel.Color().get(); + if (mp != null && mp.OtherColorMode != null) + colormode = mp.OtherColorMode; + if (message.startsWith(">")) + colormode = Color.Green; + // If greentext, ignore channel or player colors + + ArrayList formatters; + if (component.allowFormatting().get()) { + formatters = addFormatters(colormode, e::shouldSendTo); + if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color + final AtomicInteger rpc = new AtomicInteger(0); + formatters.add(ChatFormatter.builder("word", WORD_PATTERN).color(colormode).onmatch((match, cf, s) -> { + cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); + return match; + }).build()); + } + pingedconsole = false; // Will set it to true onmatch (static constructor) + } else + formatters = Lists.newArrayList(ChatFormatter.builder("entireMessage", ENTIRE_MESSAGE_PATTERN) + .color(Color.White).priority(Priority.Low).build()); //This formatter is necessary + + TellrawPart json = createTellraw(sender, message, player, mp, e.getUser(), channelidentifier, e.getOrigin()); + long combinetime = System.nanoTime(); + ChatFormatter.Combine(formatters, message, json, component.getConfig()); + combinetime = System.nanoTime() - combinetime; + String jsonstr = toJson(json); + if (jsonstr.length() >= 32767) { + sender.sendMessage( + "§cError: Message too long. Try shortening it, or remove hashtags and other formatting."); + return true; + } + DebugCommand.SendDebugMessage(jsonstr); + + try { + if (!channel.isGlobal()) { + String senderGroup = e.getGroupID(sender); + if (senderGroup == null) { // Never send messages if the group is null + sender.sendMessage("§cYou don't have permission to send this message or something went wrong"); + return true; + } + val tc = ComponentManager.getIfEnabled(TownyComponent.class); + if (tc != null) tc.handleSpiesInit(channel, json, ChatProcessing::toJson); + for (Player p : Bukkit.getOnlinePlayers()) { + final String group; + if (player != null + && PluginMain.essentials.getUser(p).isIgnoredPlayer(PluginMain.essentials.getUser(player))) + group = null; // Don't send the message to them + else + group = VanillaUtils.getGroupIfChatOn(p, e); + if (senderGroup.equals(group)) + VanillaUtils.tellRaw(p, jsonstr); + else if (tc != null) tc.handleSpies(channel, p); + //Only sends if didn't send normally + } + } else + for (Player p : Bukkit.getOnlinePlayers()) + VanillaUtils.tellRaw(p, jsonstr); + } catch (Exception ex) { + TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex); + sender.sendMessage("§cAn error occured while sending the message."); + return true; + } + DebugCommand.SendDebugMessage( + "-- Full ChatProcessing time: " + (System.nanoTime() - processstart) / 1000000f + " ms"); + DebugCommand.SendDebugMessage("-- ChatFormatter.Combine time: " + combinetime / 1000000f + " ms"); + return false; + } + + static String toJson(TellrawPart json) { + return gson.toJson(json); + } + + static TellrawPart createTellraw(CommandSender sender, String message, @Nullable Player player, + @Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier, + String origin) { + TellrawPart json = new TellrawPart(""); + ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Make nice API + json.addExtra( + new TellrawPart(channelidentifier) + .setHoverEvent( + TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, + new TellrawPart((ChatUtils.MCORIGIN.equals(origin) ? "" : "From " + origin + "n") + + "Copy message").setColor(Color.Blue))) + .setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND, message))); + if (PluginMain.permission.has(sender, "tbmc.badge.diamond")) + json.addExtra(new TellrawPart("[P]").setColor(Color.Aqua).setBold(true) + .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Diamond Patreon supporter"))); + else if (PluginMain.permission.has(sender, "tbmc.badge.gold")) + json.addExtra(new TellrawPart("[P]").setColor(Color.Gold).setBold(true) + .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Gold Patreon supporter"))); + json.addExtra(new TellrawPart(" <")); + TellrawPart hovertp = new TellrawPart(""); + if (cg != null) + hovertp.addExtra(new TellrawPart(cg.getInfo(ChromaGamerBase.InfoTarget.MCHover))); + json.addExtra(new TellrawPart(getSenderName(sender, player)) + .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, hovertp))); + json.addExtra(new TellrawPart("> ")); + return json; + } + + private static String getSenderName(CommandSender sender, Player player) { + if (player == null) + return sender.getName(); + return player.getDisplayName(); + } + + static String getChannelID(Channel channel, String origin) { + return ("[" + (ChatUtils.MCORIGIN.equals(origin) ? "" : "§8" + origin.substring(0, 1) + "§r|") + channel.DisplayName().get()) + + "]"; + } + + static ArrayList addFormatters(Color colormode, Predicate canSee) { + @SuppressWarnings("unchecked") + ArrayList formatters = (ArrayList) commonFormatters.clone(); + + formatters.add( + ChatFormatter.builder("entireMessage", ENTIRE_MESSAGE_PATTERN).color(colormode).priority(Priority.Low).build()); + + boolean nottest; //Not assigning a default value, so that it can only be used in the if + if ((nottest = Bukkit.getOnlinePlayers().size() > 0) || Bukkit.getVersion().equals("test")) { + StringBuilder namesb = new StringBuilder("(?i)("); + boolean addNameFormatter = false; //Needed because some names may be filtered out if they can't see the channel + if (nottest) + for (Player p : Bukkit.getOnlinePlayers()) { + if (canSee.test(p)) { + namesb.append(p.getName()).append("|"); + addNameFormatter = true; + } + } + else { + for (String testPlayer : testPlayers) + namesb.append(testPlayer).append("|"); + addNameFormatter = true; + } + namesb.deleteCharAt(namesb.length() - 1); + namesb.append(")"); + StringBuilder nicksb = new StringBuilder("(?i)("); + boolean addNickFormatter = false; + for (Player p : Bukkit.getOnlinePlayers()) { + if (!canSee.test(p)) continue; + final String nick = PlayerListener.nicknames.inverse().get(p.getUniqueId()); + if (nick != null) { + nicksb.append(nick).append("|"); + addNickFormatter = true; + } + } + nicksb.deleteCharAt(nicksb.length() - 1); + nicksb.append(")"); + + Consumer error = message -> { + if (PluginMain.Instance != null) + PluginMain.Instance.getLogger().warning(message); + else + System.out.println(message); + }; + + if (addNameFormatter) + formatters.add(ChatFormatter.builder("name", Pattern.compile(namesb.toString())).color(Color.Aqua) + .onmatch((match, builder, section) -> { + Player p = Bukkit.getPlayer(match); + Optional pn = nottest ? Optional.empty() + : Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny(); + if (nottest ? p == null : !pn.isPresent()) { + error.accept("Error: Can't find player " + match + " but was reported as online."); + return "§c" + match + "§r"; + } + ChatPlayer mpp = TBMCPlayer.getPlayer(nottest ? p.getUniqueId() : new UUID(0, 0), ChatPlayer.class); + if (nottest) { + playPingSound(p); + } + String color = String.format("§%x", (mpp.GetFlairColor() == 0x00 ? 0xb : mpp.GetFlairColor())); + return color + (nottest ? p.getName() : pn.get()) + "§r"; //Fix name casing, except when testing + }).priority(Priority.High).type(ChatFormatter.Type.Excluder).build()); + + if (addNickFormatter) + formatters.add(ChatFormatter.builder("nickname", Pattern.compile(nicksb.toString())).color(Color.Aqua) + .onmatch((match, builder, section) -> { + if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased + Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase())); + if (p == null) { + error.accept("Error: Can't find player nicknamed " + + match.toLowerCase() + " but was reported as online."); + return "§c" + match + "§r"; + } + playPingSound(p); + return PluginMain.essentials.getUser(p).getNickname(); + } + error.accept("Player nicknamed " + match.toLowerCase() + + " not found in nickname map but was reported as online."); + return "§c" + match + "§r"; + }).priority(Priority.High).type(ChatFormatter.Type.Excluder).build()); + } + return formatters; + } + + private static void playPingSound(Player p) { + if (PluginMain.Instance.notificationSound().get().length() == 0) + p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f); // TODO: Airhorn + else + p.playSound(p.getLocation(), PluginMain.Instance.notificationSound().get(), 1.0f, + PluginMain.Instance.notificationPitch().get()); + } + + static void doFunStuff(CommandSender sender, TBMCChatEventBase event, String message) { + val fc = ComponentManager.getIfEnabled(FunComponent.class); + if (fc != null) fc.onChat(sender, event, message); + } +} diff --git a/src/main/java/buttondevteam/chat/components/formatter/FormatterComponent.java b/src/main/java/buttondevteam/chat/components/formatter/FormatterComponent.java new file mode 100644 index 0000000..6789b0d --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/formatter/FormatterComponent.java @@ -0,0 +1,40 @@ +package buttondevteam.chat.components.formatter; + +import buttondevteam.chat.PluginMain; +import buttondevteam.core.ComponentManager; +import buttondevteam.core.MainPlugin; +import buttondevteam.lib.TBMCChatEvent; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; + +/** + * This component handles the custom processing of chat messages. If this component is disabled channels won't be supported either in Minecraft. + * If you only want to disable the formatting features, set allowFormatting to false. + */ +public class FormatterComponent extends Component { + ConfigData allowFormatting() { + return getConfig().getData("allowFormatting", true); + } + + @Override + protected void enable() { + MainPlugin.Instance.setChatHandlerEnabled(false); //Disable Core chat handler - if this component is disabled then let it do it's job + } + + @Override + protected void disable() { + MainPlugin.Instance.setChatHandlerEnabled(true); + } + + /** + * Handles the chat if the component is enabled. + * + * @param event The chat event + * @return Whether the chat message shouldn't be sent for some reason + */ + public static boolean handleChat(TBMCChatEvent event) { + FormatterComponent component = ComponentManager.getIfEnabled(FormatterComponent.class); + if (component == null) return false; + return ChatProcessing.ProcessChat(event, component); + } +} diff --git a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java b/src/main/java/buttondevteam/chat/components/formatter/formatting/ChatFormatter.java similarity index 50% rename from src/main/java/buttondevteam/chat/formatting/ChatFormatter.java rename to src/main/java/buttondevteam/chat/components/formatter/formatting/ChatFormatter.java index aa7eb96..e39eef5 100644 --- a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java +++ b/src/main/java/buttondevteam/chat/components/formatter/formatting/ChatFormatter.java @@ -1,7 +1,9 @@ -package buttondevteam.chat.formatting; +package buttondevteam.chat.components.formatter.formatting; -import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.commands.ucmds.admin.DebugCommand; +import buttondevteam.chat.components.formatter.ChatProcessing; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Priority; import lombok.Builder; @@ -15,13 +17,13 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; /** - * A {@link ChatFormatter} shows what formatting to use based on regular expressions. {@link ChatFormatter#Combine(List, String, TellrawPart)} is used to turn it into a {@link TellrawPart}, combining + * A {@link ChatFormatter} shows what formatting to use based on regular expressions. {@link ChatFormatter#Combine(List, String, TellrawPart, IHaveConfig)} is used to turn it into a {@link TellrawPart}, combining * intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined and italics part, finally an underlined part * again. - * - * @author NorbiPeti * + * @author NorbiPeti */ +@SuppressWarnings("UnusedAssignment") @Data @Builder public final class ChatFormatter { @@ -39,118 +41,120 @@ public final class ChatFormatter { @Builder.Default short removeCharCount = 0; @Builder.Default - Type type = Type.Normal; + Type type = Type.Normal; String hoverText; + String name; + + public static ChatFormatterBuilder builder(String name, Pattern regex) { + return builder().regex(regex).name(name); + } + + private static ChatFormatterBuilder builder() { + return new ChatFormatterBuilder(); + } + + private ConfigData enabled(IHaveConfig config) { + return config.getData(name + ".enabled", true); + } public enum Type { - Normal, - /** - * Matches a start and an end section which gets converted to one section (for example see italics) - */ - Range, - /** - * Exclude matching area from further processing (besides this formatter) - */ - Excluder - } + Normal, + /** + * Matches a start and an end section which gets converted to one section (for example see italics) + */ + Range, + /** + * Exclude matching area from further processing (besides this formatter) + */ + Excluder + } @FunctionalInterface public interface TriFunc { R apply(T1 x1, T2 x2, T3 x3); } - public static void Combine(List formatters, String str, TellrawPart tp) { + public static void Combine(List formatters, String str, TellrawPart tp, IHaveConfig config) { /* * This method assumes that there is always a global formatter - */ - header("ChatFormatter.Combine begin"); - ArrayList sections = new ArrayList(); + */ + header("ChatFormatter.Combine begin"); + ArrayList sections = new ArrayList<>(); - for (ChatFormatter formatter : formatters) { - if (formatter.type != Type.Excluder) - continue; - Matcher matcher = formatter.regex.matcher(str); - while (matcher.find()) { - DebugCommand.SendDebugMessage("Found match from " + matcher.start() + " to " + (matcher.end() - 1)); - DebugCommand.SendDebugMessage("With excluder formatter:" + formatter); - sendMessageWithPointer(str, matcher.start(), matcher.end() - 1); - if (formatter.regex != ChatProcessing.ENTIRE_MESSAGE_PATTERN && sections.stream().anyMatch(fs -> fs.type == Type.Excluder && (fs.End >= matcher.start() && fs.Start <= matcher.end() - 1))) { - DebugCommand.SendDebugMessage("Ignoring formatter because of an excluder"); - continue; //Exclude areas matched by excluders - Range sections are correctly handled afterwards - } - ArrayList groups = new ArrayList(); - for (int i = 0; i < matcher.groupCount(); i++) - groups.add(matcher.group(i + 1)); - if (groups.size() > 0) - DebugCommand.SendDebugMessage("First group: " + groups.get(0)); - FormattedSection section = new FormattedSection(formatter, matcher.start(), matcher.end() - 1, groups, - formatter.type); - sections.add(section); - } - } + if (config != null) //null if testing + formatters.removeIf(cf -> !cf.enabled(config).get()); //Remove disabled formatters + createSections(formatters, str, sections, true); - header("Section creation (excluders done)"); - for (ChatFormatter formatter : formatters) { - if (formatter.type == Type.Excluder) - continue; - Matcher matcher = formatter.regex.matcher(str); - while (matcher.find()) { - DebugCommand.SendDebugMessage("Found match from " + matcher.start() + " to " + (matcher.end() - 1)); - DebugCommand.SendDebugMessage("With formatter:" + formatter); - sendMessageWithPointer(str, matcher.start(), matcher.end() - 1); - if (formatter.regex != ChatProcessing.ENTIRE_MESSAGE_PATTERN && sections.stream().anyMatch(fs -> fs.type == Type.Excluder && (fs.End >= matcher.start() && fs.Start <= matcher.end() - 1))) { - DebugCommand.SendDebugMessage("Ignoring formatter because of an excluder"); - continue; //Exclude areas matched by excluders - Range sections are correctly handled afterwards - } - ArrayList groups = new ArrayList(); - for (int i = 0; i < matcher.groupCount(); i++) - groups.add(matcher.group(i + 1)); - if (groups.size() > 0) - DebugCommand.SendDebugMessage("First group: " + groups.get(0)); - FormattedSection section = new FormattedSection(formatter, matcher.start(), matcher.end() - 1, groups, - formatter.type); - sections.add(section); - } - } - sections.sort( - (s1, s2) -> s1.Start == s2.Start - ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), - s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s2.End, s1.End) - : Integer.compare(s1.Start, s2.Start)); + header("Section creation (excluders done)"); + createSections(formatters, str, sections, false); + sortSections(sections); - /** + /* * 0: Start - 1: End index */ val remchars = new ArrayList(); header("Range section conversion"); + sections = convertRangeSections(str, sections, remchars); + + header("Adding remove chars (RC)"); // Important to add after the range section conversion + addRemChars(sections, remchars); + + header("Section combining"); + combineSections(str, sections); + + header("Section applying"); + applySections(str, tp, sections, remchars); + header("ChatFormatter.Combine done"); + } + + private static void createSections(List formatters, String str, ArrayList sections, + boolean excluders) { + for (ChatFormatter formatter : formatters) { + if (excluders == (formatter.type != Type.Excluder)) + continue; //If we're looking at excluders and this isn't one, skip - or vica-versa + Matcher matcher = formatter.regex.matcher(str); + while (matcher.find()) { + DebugCommand.SendDebugMessage("Found match from " + matcher.start() + " to " + (matcher.end() - 1)); + DebugCommand.SendDebugMessage("With " + (excluders ? "excluder " : "") + "formatter: " + formatter); + sendMessageWithPointer(str, matcher.start(), matcher.end() - 1); + if (formatter.regex != ChatProcessing.ENTIRE_MESSAGE_PATTERN && sections.stream().anyMatch(fs -> fs.type == Type.Excluder && (fs.End >= matcher.start() && fs.Start <= matcher.end() - 1))) { + DebugCommand.SendDebugMessage("Ignoring formatter because of an excluder"); + continue; //Exclude areas matched by excluders - Range sections are correctly handled afterwards + } + ArrayList groups = new ArrayList<>(); + for (int i = 0; i < matcher.groupCount(); i++) + groups.add(matcher.group(i + 1)); + if (groups.size() > 0) + DebugCommand.SendDebugMessage("First group: " + groups.get(0)); + FormattedSection section = new FormattedSection(formatter, matcher.start(), matcher.end() - 1, groups, + formatter.type); + sections.add(section); + } + } + } + + private static ArrayList convertRangeSections(String str, ArrayList sections, ArrayList remchars) { ArrayList combined = new ArrayList<>(); Map nextSection = new HashMap<>(); boolean escaped = false; int takenStart = -1, takenEnd = -1; ChatFormatter takenFormatter = null; - for (int i = 0; i < sections.size(); i++) { + for (final FormattedSection section : sections) { // Set ending to -1 until closed with another 1 long "section" - only do this if IsRange is true - final FormattedSection section = sections.get(i); - if (section.type!=Type.Range) { + if (section.type != Type.Range) { escaped = section.Formatters.contains(ChatProcessing.ESCAPE_FORMATTER) && !escaped; // Enable escaping on first \, disable on second - if (escaped) {// Don't add the escape character + if (escaped) {// Don't add the escape character remchars.add(new int[]{section.Start, section.Start}); - DebugCommand.SendDebugMessage("Found escaper section: " + section); - } else { - combined.add(section); // The above will delete the \ - DebugCommand.SendDebugMessage("Added section: " + section); - } + DebugCommand.SendDebugMessage("Found escaper section: " + section); + } else { + combined.add(section); // The above will delete the \ + DebugCommand.SendDebugMessage("Added section: " + section); + } sendMessageWithPointer(str, section.Start, section.End); continue; - } - if (!escaped) { - if (combined.stream().anyMatch(s -> section.type != Type.Range && (s.Start == section.Start - || (s.Start < section.Start ? s.End >= section.Start : s.Start <= section.End)))) { - DebugCommand.SendDebugMessage("Range " + section + " overlaps with a combined section, ignoring."); - sendMessageWithPointer(str, section.Start, section.End); - continue; - } + } + if (!escaped) { if (section.Start == takenStart || (section.Start > takenStart && section.Start < takenEnd)) { /* * if (nextSection.containsKey(section.Formatters.get(0)) ? section.RemCharFromStart <= takenEnd - takenStart : section.RemCharFromStart > takenEnd - takenStart) { @@ -183,7 +187,7 @@ public final class ChatFormatter { nextSection.put(section.Formatters.get(0), section); } DebugCommand - .SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter); + .SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter); sendMessageWithPointer(str, takenStart, takenEnd); } else { DebugCommand.SendDebugMessage("Skipping section: " + section); // This will keep the text (character) @@ -193,24 +197,27 @@ public final class ChatFormatter { } //Do not finish unfinished sections, ignore them sections = combined; + return sections; + } - header("Adding remove chars (RC)"); // Important to add after the range section conversion + private static void addRemChars(ArrayList sections, ArrayList remchars) { sections.stream() - .flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0) - .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.Start, fs.Start + rcc - 1})) - .forEach(rc -> remchars.add(rc)); + .flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0) + .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.Start, fs.Start + rcc - 1})) + .forEach(remchars::add); sections.stream() - .flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0) - .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.End - rcc + 1, fs.End})) - .forEach(rc -> remchars.add(rc)); + .flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0) + .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.End - rcc + 1, fs.End})) + .forEach(remchars::add); DebugCommand.SendDebugMessage("Added remchars:"); DebugCommand - .SendDebugMessage(remchars.stream().map(rc -> Arrays.toString(rc)).collect(Collectors.joining("; "))); + .SendDebugMessage(remchars.stream().map(Arrays::toString).collect(Collectors.joining("; "))); + } - header("Section combining"); + private static void combineSections(String str, ArrayList sections) { boolean cont = true; boolean found = false; - for (int i = 1; cont;) { + for (int i = 1; cont; ) { int nextindex = i + 1; if (sections.size() < 2) break; @@ -218,47 +225,40 @@ public final class ChatFormatter { FormattedSection firstSection = sections.get(i - 1); DebugCommand.SendDebugMessage("Combining sections " + firstSection); sendMessageWithPointer(str, firstSection.Start, firstSection.End); - DebugCommand.SendDebugMessage(" and " + sections.get(i)); - sendMessageWithPointer(str, sections.get(i).Start, sections.get(i).End); - if (firstSection.Start == sections.get(i).Start && firstSection.End == sections.get(i).End) { - firstSection.Formatters.addAll(sections.get(i).Formatters); - firstSection.Matches.addAll(sections.get(i).Matches); + final FormattedSection lastSection = sections.get(i); + DebugCommand.SendDebugMessage(" and " + lastSection); + sendMessageWithPointer(str, lastSection.Start, lastSection.End); + if (firstSection.Start == lastSection.Start && firstSection.End == lastSection.End) { + firstSection.Formatters.addAll(lastSection.Formatters); + firstSection.Matches.addAll(lastSection.Matches); DebugCommand.SendDebugMessage("To section " + firstSection); sendMessageWithPointer(str, firstSection.Start, firstSection.End); sections.remove(i); found = true; - } else if (firstSection.End > sections.get(i).Start && firstSection.Start < sections.get(i).End) { - int origend = firstSection.End; - firstSection.End = sections.get(i).Start - 1; - int origend2 = sections.get(i).End; - boolean switchends; - if (switchends = origend2 < origend) { - int tmp = origend; - origend = origend2; - origend2 = tmp; - } - FormattedSection section = new FormattedSection(firstSection.Formatters, sections.get(i).Start, origend, - firstSection.Matches, Type.Normal); - section.Formatters.addAll(sections.get(i).Formatters); - section.Matches.addAll(sections.get(i).Matches); // TODO: Clean + } else if (firstSection.End > lastSection.Start && firstSection.Start < lastSection.End) { + int origend2 = firstSection.End; + firstSection.End = lastSection.Start - 1; + int origend = lastSection.End; + FormattedSection section = new FormattedSection(firstSection.Formatters, lastSection.Start, origend, + firstSection.Matches, Type.Normal); + section.Formatters.addAll(lastSection.Formatters); + section.Matches.addAll(lastSection.Matches); // TODO: Clean sections.add(i, section); nextindex++; - FormattedSection thirdFormattedSection = sections.get(i + 1); - if (switchends) { // Use the properties of the first section not the second one - thirdFormattedSection.Formatters.clear(); - thirdFormattedSection.Formatters.addAll(firstSection.Formatters); - thirdFormattedSection.Matches.clear(); - thirdFormattedSection.Matches.addAll(firstSection.Matches); - } - thirdFormattedSection.Start = origend + 1; - thirdFormattedSection.End = origend2; + // Use the properties of the first section not the second one + lastSection.Formatters.clear(); + lastSection.Formatters.addAll(firstSection.Formatters); + lastSection.Matches.clear(); + lastSection.Matches.addAll(firstSection.Matches); + + lastSection.Start = origend + 1; + lastSection.End = origend2; - ArrayList sts = sections; Predicate removeIfNeeded = s -> { if (s.Start < 0 || s.End < 0 || s.Start > s.End) { DebugCommand.SendDebugMessage("Removing section: " + s); sendMessageWithPointer(str, s.Start, s.End); - sts.remove(s); + sections.remove(s); return true; } return false; @@ -273,9 +273,9 @@ public final class ChatFormatter { DebugCommand.SendDebugMessage(" 2:" + section + ""); sendMessageWithPointer(str, section.Start, section.End); } - if (!removeIfNeeded.test(thirdFormattedSection)) { - DebugCommand.SendDebugMessage(" 3:" + thirdFormattedSection); - sendMessageWithPointer(str, thirdFormattedSection.Start, thirdFormattedSection.End); + if (!removeIfNeeded.test(lastSection)) { + DebugCommand.SendDebugMessage(" 3:" + lastSection); + sendMessageWithPointer(str, lastSection.Start, lastSection.End); } found = true; } @@ -294,48 +294,44 @@ public final class ChatFormatter { if (found) { i = 1; found = false; - sections.sort( - (s1, s2) -> s1.Start == s2.Start - ? s1.End == s2.End - ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), - s1.Formatters.get(0).priority.GetValue()) - : Integer.compare(s2.End, s1.End) - : Integer.compare(s1.Start, s2.Start)); + sortSections(sections); } else cont = false; } } + } - header("Section applying"); - TellrawPart lasttp = null; String lastlink = null; - for (FormattedSection section : sections) { + private static void applySections(String str, TellrawPart tp, ArrayList sections, ArrayList remchars) { + TellrawPart lasttp = null; + String lastlink = null; + for (FormattedSection section : sections) { DebugCommand.SendDebugMessage("Applying section: " + section); String originaltext; int start = section.Start, end = section.End; DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end); sendMessageWithPointer(str, start, end); - val rcs = remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).findAny(); - val rce = remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).findAny(); - val rci = remchars.stream().filter(rc -> start < rc[0] && rc[1] < end).toArray(int[][]::new); + val rcs = remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).findAny(); + val rce = remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).findAny(); + val rci = remchars.stream().filter(rc -> start < rc[0] && rc[1] < end).toArray(int[][]::new); int s = start, e = end; if (rcs.isPresent()) s = rcs.get()[1] + 1; if (rce.isPresent()) e = rce.get()[0] - 1; DebugCommand.SendDebugMessage("After RC - Start: " + s + " - End: " + e); - if (e - s < 0) { //e-s==0 means the end char is the same as start char, so one char message - DebugCommand.SendDebugMessage("Skipping section because of remchars (length would be " + (e - s + 1) + ")"); + if (e - s < 0) { //e-s==0 means the end char is the same as start char, so one char message + DebugCommand.SendDebugMessage("Skipping section because of remchars (length would be " + (e - s + 1) + ")"); continue; } originaltext = str.substring(s, e + 1); - val sb = new StringBuilder(originaltext); - for (int x = rci.length - 1; x >= 0; x--) - sb.delete(rci[x][0] - start - 1, rci[x][1] - start); //Delete going backwards - originaltext = sb.toString(); + val sb = new StringBuilder(originaltext); + for (int x = rci.length - 1; x >= 0; x--) + sb.delete(rci[x][0] - start - 1, rci[x][1] - start); //Delete going backwards + originaltext = sb.toString(); DebugCommand.SendDebugMessage("Section text: " + originaltext); - String openlink = null; - section.Formatters.sort(Comparator.comparing(cf2 -> cf2.priority.GetValue())); //Apply the highest last, to overwrite previous ones - TellrawPart newtp = new TellrawPart(""); + String openlink = null; + section.Formatters.sort(Comparator.comparing(cf2 -> cf2.priority.GetValue())); //Apply the highest last, to overwrite previous ones + TellrawPart newtp = new TellrawPart(""); for (ChatFormatter formatter : section.Formatters) { DebugCommand.SendDebugMessage("Applying formatter: " + formatter); if (formatter.onmatch != null) @@ -343,42 +339,50 @@ public final class ChatFormatter { if (formatter.color != null) newtp.setColor(formatter.color); if (formatter.bold) - newtp.setBold(formatter.bold); + newtp.setBold(true); if (formatter.italic) - newtp.setItalic(formatter.italic); + newtp.setItalic(true); if (formatter.underlined) - newtp.setUnderlined(formatter.underlined); + newtp.setUnderlined(true); if (formatter.strikethrough) - newtp.setStrikethrough(formatter.strikethrough); + newtp.setStrikethrough(true); if (formatter.obfuscated) - newtp.setObfuscated(formatter.obfuscated); + newtp.setObfuscated(true); if (formatter.openlink != null) openlink = formatter.openlink; if (formatter.hoverText != null) newtp.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, formatter.hoverText)); } - if (lasttp != null && newtp.getColor() == lasttp.getColor() - && newtp.isBold() == lasttp.isBold() - && newtp.isItalic() == lasttp.isItalic() - && newtp.isUnderlined() == lasttp.isUnderlined() - && newtp.isStrikethrough() == lasttp.isStrikethrough() - && newtp.isObfuscated() == lasttp.isObfuscated() - && Objects.equals(openlink, lastlink)) { - DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining."); - lasttp.setText(lasttp.getText() + originaltext); - continue; //Combine parts with the same properties - } + if (lasttp != null && newtp.getColor() == lasttp.getColor() + && newtp.isBold() == lasttp.isBold() + && newtp.isItalic() == lasttp.isItalic() + && newtp.isUnderlined() == lasttp.isUnderlined() + && newtp.isStrikethrough() == lasttp.isStrikethrough() + && newtp.isObfuscated() == lasttp.isObfuscated() + && Objects.equals(openlink, lastlink)) { + DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining."); + lasttp.setText(lasttp.getText() + originaltext); + continue; //Combine parts with the same properties + } + lastlink = openlink; newtp.setText(originaltext); if (openlink != null && openlink.length() > 0) { newtp.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.OPEN_URL, - (section.Matches.size() > 0 ? openlink.replace("$1", section.Matches.get(0)) : openlink))) - .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, - new TellrawPart("Click to open").setColor(Color.Blue))); + (section.Matches.size() > 0 ? openlink.replace("$1", section.Matches.get(0)) : openlink))) + .setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, + new TellrawPart("Click to open").setColor(Color.Blue))); } tp.addExtra(newtp); - lasttp = newtp; + lasttp = newtp; } - header("ChatFormatter.Combine done"); + } + + private static void sortSections(ArrayList sections) { + sections.sort( + (s1, s2) -> s1.Start == s2.Start + ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), + s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s2.End, s1.End) + : Integer.compare(s1.Start, s2.Start)); } private static void sendMessageWithPointer(String str, int... pointer) { diff --git a/src/main/java/buttondevteam/chat/formatting/FormattedSection.java b/src/main/java/buttondevteam/chat/components/formatter/formatting/FormattedSection.java similarity index 94% rename from src/main/java/buttondevteam/chat/formatting/FormattedSection.java rename to src/main/java/buttondevteam/chat/components/formatter/formatting/FormattedSection.java index 15101c4..c609e58 100644 --- a/src/main/java/buttondevteam/chat/formatting/FormattedSection.java +++ b/src/main/java/buttondevteam/chat/components/formatter/formatting/FormattedSection.java @@ -1,4 +1,4 @@ -package buttondevteam.chat.formatting; +package buttondevteam.chat.components.formatter.formatting; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/buttondevteam/chat/formatting/TellrawEvent.java b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawEvent.java similarity index 93% rename from src/main/java/buttondevteam/chat/formatting/TellrawEvent.java rename to src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawEvent.java index 8f43d63..4c532e5 100644 --- a/src/main/java/buttondevteam/chat/formatting/TellrawEvent.java +++ b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawEvent.java @@ -1,76 +1,76 @@ -package buttondevteam.chat.formatting; - -import java.io.Serializable; - -import buttondevteam.lib.chat.TellrawSerializableEnum; - -public final class TellrawEvent implements Serializable { - private static final long serialVersionUID = -1681364161210561505L; - private transient boolean hoverEvent; - private T action; - private Object value; - - private TellrawEvent(T action, String value) { - this.hoverEvent = action instanceof HoverAction; - this.action = action; - this.value = value; - } - - private TellrawEvent(T action, TellrawPart value) { - this.hoverEvent = action instanceof HoverAction; - this.action = action; - this.value = value; - } - - public static TellrawEvent create(V action, String value) { - return new TellrawEvent<>(action, value); - } - - public static TellrawEvent create(V action, TellrawPart value) { - return new TellrawEvent<>(action, value); - } - - public boolean isHoverEvent() { - return hoverEvent; - } - - public T getAction() { - return action; - } - - public Object getValue() { - return value; - } - - public enum ClickAction implements Action { - OPEN_URL("open_url"), RUN_COMMAND("run_command"), SUGGEST_COMMAND("suggest_command"); - private String action; - - ClickAction(String action) { - this.action = action; - } - - @Override - public String getName() { - return action; - } - } - - public enum HoverAction implements Action { - SHOW_TEXT("show_text"), SHOW_ITEM("show_item"), SHOW_ACHIEVEMENT("show_achievement"), SHOW_ENTITY( - "show_entity"); - private String action; - - HoverAction(String action) { - this.action = action; - } - - @Override - public String getName() { - return action; - } - } - - public static interface Action extends TellrawSerializableEnum { - } -} +package buttondevteam.chat.components.formatter.formatting; + +import buttondevteam.lib.chat.TellrawSerializableEnum; + +import java.io.Serializable; + +public final class TellrawEvent implements Serializable { + private static final long serialVersionUID = -1681364161210561505L; + private transient boolean hoverEvent; + private T action; + private Object value; + + private TellrawEvent(T action, String value) { + this.hoverEvent = action instanceof HoverAction; + this.action = action; + this.value = value; + } + + private TellrawEvent(T action, TellrawPart value) { + this.hoverEvent = action instanceof HoverAction; + this.action = action; + this.value = value; + } + + public static TellrawEvent create(V action, String value) { + return new TellrawEvent<>(action, value); + } + + public static TellrawEvent create(V action, TellrawPart value) { + return new TellrawEvent<>(action, value); + } + + public boolean isHoverEvent() { + return hoverEvent; + } + + public T getAction() { + return action; + } + + public Object getValue() { + return value; + } + + public enum ClickAction implements Action { + OPEN_URL("open_url"), RUN_COMMAND("run_command"), SUGGEST_COMMAND("suggest_command"); + private String action; + + ClickAction(String action) { + this.action = action; + } + + @Override + public String getName() { + return action; + } + } + + public enum HoverAction implements Action { + SHOW_TEXT("show_text"), SHOW_ITEM("show_item"), SHOW_ACHIEVEMENT("show_achievement"), SHOW_ENTITY( + "show_entity"); + private String action; + + HoverAction(String action) { + this.action = action; + } + + @Override + public String getName() { + return action; + } + } + + public static interface Action extends TellrawSerializableEnum { + } +} diff --git a/src/main/java/buttondevteam/chat/formatting/TellrawPart.java b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawPart.java similarity index 92% rename from src/main/java/buttondevteam/chat/formatting/TellrawPart.java rename to src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawPart.java index 0e7dc72..2425574 100644 --- a/src/main/java/buttondevteam/chat/formatting/TellrawPart.java +++ b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawPart.java @@ -1,115 +1,115 @@ -package buttondevteam.chat.formatting; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import buttondevteam.lib.chat.*; - -public final class TellrawPart implements Serializable { - private static final long serialVersionUID = 4125357644462144024L; - private Color color; - private boolean italic; - private boolean bold; - private boolean underlined; - private boolean strikethrough; - private boolean obfuscated; - private List extra = new ArrayList<>(); - private String text; - private TellrawEvent hoverEvent; - private TellrawEvent clickEvent; - - public TellrawPart(String text) { - this.text = text; - } - - public Color getColor() { - return color; - } - - public TellrawPart setColor(Color color) { - this.color = color; - return this; - } - - public boolean isItalic() { - return italic; - } - - public TellrawPart setItalic(boolean italic) { - this.italic = italic; - return this; - } - - public boolean isBold() { - return bold; - } - - public TellrawPart setBold(boolean bold) { - this.bold = bold; - return this; - } - - public boolean isUnderlined() { - return underlined; - } - - public TellrawPart setUnderlined(boolean underlined) { - this.underlined = underlined; - return this; - } - - public boolean isStrikethrough() { - return strikethrough; - } - - public TellrawPart setStrikethrough(boolean strikethrough) { - this.strikethrough = strikethrough; - return this; - } - - public boolean isObfuscated() { - return obfuscated; - } - - public TellrawPart setObfuscated(boolean obfuscated) { - this.obfuscated = obfuscated; - return this; - } - - public Iterable getExtra() { - return extra; - } - - public TellrawPart addExtra(TellrawPart extra) { - this.extra.add(extra); - return this; - } - - public String getText() { - return text; - } - - public TellrawPart setText(String text) { - this.text = text; - return this; - } - - public TellrawEvent getHoverEvent() { - return hoverEvent; - } - - public TellrawPart setHoverEvent(TellrawEvent hoverEvent) { - this.hoverEvent = hoverEvent; - return this; - } - - public TellrawEvent getClickEvent() { - return clickEvent; - } - - public TellrawPart setClickEvent(TellrawEvent clickEvent) { - this.clickEvent = clickEvent; - return this; - } -} +package buttondevteam.chat.components.formatter.formatting; + +import buttondevteam.lib.chat.Color; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public final class TellrawPart implements Serializable { + private static final long serialVersionUID = 4125357644462144024L; + private Color color; + private boolean italic; + private boolean bold; + private boolean underlined; + private boolean strikethrough; + private boolean obfuscated; + private List extra = new ArrayList<>(); + private String text; + private TellrawEvent hoverEvent; + private TellrawEvent clickEvent; + + public TellrawPart(String text) { + this.text = text; + } + + public Color getColor() { + return color; + } + + public TellrawPart setColor(Color color) { + this.color = color; + return this; + } + + public boolean isItalic() { + return italic; + } + + public TellrawPart setItalic(boolean italic) { + this.italic = italic; + return this; + } + + public boolean isBold() { + return bold; + } + + public TellrawPart setBold(boolean bold) { + this.bold = bold; + return this; + } + + public boolean isUnderlined() { + return underlined; + } + + public TellrawPart setUnderlined(boolean underlined) { + this.underlined = underlined; + return this; + } + + public boolean isStrikethrough() { + return strikethrough; + } + + public TellrawPart setStrikethrough(boolean strikethrough) { + this.strikethrough = strikethrough; + return this; + } + + public boolean isObfuscated() { + return obfuscated; + } + + public TellrawPart setObfuscated(boolean obfuscated) { + this.obfuscated = obfuscated; + return this; + } + + public Iterable getExtra() { + return extra; + } + + public TellrawPart addExtra(TellrawPart extra) { + this.extra.add(extra); + return this; + } + + public String getText() { + return text; + } + + public TellrawPart setText(String text) { + this.text = text; + return this; + } + + public TellrawEvent getHoverEvent() { + return hoverEvent; + } + + public TellrawPart setHoverEvent(TellrawEvent hoverEvent) { + this.hoverEvent = hoverEvent; + return this; + } + + public TellrawEvent getClickEvent() { + return clickEvent; + } + + public TellrawPart setClickEvent(TellrawEvent clickEvent) { + this.clickEvent = clickEvent; + return this; + } +} diff --git a/src/main/java/buttondevteam/chat/formatting/TellrawSerializer.java b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawSerializer.java similarity index 90% rename from src/main/java/buttondevteam/chat/formatting/TellrawSerializer.java rename to src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawSerializer.java index f8b591e..b1a36fd 100644 --- a/src/main/java/buttondevteam/chat/formatting/TellrawSerializer.java +++ b/src/main/java/buttondevteam/chat/components/formatter/formatting/TellrawSerializer.java @@ -1,59 +1,59 @@ -package buttondevteam.chat.formatting; - -import java.io.IOException; -import java.lang.reflect.Type; -import java.util.Collection; - -import com.google.gson.*; -import com.google.gson.stream.*; - -import buttondevteam.lib.chat.TellrawSerializableEnum; - -public abstract class TellrawSerializer { - public static class TwEnum extends TypeAdapter { - @Override - public TellrawSerializableEnum read(JsonReader reader) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public void write(JsonWriter writer, TellrawSerializableEnum enumval) throws IOException { - if (enumval == null) - writer.nullValue(); - else - writer.value(enumval.getName()); - } - } - - public static class TwCollection implements JsonSerializer> { - @Override - public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) { - if (src == null || src.isEmpty()) - return null; - - JsonArray array = new JsonArray(); - - for (Object child : src) { - JsonElement element = context.serialize(child); - array.add(element); - } - - return array; - } - } - - public static class TwBool extends TypeAdapter { - @Override - public Boolean read(JsonReader reader) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public void write(JsonWriter writer, Boolean val) throws IOException { - if (val) - writer.value(val); - else - writer.nullValue(); - } - } -} +package buttondevteam.chat.components.formatter.formatting; + +import buttondevteam.lib.chat.TellrawSerializableEnum; +import com.google.gson.*; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Collection; + +public abstract class TellrawSerializer { + public static class TwEnum extends TypeAdapter { + @Override + public TellrawSerializableEnum read(JsonReader reader) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void write(JsonWriter writer, TellrawSerializableEnum enumval) throws IOException { + if (enumval == null) + writer.nullValue(); + else + writer.value(enumval.getName()); + } + } + + public static class TwCollection implements JsonSerializer> { + @Override + public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) { + if (src == null || src.isEmpty()) + return null; + + JsonArray array = new JsonArray(); + + for (Object child : src) { + JsonElement element = context.serialize(child); + array.add(element); + } + + return array; + } + } + + public static class TwBool extends TypeAdapter { + @Override + public Boolean read(JsonReader reader) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void write(JsonWriter writer, Boolean val) throws IOException { + if (val) + writer.value(val); + else + writer.nullValue(); + } + } +} diff --git a/src/main/java/buttondevteam/chat/components/fun/CCommand.java b/src/main/java/buttondevteam/chat/components/fun/CCommand.java index 3cd8e27..42acb07 100644 --- a/src/main/java/buttondevteam/chat/components/fun/CCommand.java +++ b/src/main/java/buttondevteam/chat/components/fun/CCommand.java @@ -6,6 +6,9 @@ import buttondevteam.lib.chat.*; import buttondevteam.lib.player.TBMCPlayer; import org.bukkit.entity.Player; +import java.util.Arrays; +import java.util.Optional; + @CommandClass(path = "u c", helpText = { "Rainbow mode", "This command allows you to talk in rainbow colors" @@ -16,7 +19,7 @@ public class CCommand extends ICommand2MC { public boolean def(Player player, @Command2.OptionalArg String color) { ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); if (color == null) { - if (PluginMain.permission.has(player, "thorpe.color.rainbow")) { + if (PluginMain.permission.has(player, "chroma.color.rainbow")) { p.RainbowPresserColorMode = !p.RainbowPresserColorMode; p.OtherColorMode = null; if (p.RainbowPresserColorMode) @@ -28,19 +31,23 @@ public class CCommand extends ICommand2MC { return true; } } else { - if (PluginMain.permission.has(player, "thorpe.color.custom")) { - p.RainbowPresserColorMode = false; - p.OtherColorMode = null; - try { - p.OtherColorMode = Color.valueOf(color.toLowerCase()); - } catch (Exception e) { + if (PluginMain.permission.has(player, "chroma.color.custom")) { + String x = color.toLowerCase(); + if ("off".equals(x)) { + p.OtherColorMode = null; + player.sendMessage("§eMessage color reset."); + return true; + } + Optional oc = Arrays.stream(Color.values()).filter(c -> c.getName().equals(x)).findAny(); + if (!oc.isPresent()) { player.sendMessage("§cUnknown message color: " + color); player.sendMessage("§cUse color names, like blue, or dark_aqua"); + player.sendMessage("§cOr use 'off' to disable"); + return true; } - if (p.OtherColorMode != null) - player.sendMessage(String.format("§eMessage color set to %s", p.OtherColorMode)); - else - player.sendMessage("§eMessage color reset."); + p.RainbowPresserColorMode = false; + p.OtherColorMode = oc.get(); + player.sendMessage(String.format("§eMessage color set to %s", p.OtherColorMode)); } else { player.sendMessage("§cYou don't have permission for this command."); return true; diff --git a/src/main/java/buttondevteam/chat/components/fun/FunComponent.java b/src/main/java/buttondevteam/chat/components/fun/FunComponent.java index 4b726b8..82b1229 100644 --- a/src/main/java/buttondevteam/chat/components/fun/FunComponent.java +++ b/src/main/java/buttondevteam/chat/components/fun/FunComponent.java @@ -3,10 +3,10 @@ package buttondevteam.chat.components.fun; import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.PluginMain; import buttondevteam.core.component.channel.Channel; +import buttondevteam.lib.ChromaUtils; import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.ThorpeUtils; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.TBMCChatAPI; @@ -139,15 +139,15 @@ public class FunComponent extends Component implements Listener { if (ht.getName().equalsIgnoreCase(cmd)) return; } - if (PluginMain.permission.has(event.getSender(), "thorpe.unanything")) { + if (PluginMain.permission.has(event.getSender(), "chroma.unanything")) { event.setCancelled(true); - String s = cmd.substring(3); - int index = event.getMessage().indexOf(' '); + int index = cmd.lastIndexOf(' '); if (index == -1) { - event.getSender().sendMessage("§cUsage: /un" + s + " "); + event.getSender().sendMessage("§cUsage: " + cmd + " "); return; } - Player target = Bukkit.getPlayer(event.getMessage().substring(index + 1)); + String s = cmd.substring(3, index); + Player target = Bukkit.getPlayer(cmd.substring(index + 1)); if (target == null) { event.getSender().sendMessage("§cError: Player not found. (/un" + s + " )"); return; @@ -155,7 +155,7 @@ public class FunComponent extends Component implements Listener { val user = ChromaGamerBase.getFromSender(event.getSender()); target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10 * 20, 5, false, false)); val chan = user.channel().get(); - TBMCChatAPI.SendSystemMessage(chan, chan.getRTR(event.getSender()), ThorpeUtils.getDisplayName(event.getSender()) + " un" + s + TBMCChatAPI.SendSystemMessage(chan, chan.getRTR(event.getSender()), ChromaUtils.getDisplayName(event.getSender()) + " un" + s + "'d " + target.getDisplayName(), unlolTarget); } } diff --git a/src/main/java/buttondevteam/chat/components/fun/PressCommand.java b/src/main/java/buttondevteam/chat/components/fun/PressCommand.java index 123aab5..e675d20 100644 --- a/src/main/java/buttondevteam/chat/components/fun/PressCommand.java +++ b/src/main/java/buttondevteam/chat/components/fun/PressCommand.java @@ -1,15 +1,13 @@ package buttondevteam.chat.components.fun; import buttondevteam.core.component.channel.Channel; -import buttondevteam.core.component.restart.RestartComponent; import buttondevteam.core.component.restart.ScheduledRestartCommand; +import buttondevteam.lib.ChromaUtils; import buttondevteam.lib.ScheduledServerRestartEvent; -import buttondevteam.lib.ThorpeUtils; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.chat.TBMCChatAPI; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -33,7 +31,7 @@ public class PressCommand extends ICommand2MC implements Listener { return; } pressers.add(sender); - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("§b-- %s §bpressed at %.0fs", ThorpeUtils.getDisplayName(sender), command.getRestartCounter() / 20f), command.getComponent().getRestartBroadcast()); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("§b-- %s §bpressed at %.0fs", ChromaUtils.getDisplayName(sender), command.getRestartCounter() / 20f), command.getComponent().getRestartBroadcast()); command.setRestartCounter(startTicks); } diff --git a/src/main/java/buttondevteam/chat/components/fun/UnlolCommand.java b/src/main/java/buttondevteam/chat/components/fun/UnlolCommand.java index 8de6c9e..8a0ea93 100644 --- a/src/main/java/buttondevteam/chat/components/fun/UnlolCommand.java +++ b/src/main/java/buttondevteam/chat/components/fun/UnlolCommand.java @@ -1,13 +1,15 @@ package buttondevteam.chat.components.fun; import buttondevteam.core.component.channel.Channel; +import buttondevteam.lib.ChromaUtils; import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.ThorpeUtils; -import buttondevteam.lib.chat.*; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2MC; +import buttondevteam.lib.chat.TBMCChatAPI; import lombok.Data; import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; @@ -39,9 +41,9 @@ public final class UnlolCommand extends ICommand2MC { if (lol.Lolowner instanceof Player) ((Player) lol.Lolowner) .addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 2 * 20, 5, false, false)); - String msg = ThorpeUtils.getDisplayName(sender) + String msg = ChromaUtils.getDisplayName(sender) + (lol.Lolornot ? " unlolled " : " unlaughed ") - + ThorpeUtils.getDisplayName(lol.Lolowner); + + ChromaUtils.getDisplayName(lol.Lolowner); TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, msg, target); Lastlol.remove(lol.Chatevent.getChannel()); return true; diff --git a/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java index ab41374..d685030 100644 --- a/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java @@ -15,7 +15,6 @@ import com.earth2me.essentials.User; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.object.Nation; import lombok.Getter; -import lombok.experimental.var; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -113,6 +112,7 @@ public class TownColorComponent extends Component implements Listene if (useNationColors().get()) registerCommand(new buttondevteam.chat.components.towncolors.admin.NationColorCommand()); registerCommand(new TCCount()); + registerCommand(new NColorCommand()); registerListener(new TownyListener()); registerListener(this); } diff --git a/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java index 963cb05..77bba40 100644 --- a/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java @@ -35,7 +35,7 @@ public class NationColorCommand extends AdminCommandBase { if (!c.get().getName().equals(Color.White.getName())) { //Default nation color for (val e : TownColorComponent.NationColor.entrySet()) { if (e.getValue().getName().equals(c.get().getName())) { - sender.sendMessage("§The nation " + e.getKey() + " already uses this color!"); + sender.sendMessage("§cThe nation " + e.getKey() + " already uses this color!"); return true; } } diff --git a/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java b/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java index 55702c7..1283a3d 100644 --- a/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java +++ b/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java @@ -1,23 +1,33 @@ package buttondevteam.chat.components.towny; -import buttondevteam.chat.ChatProcessing; +import buttondevteam.chat.ChatUtils; import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.TBMCChatAPI; -import com.palmergames.bukkit.towny.TownyLogger; import lombok.val; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.filter.LevelRangeFilter; +import org.apache.logging.log4j.core.layout.PatternLayout; -import java.util.logging.Handler; -import java.util.logging.LogRecord; import java.util.regex.Pattern; public class TownyAnnouncer { private static final Pattern LOG_TYPE_PATTERN = Pattern.compile("\\[(\\w+) (?:Msg|Message)](?: (\\w+):)?"); - private static final Handler HANDLER = new Handler() { + private static final String APPENDER_NAME = "Chroma"; + private static final AbstractAppender HANDLER = new AbstractAppender(APPENDER_NAME, + LevelRangeFilter.createFilter(Level.INFO, Level.INFO, Filter.Result.ACCEPT, Filter.Result.ACCEPT), + PatternLayout.createDefaultLayout()) { @Override - public void publish(LogRecord logRecord) { + public void append(LogEvent logRecord) { if (logRecord.getMessage() == null) return; - val m = LOG_TYPE_PATTERN.matcher(logRecord.getMessage()); + String message = logRecord.getMessage().getFormattedMessage(); + val m = LOG_TYPE_PATTERN.matcher(message); if (!m.find()) return; String groupID = m.group(2); //The group ID is correctly cased switch (String.valueOf(m.group(1))) { //valueOf: Handles null @@ -25,31 +35,21 @@ public class TownyAnnouncer { if (townChannel == null) return; TBMCChatAPI.SendSystemMessage(townChannel, new Channel.RecipientTestResult(TownyComponent.getTownNationIndex(groupID, false), groupID), - logRecord.getMessage(), target, ChatProcessing.MCORIGIN); + message, target, ChatUtils.MCORIGIN); break; case "Nation": if (nationChannel == null) return; TBMCChatAPI.SendSystemMessage(nationChannel, new Channel.RecipientTestResult(TownyComponent.getTownNationIndex(groupID, true), groupID), - logRecord.getMessage(), target, ChatProcessing.MCORIGIN); + message, target, ChatUtils.MCORIGIN); break; case "Global": TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, - logRecord.getMessage(), target, ChatProcessing.MCORIGIN); + message, target, ChatUtils.MCORIGIN); break; } } - - @Override - public void flush() { - - } - - @Override - public void close() throws SecurityException { - - } }; private static TBMCSystemChatEvent.BroadcastTarget target; @@ -60,7 +60,23 @@ public class TownyAnnouncer { target = TBMCSystemChatEvent.BroadcastTarget.add("towny"); TownyAnnouncer.townChannel = townChannel; TownyAnnouncer.nationChannel = nationChannel; - TownyLogger.log.addHandler(HANDLER); + /*System.out.println(LogManager.getLogger("com.palmergames.bukkit.towny")); + ((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getContext().getConfiguration().addAppender(HANDLER); + System.out.println(((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getAppenders()); + ((LoggerContext)LogManager.getContext(false)).updateLoggers(); + System.out.println(((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getAppenders()); + ((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getContext().updateLoggers(); + System.out.println(((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getAppenders());*/ + val lc = (LoggerContext) LogManager.getContext(false); + HANDLER.start(); + lc.getConfiguration().addAppender(HANDLER); + Logger logger = lc.getLogger("com.palmergames.bukkit.towny"); + //System.out.println(logger); + //System.out.println(lc.getConfiguration().getAppender(HANDLER.getName())); //T defaults to String because of the context which results in a cast exception + logger.addAppender(lc.getConfiguration().getAppender(HANDLER.getName())); + logger.get().addAppender(HANDLER, Level.INFO, HANDLER.getFilter()); + lc.updateLoggers(); + //System.out.println(logger.getAppenders()); } public static void setdown() { @@ -68,6 +84,6 @@ public class TownyAnnouncer { target = null; TownyAnnouncer.townChannel = null; TownyAnnouncer.nationChannel = null; - TownyLogger.log.removeHandler(HANDLER); + ((Logger) LogManager.getLogger("com.palmergames.bukkit.towny")).getAppenders().remove(APPENDER_NAME); } } diff --git a/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java b/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java index dbfe93c..a77bc83 100644 --- a/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java +++ b/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java @@ -1,24 +1,24 @@ package buttondevteam.chat.components.towny; import buttondevteam.chat.PluginMain; -import buttondevteam.chat.formatting.TellrawPart; +import buttondevteam.chat.VanillaUtils; +import buttondevteam.chat.components.formatter.formatting.TellrawPart; import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; -import com.palmergames.bukkit.towny.Towny; +import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownyUniverse; import lombok.val; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -32,7 +32,7 @@ public class TownyComponent extends Component { @Override protected void enable() { - TU = ((Towny) Bukkit.getPluginManager().getPlugin("Towny")).getTownyUniverse(); + TU = TownyUniverse.getInstance(); Towns = TU.getTownsMap().values().stream().map(Town::getName).collect(Collectors.toCollection(ArrayList::new)); // Creates a snapshot of towns, new towns will be added when needed Nations = TU.getNationsMap().values().stream().map(Nation::getName).collect(Collectors.toCollection(ArrayList::new)); // Same here but with nations TBMCChatAPI.RegisterChatChannel( @@ -47,12 +47,20 @@ public class TownyComponent extends Component { TownyAnnouncer.setdown(); } - public void handleSpies(Channel channel, TellrawPart json, Function toJson) { + public void handleSpiesInit(Channel channel, TellrawPart json, Function toJson) { if (channel.ID.equals(TownChat.ID) || channel.ID.equals(NationChat.ID)) { ((List) json.getExtra()).add(0, new TellrawPart("[SPY]")); - String jsonstr = toJson.apply(json); - Bukkit.getServer().dispatchCommand(PluginMain.Console, String.format( - "tellraw @a[score_%s=1000,score_%s_min=1000] %s", channel.ID, channel.ID, jsonstr)); + jsonstr = toJson.apply(json); + } + } + + private String jsonstr; + + public void handleSpies(Channel channel, Player p) { + if (channel.ID.equals(TownChat.ID) || channel.ID.equals(NationChat.ID)) { + if (Optional.ofNullable(TU.getResidentMap().get(p.getName().toLowerCase())) + .filter(r -> r.hasMode("spy")).isPresent()) + VanillaUtils.tellRaw(p, jsonstr); } } diff --git a/src/main/java/buttondevteam/chat/listener/PlayerListener.java b/src/main/java/buttondevteam/chat/listener/PlayerListener.java index 84f7fc1..eb3aaf9 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerListener.java @@ -1,19 +1,19 @@ package buttondevteam.chat.listener; import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.ChatProcessing; +import buttondevteam.chat.ChatUtils; import buttondevteam.chat.PluginMain; import buttondevteam.chat.commands.ucmds.HistoryCommand; import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.formatter.FormatterComponent; import buttondevteam.chat.components.towncolors.TownColorComponent; import buttondevteam.core.ComponentManager; import buttondevteam.core.component.channel.Channel; -import buttondevteam.core.component.channel.ChatChannelRegisterEvent; import buttondevteam.core.component.channel.ChatRoom; +import buttondevteam.lib.ChromaUtils; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.ThorpeUtils; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; @@ -52,7 +52,8 @@ public class PlayerListener implements Listener { if (event.isCancelled()) return; //The custom event is called in the core, but doesn't cancel the MC event - event.setCancelled(true); // The custom event should only be cancelled when muted or similar + if (ComponentManager.isEnabled(FormatterComponent.class)) //If not enabled, then let the other plugins deal with the message + event.setCancelled(true); // The custom event should only be cancelled when muted or similar } @EventHandler(priority = EventPriority.HIGHEST) @@ -95,11 +96,11 @@ public class PlayerListener implements Listener { Player player = Bukkit.getPlayer(message.substring(index + 1)); if (player != null && sender instanceof Player) player.sendMessage("§b" + ((Player) sender).getDisplayName() + " §bis in this world: " //TODO: Move to the Core - + ((Player) sender).getWorld().getName()); + + ((Player) sender).getWorld().getName()); } else if (cmd.equalsIgnoreCase("minecraft:me")) { if (!(sender instanceof Player) || !PluginMain.essentials.getUser((Player) sender).isMuted()) { String msg = message.substring(index + 1); - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("* %s %s", ThorpeUtils.getDisplayName(sender), msg), TBMCSystemChatEvent.BroadcastTarget.ALL); //TODO: Don't send to all + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("* %s %s", ChromaUtils.getDisplayName(sender), msg), TBMCSystemChatEvent.BroadcastTarget.ALL); //TODO: Don't send to all return true; } else { sender.sendMessage("§cCan't use /minecraft:me while muted."); @@ -131,7 +132,7 @@ public class PlayerListener implements Listener { String name = e.getLastToken(); for (Entry nicknamekv : nicknames.entrySet()) { if (nicknamekv.getKey().startsWith(name.toLowerCase())) - e.getTabCompletions().add(PluginMain.essentials.getUser(Bukkit.getPlayer(nicknamekv.getValue())).getNick(true)); //Tabcomplete with the correct case + e.getTabCompletions().add(PluginMain.essentials.getUser(Bukkit.getPlayer(nicknamekv.getValue())).getNick(true)); //Tabcomplete with the correct case } } @@ -154,7 +155,7 @@ public class PlayerListener implements Listener { if (flair.length() > 0) e.addInfo("/r/TheButton flair: " + flair); } - e.addInfo(String.format("Respect: %.2f", cp.getF())); + e.addInfo(String.format("Respect: %.2f", cp.getF())); } catch (Exception ex) { TBMCCoreAPI.SendException("Error while providing chat info for player " + e.getPlayer().getFileName(), ex); } @@ -166,31 +167,20 @@ public class PlayerListener implements Listener { if (e.isCancelled()) return; HistoryCommand.addChatMessage(e.getCm(), e.getChannel()); - e.setCancelled(ChatProcessing.ProcessChat(e)); + e.setCancelled(FormatterComponent.handleChat(e)); } catch (NoClassDefFoundError | Exception ex) { // Weird things can happen - val str = "§c!§r[" + e.getChannel().DisplayName().get() + "] <" - + ThorpeUtils.getDisplayName(e.getSender()) + "> " + e.getMessage(); - for (Player p : Bukkit.getOnlinePlayers()) - if (e.shouldSendTo(p)) - p.sendMessage(str); - Bukkit.getConsoleSender().sendMessage(str); + ChatUtils.sendChatMessage(e, s -> "§c!§r" + s); TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex); } } - @EventHandler - public void onChannelRegistered(ChatChannelRegisterEvent e) { - if (!e.getChannel().isGlobal() && PluginMain.SB.getObjective(e.getChannel().ID) == null) // Not global chat and doesn't exist yet - PluginMain.SB.registerNewObjective(e.getChannel().ID, "dummy"); - } - @EventHandler public void onNickChange(NickChangeEvent e) { - String nick = e.getValue(); - if (nick == null) - nicknames.inverse().remove(e.getAffected().getBase().getUniqueId()); - else - nicknames.inverse().forcePut(e.getAffected().getBase().getUniqueId(), ChatColor.stripColor(nick).toLowerCase()); + String nick = e.getValue(); + if (nick == null) + nicknames.inverse().remove(e.getAffected().getBase().getUniqueId()); + else + nicknames.inverse().forcePut(e.getAffected().getBase().getUniqueId(), ChatColor.stripColor(nick).toLowerCase()); Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> { TownColorComponent.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d618f6b..105abc9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,4 +1,4 @@ -name: Thorpe-Chat +name: Chroma-Chat main: buttondevteam.chat.PluginMain version: 4.0 commands: @@ -34,7 +34,7 @@ author: NorbiPeti depend: - Essentials - Vault -- ThorpeCore +- ChromaCore soft-depend: - Minigames - Dynmap-Towny diff --git a/src/test/java/buttondevteam/chat/ChatFormatIT.java b/src/test/java/buttondevteam/chat/components/formatter/ChatFormatIT.java similarity index 86% rename from src/test/java/buttondevteam/chat/ChatFormatIT.java rename to src/test/java/buttondevteam/chat/components/formatter/ChatFormatIT.java index 839942f..438155d 100644 --- a/src/test/java/buttondevteam/chat/ChatFormatIT.java +++ b/src/test/java/buttondevteam/chat/components/formatter/ChatFormatIT.java @@ -1,17 +1,21 @@ -package buttondevteam.chat; +package buttondevteam.chat.components.formatter; +import buttondevteam.chat.ChatUtils; +import buttondevteam.chat.ObjectTestRunner; import buttondevteam.chat.ObjectTestRunner.Objects; +import buttondevteam.chat.PluginMain; import buttondevteam.chat.commands.ucmds.admin.DebugCommand; -import buttondevteam.chat.formatting.ChatFormatter; -import buttondevteam.chat.formatting.TellrawEvent; -import buttondevteam.chat.formatting.TellrawEvent.ClickAction; -import buttondevteam.chat.formatting.TellrawEvent.HoverAction; -import buttondevteam.chat.formatting.TellrawPart; +import buttondevteam.chat.components.formatter.formatting.ChatFormatter; +import buttondevteam.chat.components.formatter.formatting.TellrawEvent; +import buttondevteam.chat.components.formatter.formatting.TellrawEvent.ClickAction; +import buttondevteam.chat.components.formatter.formatting.TellrawEvent.HoverAction; +import buttondevteam.chat.components.formatter.formatting.TellrawPart; import buttondevteam.core.TestPrepare; import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.chat.Color; import net.milkbowl.vault.permission.Permission; import org.bukkit.command.CommandSender; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -19,8 +23,6 @@ import org.mockito.Mockito; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; - @RunWith(ObjectTestRunner.class) public class ChatFormatIT { @Objects @@ -91,16 +93,16 @@ public class ChatFormatIT { @Test public void testMessage() { - ArrayList cfs = ChatProcessing.addFormatters(Color.White); - final String chid = ChatProcessing.getChannelID(Channel.GlobalChat, ChatProcessing.MCORIGIN); - final TellrawPart tp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatProcessing.MCORIGIN); - ChatFormatter.Combine(cfs, message, tp); + ArrayList cfs = ChatProcessing.addFormatters(Color.White, p -> true); + final String chid = ChatProcessing.getChannelID(Channel.GlobalChat, ChatUtils.MCORIGIN); + final TellrawPart tp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); + ChatFormatter.Combine(cfs, message, tp, null); System.out.println("Testing: " + message); // System.out.println(ChatProcessing.toJson(tp)); - final TellrawPart expectedtp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatProcessing.MCORIGIN); + final TellrawPart expectedtp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); // System.out.println("Raw: " + ChatProcessing.toJson(expectedtp)); for (TellrawPart extra : extras) expectedtp.addExtra(extra); - assertEquals(ChatProcessing.toJson(expectedtp), ChatProcessing.toJson(tp)); + Assert.assertEquals(ChatProcessing.toJson(expectedtp), ChatProcessing.toJson(tp)); } }