From be29caa904fcaa9e5d5304b743ec2086ba4a2afe Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 4 Jan 2019 01:11:15 +0100 Subject: [PATCH 1/7] Added handler for Towny logger Listening for Towny events and sending it to our system --- .../buttondevteam/chat/ChatProcessing.java | 2 - .../java/buttondevteam/chat/PluginMain.java | 853 +++++++++--------- .../chat/components/TownyAnnouncer.java | 56 ++ .../chat/components/TownyComponent.java | 15 + 4 files changed, 498 insertions(+), 428 deletions(-) create mode 100644 src/main/java/buttondevteam/chat/components/TownyAnnouncer.java create mode 100644 src/main/java/buttondevteam/chat/components/TownyComponent.java diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index 77d1f03..5867e8c 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -257,14 +257,12 @@ public class ChatProcessing { namesb.append(")"); StringBuilder nicksb = new StringBuilder("(?i)("); boolean addNickFormatter = false; - int index = 0; 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) } - index++; } nicksb.deleteCharAt(nicksb.length() - 1); nicksb.append(")"); diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index b02f678..de05ca8 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -1,426 +1,427 @@ -package buttondevteam.chat; - -import buttondevteam.chat.commands.YeehawCommand; -import buttondevteam.chat.commands.ucmds.TownColorCommand; -import buttondevteam.chat.listener.PlayerJoinLeaveListener; -import buttondevteam.chat.listener.PlayerListener; -import buttondevteam.chat.listener.TownyListener; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.Channel; -import buttondevteam.lib.chat.Channel.RecipientTestResult; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.TBMCPlayerBase; -import com.earth2me.essentials.Essentials; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.palmergames.bukkit.towny.Towny; -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 net.milkbowl.vault.chat.Chat; -import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.permission.Permission; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scoreboard.Scoreboard; -import org.dynmap.towny.DTBridge; -import org.dynmap.towny.DynmapTownyPlugin; -import org.htmlcleaner.HtmlCleaner; -import org.htmlcleaner.TagNode; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.net.UnknownHostException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. - // A user, which flair isn't obtainable: - // https://www.reddit.com/r/thebutton/comments/31c32v/i_pressed_the_button_without_really_thinking/ - public static PluginMain Instance; - public static ConsoleCommandSender Console; - private final static String FlairThreadURL = "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"; - - public static Scoreboard SB; - public static TownyUniverse TU; - private static ArrayList Towns; - private static ArrayList Nations; - - public static Channel TownChat; - public static Channel NationChat; - private static Channel RPChannel; - - /** - *

- * This variable is used as a cache for flair state checking when reading the flair thread. - *

- *

- * It's used because normally it has to load all associated player files every time to read the flair state - *

- */ - private Set PlayersWithFlairs = new HashSet<>(); - - // Fired when plugin is first enabled - @Override - public void onEnable() { - Instance = this; - PluginMain.essentials = (Essentials) (Bukkit.getPluginManager().getPlugin("Essentials")); - - TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); - TBMCCoreAPI.RegisterEventsForExceptions(new PlayerJoinLeaveListener(), this); - TBMCCoreAPI.RegisterEventsForExceptions(new TownyListener(), this); - TBMCChatAPI.AddCommands(this, YeehawCommand.class); - Console = this.getServer().getConsoleSender(); - LoadFiles(); - - SB = getServer().getScoreboardManager().getMainScoreboard(); // Main can be detected with @a[score_...] - TU = ((Towny) Bukkit.getPluginManager().getPlugin("Towny")).getTownyUniverse(); - Towns = new ArrayList<>(TU.getTownsMap().values()); // Creates a snapshot of towns, new towns will be added when needed - Nations = new ArrayList<>(TU.getNationsMap().values()); // Same here but with nations - - TownColors.keySet().removeIf(t -> !TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns - NationColor.keySet().removeIf(n -> !TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations - - TBMCChatAPI.RegisterChatChannel( - TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false))); - TBMCChatAPI.RegisterChatChannel( - NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true))); - TBMCChatAPI.RegisterChatChannel(RPChannel = new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global - - Bukkit.getScheduler().runTask(this, () -> { - val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); - if (dtp == null) - return; - for (val entry : TownColors.entrySet()) - setTownColor(dtp, buttondevteam.chat.commands.ucmds.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue()); - }); - - if (!setupEconomy() || !setupPermissions()) - TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up economy or permissions!")); - - new Thread(this::FlairGetterThreadMethod).start(); - new Thread(new AnnouncerThread()).start(); - } - - /** - * Sets a town's color on Dynmap. - * - * @param dtp A reference for the Dynmap-Towny plugin - * @param town The town's name using the correct casing - * @param colors The town's colors - */ - public static void setTownColor(DynmapTownyPlugin dtp, String town, Color[] colors) { - Function c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue(); - try { - DTBridge.setTownColor(dtp, town, c2i.apply(colors[0]), - c2i.apply(colors.length > 1 ? colors[1] : colors[0])); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e); - } - } - - public Boolean stop = false; - public static Essentials essentials = null; - - // Fired when plugin is disabled - @Override - public void onDisable() { - SaveFiles(); - stop = true; - } - - private void FlairGetterThreadMethod() { - int errorcount = 0; - while (!stop) { - try { - String body = TBMCCoreAPI.DownloadString(FlairThreadURL + ".json?limit=1000"); - JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data") - .getAsJsonObject().get("children").getAsJsonArray(); - for (Object obj : json) { - JsonObject item = (JsonObject) obj; - String author = item.get("data").getAsJsonObject().get("author").getAsString(); - String ign = item.get("data").getAsJsonObject().get("body").getAsString(); - int start = ign.indexOf("IGN:") + "IGN:".length(); - if (start == -1 + "IGN:".length()) - continue; - int end = ign.indexOf(' ', start); - if (end == -1 || end == start) - end = ign.indexOf('\n', start); - if (end == -1 || end == start) - ign = ign.substring(start); - else - ign = ign.substring(start, end); - ign = ign.trim(); - if (PlayersWithFlairs.contains(ign)) - continue; - try (ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class)) { // Loads player file - if (mp == null) - continue; - /* - * if (!JoinedBefore(mp, 2015, 6, 5)) continue; - */ - if (!mp.UserNames().contains(author)) - mp.UserNames().add(author); - if (mp.FlairState().get().equals(FlairStates.NoComment)) { - mp.FlairState().set(FlairStates.Commented); - ConfirmUserMessage(mp); - } - PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted - } - } - } catch (Exception e) { - errorcount++; - if (errorcount >= 10) { - errorcount = 0; - if (!e.getMessage().contains("Server returned HTTP response code") - && !(e instanceof UnknownHostException)) - TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e); - } - } - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - - public void DownloadFlair(ChatPlayer mp) throws IOException { - String[] flairdata = TBMCCoreAPI - .DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName().get()) - .replace("\"", "").split(":"); - String flair; - if (flairdata.length > 1) - flair = flairdata[1]; - else - flair = ""; - String flairclass; - if (flairdata.length > 2) - flairclass = flairdata[2]; - else - flairclass = "unknown"; - SetFlair(mp, flair, flairclass, mp.UserName().get()); - } - - private void SetFlair(ChatPlayer p, String text, String flairclass, String username) { - p.UserName().set(username); - p.FlairState().set(FlairStates.Recognised); - switch (flairclass) { - case "cheater": - p.SetFlair(Short.parseShort(text), true); - return; - case "unknown": - try { - if (CheckForJoinDate(p)) { - if (text.equals("-1")) // If true, only non-presser/can't press; if false, any flair (but we can still detect can't press) - p.SetFlair(ChatPlayer.FlairTimeNonPresser); - else - p.SetFlair(ChatPlayer.FlairTimeNone); // Flair unknown - } else { - p.SetFlair(ChatPlayer.FlairTimeCantPress); - } - } catch (Exception e) { - p.FlairState().set(FlairStates.Commented); // Flair unknown - p.SetFlair(ChatPlayer.FlairTimeNone); - TBMCCoreAPI.SendException("Error while checking join date for player " + p.PlayerName() + "!", e); - } - return; - default: - break; - } - p.SetFlair(Short.parseShort(text)); - } - - private static boolean CheckForJoinDate(ChatPlayer mp) throws Exception { - return JoinedBefore(mp, 2015, 4, 1); - } - - private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception { - URL url = new URL("https://www.reddit.com/u/" + mp.UserName()); - URLConnection con = url.openConnection(); - con.setRequestProperty("User-Agent", "TheButtonAutoFlair"); - InputStream in = con.getInputStream(); - HtmlCleaner cleaner = new HtmlCleaner(); - TagNode node = cleaner.clean(in); - - node = node.getElementsByAttValue("class", "age", true, true)[0]; - node = node.getElementsByName("time", false)[0]; - String joindate = node.getAttributeByName("datetime"); - SimpleDateFormat parserSDF = new SimpleDateFormat("yyyy-MM-dd"); - joindate = joindate.split("T")[0]; - Date date = parserSDF.parse(joindate); - return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day) - .build().getTime()); - } - - public static void ConfirmUserMessage(ChatPlayer mp) { - Player p = Bukkit.getPlayer(mp.getUUID()); - if (mp.FlairState().get().equals(FlairStates.Commented) && p != null) - if (mp.UserNames().size() > 1) - p.sendMessage( - "§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r"); - else - p.sendMessage("§9A Reddit user commented your name. Is that you?§r §6Type /u accept or /u ignore§r"); - } - - public static ArrayList AnnounceMessages = new ArrayList<>(); - public static int AnnounceTime = 15 * 60 * 1000; - /** - * Names lowercased - */ - public static Map TownColors = new HashMap<>(); - /** - * Names lowercased - nation color gets added to town colors when needed - */ - public static Map NationColor = new HashMap<>(); - - @SuppressWarnings("unchecked") - private static void LoadFiles() { - PluginMain.Instance.getLogger().info("Loading files..."); - try { - File file = new File("TBMC/chatsettings.yml"); - if (file.exists()) { - YamlConfiguration yc = new YamlConfiguration(); - yc.load(file); - PlayerListener.NotificationSound = yc.getString("notificationsound"); - PlayerListener.NotificationPitch = yc.getDouble("notificationpitch"); - AnnounceTime = yc.getInt("announcetime", 15 * 60 * 1000); - AnnounceMessages.addAll(yc.getStringList("announcements")); - PlayerListener.AlphaDeaths = yc.getInt("alphadeaths"); - val cs = yc.getConfigurationSection("towncolors"); - if (cs != null) - TownColors.putAll(cs.getValues(true).entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, v -> ((List) v.getValue()).stream() - .map(Color::valueOf).toArray(Color[]::new)))); - TownColorCommand.ColorCount = (byte) yc.getInt("towncolorcount", 1); - val ncs = yc.getConfigurationSection("nationcolors"); - if (ncs != null) - NationColor.putAll(ncs.getValues(true).entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue())))); - PluginMain.Instance.getLogger().info("Loaded files!"); - } else - PluginMain.Instance.getLogger().info("No files to load, first run probably."); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while loading chat files!", e); - } - } - - public static void SaveFiles() { - PluginMain.Instance.getLogger().info("Saving files..."); - try { - File file = new File("TBMC/chatsettings.yml"); - YamlConfiguration yc = new YamlConfiguration(); - yc.set("notificationsound", PlayerListener.NotificationSound); - yc.set("notificationpitch", PlayerListener.NotificationPitch); - yc.set("announcetime", AnnounceTime); - yc.set("announcements", AnnounceMessages); - yc.set("alphadeaths", PlayerListener.AlphaDeaths); - yc.createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, - v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); - yc.set("towncolorcount", TownColorCommand.ColorCount); - yc.createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, - v -> v.getValue().toString()))); - yc.save(file); - PluginMain.Instance.getLogger().info("Saved files!"); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while loading chat files!", e); - } - } - - public static Permission permission = null; - public static Economy economy = null; - public static Chat chat = null; - - private boolean setupPermissions() { - RegisteredServiceProvider permissionProvider = getServer().getServicesManager() - .getRegistration(net.milkbowl.vault.permission.Permission.class); - if (permissionProvider != null) { - permission = permissionProvider.getProvider(); - } - return (permission != null); - } - - private boolean setupChat() { - RegisteredServiceProvider chatProvider = getServer().getServicesManager() - .getRegistration(net.milkbowl.vault.chat.Chat.class); - if (chatProvider != null) { - chat = chatProvider.getProvider(); - } - - return (chat != null); - } - - private boolean setupEconomy() { - RegisteredServiceProvider economyProvider = getServer().getServicesManager() - .getRegistration(net.milkbowl.vault.economy.Economy.class); - if (economyProvider != null) { - economy = economyProvider.getProvider(); - } - - return (economy != null); - } - - /** - * Return the error message for the message sender if they can't send it and the score - */ - private static RecipientTestResult checkTownNationChat(CommandSender sender, boolean nationchat) { - if (!(sender instanceof Player)) - return new RecipientTestResult("§cYou are not a player!"); - Resident resident = PluginMain.TU.getResidentMap().get(sender.getName().toLowerCase()); - RecipientTestResult result = checkTownNationChatInternal(sender, nationchat, resident); - if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it - result = new RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably - return result; - } - - private static RecipientTestResult checkTownNationChatInternal(CommandSender sender, boolean nationchat, - Resident resident) { - try { - /* - * p.sendMessage(String.format("[SPY-%s] - %s: %s", channel.DisplayName, ((Player) sender).getDisplayName(), message)); - */ - Town town = null; - if (resident != null && resident.hasTown()) - town = resident.getTown(); - if (town == null) - return new RecipientTestResult("You aren't in a town."); - Nation nation = null; - int index; - if (nationchat) { - if (town.hasNation()) - nation = town.getNation(); - if (nation == null) - return new RecipientTestResult("Your town isn't in a nation."); - index = PluginMain.Nations.indexOf(nation); - if (index < 0) { - PluginMain.Nations.add(nation); - index = PluginMain.Nations.size() - 1; - } - } else { - index = PluginMain.Towns.indexOf(town); - if (index < 0) { - PluginMain.Towns.add(town); - index = PluginMain.Towns.size() - 1; - } - } - return new RecipientTestResult(index, nationchat ? nation.getName() : town.getName()); - } catch (NotRegisteredException e) { - return new RecipientTestResult("You (probably) aren't knwon by Towny! (Not in a town)"); - } - } -} +package buttondevteam.chat; + +import buttondevteam.chat.commands.YeehawCommand; +import buttondevteam.chat.commands.ucmds.TownColorCommand; +import buttondevteam.chat.listener.PlayerJoinLeaveListener; +import buttondevteam.chat.listener.PlayerListener; +import buttondevteam.chat.listener.TownyListener; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.Channel; +import buttondevteam.lib.chat.Channel.RecipientTestResult; +import buttondevteam.lib.chat.Color; +import buttondevteam.lib.chat.TBMCChatAPI; +import buttondevteam.lib.player.TBMCPlayerBase; +import com.earth2me.essentials.Essentials; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.palmergames.bukkit.towny.Towny; +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 net.milkbowl.vault.chat.Chat; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scoreboard.Scoreboard; +import org.dynmap.towny.DTBridge; +import org.dynmap.towny.DynmapTownyPlugin; +import org.htmlcleaner.HtmlCleaner; +import org.htmlcleaner.TagNode; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. + // A user, which flair isn't obtainable: + // https://www.reddit.com/r/thebutton/comments/31c32v/i_pressed_the_button_without_really_thinking/ + public static PluginMain Instance; + public static ConsoleCommandSender Console; + private final static String FlairThreadURL = "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"; + + public static Scoreboard SB; + public static TownyUniverse TU; + private static ArrayList Towns; + private static ArrayList Nations; + + public static Channel TownChat; + public static Channel NationChat; + private static Channel RPChannel; + + /** + *

+ * This variable is used as a cache for flair state checking when reading the flair thread. + *

+ *

+ * It's used because normally it has to load all associated player files every time to read the flair state + *

+ */ + private Set PlayersWithFlairs = new HashSet<>(); + + // Fired when plugin is first enabled + @Override + public void onEnable() { + Instance = this; + PluginMain.essentials = (Essentials) (Bukkit.getPluginManager().getPlugin("Essentials")); + + TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); + TBMCCoreAPI.RegisterEventsForExceptions(new PlayerJoinLeaveListener(), this); + TBMCCoreAPI.RegisterEventsForExceptions(new TownyListener(), this); + TBMCChatAPI.AddCommands(this, YeehawCommand.class); + Console = this.getServer().getConsoleSender(); + LoadFiles(); + + SB = getServer().getScoreboardManager().getMainScoreboard(); // Main can be detected with @a[score_...] + TU = ((Towny) Bukkit.getPluginManager().getPlugin("Towny")).getTownyUniverse(); + 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 + + TownColors.keySet().removeIf(t -> !TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns + NationColor.keySet().removeIf(n -> !TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations + + TBMCChatAPI.RegisterChatChannel( + TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false))); + TBMCChatAPI.RegisterChatChannel( + NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true))); + TBMCChatAPI.RegisterChatChannel(RPChannel = new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global + + Bukkit.getScheduler().runTask(this, () -> { + val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); + if (dtp == null) + return; + for (val entry : TownColors.entrySet()) + setTownColor(dtp, buttondevteam.chat.commands.ucmds.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue()); + }); + + if (!setupEconomy() || !setupPermissions()) + TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up economy or permissions!")); + + new Thread(this::FlairGetterThreadMethod).start(); + new Thread(new AnnouncerThread()).start(); + } + + /** + * Sets a town's color on Dynmap. + * + * @param dtp A reference for the Dynmap-Towny plugin + * @param town The town's name using the correct casing + * @param colors The town's colors + */ + public static void setTownColor(DynmapTownyPlugin dtp, String town, Color[] colors) { + Function c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue(); + try { + DTBridge.setTownColor(dtp, town, c2i.apply(colors[0]), + c2i.apply(colors.length > 1 ? colors[1] : colors[0])); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e); + } + } + + public Boolean stop = false; + public static Essentials essentials = null; + + // Fired when plugin is disabled + @Override + public void onDisable() { + SaveFiles(); + stop = true; + } + + private void FlairGetterThreadMethod() { + int errorcount = 0; + while (!stop) { + try { + String body = TBMCCoreAPI.DownloadString(FlairThreadURL + ".json?limit=1000"); + JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data") + .getAsJsonObject().get("children").getAsJsonArray(); + for (Object obj : json) { + JsonObject item = (JsonObject) obj; + String author = item.get("data").getAsJsonObject().get("author").getAsString(); + String ign = item.get("data").getAsJsonObject().get("body").getAsString(); + int start = ign.indexOf("IGN:") + "IGN:".length(); + if (start == -1 + "IGN:".length()) + continue; + int end = ign.indexOf(' ', start); + if (end == -1 || end == start) + end = ign.indexOf('\n', start); + if (end == -1 || end == start) + ign = ign.substring(start); + else + ign = ign.substring(start, end); + ign = ign.trim(); + if (PlayersWithFlairs.contains(ign)) + continue; + try (ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class)) { // Loads player file + if (mp == null) + continue; + /* + * if (!JoinedBefore(mp, 2015, 6, 5)) continue; + */ + if (!mp.UserNames().contains(author)) + mp.UserNames().add(author); + if (mp.FlairState().get().equals(FlairStates.NoComment)) { + mp.FlairState().set(FlairStates.Commented); + ConfirmUserMessage(mp); + } + PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted + } + } + } catch (Exception e) { + errorcount++; + if (errorcount >= 10) { + errorcount = 0; + if (!e.getMessage().contains("Server returned HTTP response code") + && !(e instanceof UnknownHostException)) + TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e); + } + } + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + public void DownloadFlair(ChatPlayer mp) throws IOException { + String[] flairdata = TBMCCoreAPI + .DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName().get()) + .replace("\"", "").split(":"); + String flair; + if (flairdata.length > 1) + flair = flairdata[1]; + else + flair = ""; + String flairclass; + if (flairdata.length > 2) + flairclass = flairdata[2]; + else + flairclass = "unknown"; + SetFlair(mp, flair, flairclass, mp.UserName().get()); + } + + private void SetFlair(ChatPlayer p, String text, String flairclass, String username) { + p.UserName().set(username); + p.FlairState().set(FlairStates.Recognised); + switch (flairclass) { + case "cheater": + p.SetFlair(Short.parseShort(text), true); + return; + case "unknown": + try { + if (CheckForJoinDate(p)) { + if (text.equals("-1")) // If true, only non-presser/can't press; if false, any flair (but we can still detect can't press) + p.SetFlair(ChatPlayer.FlairTimeNonPresser); + else + p.SetFlair(ChatPlayer.FlairTimeNone); // Flair unknown + } else { + p.SetFlair(ChatPlayer.FlairTimeCantPress); + } + } catch (Exception e) { + p.FlairState().set(FlairStates.Commented); // Flair unknown + p.SetFlair(ChatPlayer.FlairTimeNone); + TBMCCoreAPI.SendException("Error while checking join date for player " + p.PlayerName() + "!", e); + } + return; + default: + break; + } + p.SetFlair(Short.parseShort(text)); + } + + private static boolean CheckForJoinDate(ChatPlayer mp) throws Exception { + return JoinedBefore(mp, 2015, 4, 1); + } + + private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception { + URL url = new URL("https://www.reddit.com/u/" + mp.UserName()); + URLConnection con = url.openConnection(); + con.setRequestProperty("User-Agent", "TheButtonAutoFlair"); + InputStream in = con.getInputStream(); + HtmlCleaner cleaner = new HtmlCleaner(); + TagNode node = cleaner.clean(in); + + node = node.getElementsByAttValue("class", "age", true, true)[0]; + node = node.getElementsByName("time", false)[0]; + String joindate = node.getAttributeByName("datetime"); + SimpleDateFormat parserSDF = new SimpleDateFormat("yyyy-MM-dd"); + joindate = joindate.split("T")[0]; + Date date = parserSDF.parse(joindate); + return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day) + .build().getTime()); + } + + public static void ConfirmUserMessage(ChatPlayer mp) { + Player p = Bukkit.getPlayer(mp.getUUID()); + if (mp.FlairState().get().equals(FlairStates.Commented) && p != null) + if (mp.UserNames().size() > 1) + p.sendMessage( + "§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r"); + else + p.sendMessage("§9A Reddit user commented your name. Is that you?§r §6Type /u accept or /u ignore§r"); + } + + public static ArrayList AnnounceMessages = new ArrayList<>(); + public static int AnnounceTime = 15 * 60 * 1000; + /** + * Names lowercased + */ + public static Map TownColors = new HashMap<>(); + /** + * Names lowercased - nation color gets added to town colors when needed + */ + public static Map NationColor = new HashMap<>(); + + @SuppressWarnings("unchecked") + private static void LoadFiles() { + PluginMain.Instance.getLogger().info("Loading files..."); + try { + File file = new File("TBMC/chatsettings.yml"); + if (file.exists()) { + YamlConfiguration yc = new YamlConfiguration(); + yc.load(file); + PlayerListener.NotificationSound = yc.getString("notificationsound"); + PlayerListener.NotificationPitch = yc.getDouble("notificationpitch"); + AnnounceTime = yc.getInt("announcetime", 15 * 60 * 1000); + AnnounceMessages.addAll(yc.getStringList("announcements")); + PlayerListener.AlphaDeaths = yc.getInt("alphadeaths"); + val cs = yc.getConfigurationSection("towncolors"); + if (cs != null) + TownColors.putAll(cs.getValues(true).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, v -> ((List) v.getValue()).stream() + .map(Color::valueOf).toArray(Color[]::new)))); + TownColorCommand.ColorCount = (byte) yc.getInt("towncolorcount", 1); + val ncs = yc.getConfigurationSection("nationcolors"); + if (ncs != null) + NationColor.putAll(ncs.getValues(true).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue())))); + PluginMain.Instance.getLogger().info("Loaded files!"); + } else + PluginMain.Instance.getLogger().info("No files to load, first run probably."); + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while loading chat files!", e); + } + } + + public static void SaveFiles() { + PluginMain.Instance.getLogger().info("Saving files..."); + try { + File file = new File("TBMC/chatsettings.yml"); + YamlConfiguration yc = new YamlConfiguration(); + yc.set("notificationsound", PlayerListener.NotificationSound); + yc.set("notificationpitch", PlayerListener.NotificationPitch); + yc.set("announcetime", AnnounceTime); + yc.set("announcements", AnnounceMessages); + yc.set("alphadeaths", PlayerListener.AlphaDeaths); + yc.createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); + yc.set("towncolorcount", TownColorCommand.ColorCount); + yc.createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + v -> v.getValue().toString()))); + yc.save(file); + PluginMain.Instance.getLogger().info("Saved files!"); + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while loading chat files!", e); + } + } + + public static Permission permission = null; + public static Economy economy = null; + public static Chat chat = null; + + private boolean setupPermissions() { + RegisteredServiceProvider permissionProvider = getServer().getServicesManager() + .getRegistration(net.milkbowl.vault.permission.Permission.class); + if (permissionProvider != null) { + permission = permissionProvider.getProvider(); + } + return (permission != null); + } + + private boolean setupChat() { + RegisteredServiceProvider chatProvider = getServer().getServicesManager() + .getRegistration(net.milkbowl.vault.chat.Chat.class); + if (chatProvider != null) { + chat = chatProvider.getProvider(); + } + + return (chat != null); + } + + private boolean setupEconomy() { + RegisteredServiceProvider economyProvider = getServer().getServicesManager() + .getRegistration(net.milkbowl.vault.economy.Economy.class); + if (economyProvider != null) { + economy = economyProvider.getProvider(); + } + + return (economy != null); + } + + /** + * Return the error message for the message sender if they can't send it and the score + */ + private static RecipientTestResult checkTownNationChat(CommandSender sender, boolean nationchat) { + if (!(sender instanceof Player)) + return new RecipientTestResult("§cYou are not a player!"); + Resident resident = PluginMain.TU.getResidentMap().get(sender.getName().toLowerCase()); + RecipientTestResult result = checkTownNationChatInternal(sender, nationchat, resident); + if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it + result = new RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably + return result; + } + + private static RecipientTestResult checkTownNationChatInternal(CommandSender sender, boolean nationchat, + Resident resident) { + try { + /* + * p.sendMessage(String.format("[SPY-%s] - %s: %s", channel.DisplayName, ((Player) sender).getDisplayName(), message)); + */ + Town town = null; + if (resident != null && resident.hasTown()) + town = resident.getTown(); + if (town == null) + return new RecipientTestResult("You aren't in a town."); + Nation nation = null; + int index; + if (nationchat) { + if (town.hasNation()) + nation = town.getNation(); + if (nation == null) + return new RecipientTestResult("Your town isn't in a nation."); + index = getTownNationIndex(nation.getName(), true); + } else + index = getTownNationIndex(town.getName(), false); + return new RecipientTestResult(index, nationchat ? nation.getName() : town.getName()); + } catch (NotRegisteredException e) { + return new RecipientTestResult("You (probably) aren't knwon by Towny! (Not in a town)"); + } + } + + public static int getTownNationIndex(String name, boolean nation) { + val list = nation ? Nations : Towns; + int index = list.indexOf(name); + if (index < 0) { + list.add(name); + index = list.size() - 1; + } + return index; + } +} diff --git a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java new file mode 100644 index 0000000..3ad6c2a --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java @@ -0,0 +1,56 @@ +package buttondevteam.chat.components; + +import buttondevteam.chat.PluginMain; +import buttondevteam.lib.chat.Channel; +import buttondevteam.lib.chat.TBMCChatAPI; +import com.palmergames.bukkit.towny.TownyLogger; +import lombok.val; + +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() { + @Override + public void publish(LogRecord logRecord) { + if (logRecord.getMessage() == null) return; + val m = LOG_TYPE_PATTERN.matcher(logRecord.getMessage()); + if (!m.find()) return; + String groupID = m.group(2); //The group ID is correctly cased + switch (String.valueOf(m.group(1))) { //valueOf: Handles null + case "Town": + TBMCChatAPI.SendSystemMessage(PluginMain.TownChat, + new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, false), groupID), + logRecord.getMessage()); //TODO: This will also send it in Minecraft + break; + case "Nation": + TBMCChatAPI.SendSystemMessage(PluginMain.NationChat, + new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, true), groupID), + logRecord.getMessage()); //TODO: This will also send it in Minecraft + break; + case "Global": //TODO + break; + } + } + + @Override + public void flush() { + + } + + @Override + public void close() throws SecurityException { + + } + }; + + public static void setup() { + TownyLogger.log.addHandler(HANDLER); + } + + public static void setdown() { + TownyLogger.log.removeHandler(HANDLER); + } +} diff --git a/src/main/java/buttondevteam/chat/components/TownyComponent.java b/src/main/java/buttondevteam/chat/components/TownyComponent.java new file mode 100644 index 0000000..3f1f83e --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/TownyComponent.java @@ -0,0 +1,15 @@ +package buttondevteam.chat.components; + +import buttondevteam.lib.architecture.Component; + +public class TownyComponent extends Component { //TODO: Register component + @Override + protected void enable() { + TownyAnnouncer.setup(); + } + + @Override + protected void disable() { + TownyAnnouncer.setdown(); + } +} From bfe7d48760fbe623106608b933e2feb3ea51d1c2 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 9 Jan 2019 18:57:21 +0100 Subject: [PATCH 2/7] Towny logger works TBMCPlugins/DiscordPlugin#81 --- src/main/java/buttondevteam/chat/ChatProcessing.java | 2 +- src/main/java/buttondevteam/chat/PluginMain.java | 6 ++++++ .../chat/components/TownyAnnouncer.java | 12 ++++++++---- .../chat/components/TownyComponent.java | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index 5867e8c..e0cafa4 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -87,7 +87,7 @@ public class ChatProcessing { .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"}; - static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized + public static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized private ChatProcessing() { } diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index de05ca8..8c96781 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -2,10 +2,13 @@ package buttondevteam.chat; import buttondevteam.chat.commands.YeehawCommand; import buttondevteam.chat.commands.ucmds.TownColorCommand; +import buttondevteam.chat.components.TownColorComponent; +import buttondevteam.chat.components.TownyComponent; import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.chat.listener.PlayerListener; import buttondevteam.chat.listener.TownyListener; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.Channel.RecipientTestResult; import buttondevteam.lib.chat.Color; @@ -115,6 +118,9 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. new Thread(this::FlairGetterThreadMethod).start(); new Thread(new AnnouncerThread()).start(); + + Component.registerComponent(this, new TownyComponent()); + Component.registerComponent(this, new TownColorComponent()); } /** diff --git a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java index 3ad6c2a..fb777d7 100644 --- a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java +++ b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java @@ -1,5 +1,6 @@ package buttondevteam.chat.components; +import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.PluginMain; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.TBMCChatAPI; @@ -11,7 +12,7 @@ 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 Pattern LOG_TYPE_PATTERN = Pattern.compile("\\[(\\w+) (?:Msg|Message)](?: (\\w+):)?"); private static final Handler HANDLER = new Handler() { @Override public void publish(LogRecord logRecord) { @@ -23,14 +24,17 @@ public class TownyAnnouncer { case "Town": TBMCChatAPI.SendSystemMessage(PluginMain.TownChat, new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, false), groupID), - logRecord.getMessage()); //TODO: This will also send it in Minecraft + logRecord.getMessage(), ChatProcessing.MCORIGIN); break; case "Nation": TBMCChatAPI.SendSystemMessage(PluginMain.NationChat, new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, true), groupID), - logRecord.getMessage()); //TODO: This will also send it in Minecraft + logRecord.getMessage(), ChatProcessing.MCORIGIN); break; - case "Global": //TODO + case "Global": + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, + Channel.RecipientTestResult.ALL, + logRecord.getMessage(), ChatProcessing.MCORIGIN); break; } } diff --git a/src/main/java/buttondevteam/chat/components/TownyComponent.java b/src/main/java/buttondevteam/chat/components/TownyComponent.java index 3f1f83e..b176710 100644 --- a/src/main/java/buttondevteam/chat/components/TownyComponent.java +++ b/src/main/java/buttondevteam/chat/components/TownyComponent.java @@ -2,7 +2,7 @@ package buttondevteam.chat.components; import buttondevteam.lib.architecture.Component; -public class TownyComponent extends Component { //TODO: Register component +public class TownyComponent extends Component { @Override protected void enable() { TownyAnnouncer.setup(); From 8ccf3ee9d73e2fb5367535ed49362e05817518cc Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 10 Jan 2019 01:46:59 +0100 Subject: [PATCH 3/7] Guess what, configs --- .../buttondevteam/chat/components/TownColorComponent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/buttondevteam/chat/components/TownColorComponent.java b/src/main/java/buttondevteam/chat/components/TownColorComponent.java index b731ea7..8a82040 100644 --- a/src/main/java/buttondevteam/chat/components/TownColorComponent.java +++ b/src/main/java/buttondevteam/chat/components/TownColorComponent.java @@ -5,11 +5,11 @@ import buttondevteam.lib.architecture.ConfigData; public class TownColorComponent extends Component { public ConfigData colorCount() { //TODO - return getData("colorCount", (byte) 1, cc -> (byte) cc, cc -> (int) cc); + return getConfig().getData("colorCount", (byte) 1, cc -> (byte) cc, cc -> (int) cc); } public ConfigData useNationColors() { //TODO - return getData("useNationColors", true); + return getConfig().getData("useNationColors", true); } @Override From 25ce2a4c9f2f75365e68fe73eaf3cb15463f0bfc Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 12 Jan 2019 01:24:31 +0100 Subject: [PATCH 4/7] API changes --- .../buttondevteam/chat/ChatProcessing.java | 8 +- .../java/buttondevteam/chat/PluginMain.java | 4 +- .../chat/commands/UnlolCommand.java | 110 ++-- .../chat/commands/ucmds/HistoryCommand.java | 4 +- .../chat/components/TownyAnnouncer.java | 2 +- .../chat/listener/PlayerListener.java | 590 +++++++++--------- .../java/buttondevteam/chat/ChatFormatIT.java | 2 +- 7 files changed, 362 insertions(+), 358 deletions(-) diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index e0cafa4..5bcf174 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -7,10 +7,10 @@ import buttondevteam.chat.formatting.TellrawEvent; import buttondevteam.chat.formatting.TellrawPart; import buttondevteam.chat.formatting.TellrawSerializer; import buttondevteam.chat.listener.PlayerListener; +import buttondevteam.component.channel.Channel; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Priority; import buttondevteam.lib.chat.TellrawSerializableEnum; @@ -114,7 +114,7 @@ public class ChatProcessing { 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; + Color colormode = channel.Color().get(); if (mp != null && mp.OtherColorMode != null) colormode = mp.OtherColorMode; if (message.startsWith(">")) @@ -122,7 +122,7 @@ public class ChatProcessing { // If greentext, ignore channel or player colors ArrayList formatters = addFormatters(colormode); - if (colormode == channel.color && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color + if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color final AtomicInteger rpc = new AtomicInteger(0); formatters.add(ChatFormatter.builder().color(colormode).onmatch((match, cf) -> { cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); @@ -233,7 +233,7 @@ public class ChatProcessing { } static String getChannelID(Channel channel, CommandSender sender, String origin) { - return ("[" + (MCORIGIN.equals(origin) ? "" : "§8" + origin.substring(0, 1) + "§r|") + channel.DisplayName) + return ("[" + (MCORIGIN.equals(origin) ? "" : "§8" + origin.substring(0, 1) + "§r|") + channel.DisplayName().get()) + "]"; } diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index 8c96781..157c743 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -7,10 +7,10 @@ import buttondevteam.chat.components.TownyComponent; import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.chat.listener.PlayerListener; import buttondevteam.chat.listener.TownyListener; +import buttondevteam.component.channel.Channel; +import buttondevteam.component.channel.Channel.RecipientTestResult; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.chat.Channel; -import buttondevteam.lib.chat.Channel.RecipientTestResult; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayerBase; diff --git a/src/main/java/buttondevteam/chat/commands/UnlolCommand.java b/src/main/java/buttondevteam/chat/commands/UnlolCommand.java index eb3db61..3c5d1de 100644 --- a/src/main/java/buttondevteam/chat/commands/UnlolCommand.java +++ b/src/main/java/buttondevteam/chat/commands/UnlolCommand.java @@ -1,55 +1,55 @@ -package buttondevteam.chat.commands; - -import buttondevteam.lib.TBMCChatEventBase; -import buttondevteam.lib.chat.Channel; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; -import lombok.Data; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; - -@CommandClass(modOnly = false) -public final class UnlolCommand extends TBMCCommandBase { - - public static Map Lastlol = new HashMap<>(); - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Unlol/unlaugh ----", - "This command is based on a joke between NorbiPeti and Ghostise", - "It will make the last person saying one of the recognized laugh strings blind for a few seconds", - "Note that you can only unlaugh laughs that weren't unlaughed before" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - LastlolData lol = Lastlol.values().stream().filter(lld -> lld.Chatevent.shouldSendTo(sender)) - .max(Comparator.comparingLong(lld -> lld.Loltime)).orElse(null); - if (lol == null) - return true; - if (lol.Lolowner instanceof Player) - ((Player) lol.Lolowner) - .addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 2 * 20, 5, false, false)); - String msg = (sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName()) - + (lol.Lolornot ? " unlolled " : " unlaughed ") - + (lol.Lolowner instanceof Player ? ((Player) lol.Lolowner).getDisplayName() : lol.Lolowner.getName()); - Bukkit.broadcastMessage(msg); - Lastlol.remove(lol.Chatevent.getChannel()); - return true; - } - - @Data - public static class LastlolData { - private boolean Lolornot; - private final CommandSender Lolowner; - private final TBMCChatEventBase Chatevent; - private final long Loltime; - } -} +package buttondevteam.chat.commands; + +import buttondevteam.component.channel.Channel; +import buttondevteam.lib.TBMCChatEventBase; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.TBMCCommandBase; +import lombok.Data; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +@CommandClass(modOnly = false) +public final class UnlolCommand extends TBMCCommandBase { + + public static Map Lastlol = new HashMap<>(); + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Unlol/unlaugh ----", + "This command is based on a joke between NorbiPeti and Ghostise", + "It will make the last person saying one of the recognized laugh strings blind for a few seconds", + "Note that you can only unlaugh laughs that weren't unlaughed before" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, String[] args) { + LastlolData lol = Lastlol.values().stream().filter(lld -> lld.Chatevent.shouldSendTo(sender)) + .max(Comparator.comparingLong(lld -> lld.Loltime)).orElse(null); + if (lol == null) + return true; + if (lol.Lolowner instanceof Player) + ((Player) lol.Lolowner) + .addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 2 * 20, 5, false, false)); + String msg = (sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName()) + + (lol.Lolornot ? " unlolled " : " unlaughed ") + + (lol.Lolowner instanceof Player ? ((Player) lol.Lolowner).getDisplayName() : lol.Lolowner.getName()); + Bukkit.broadcastMessage(msg); + Lastlol.remove(lol.Chatevent.getChannel()); + return true; + } + + @Data + public static class LastlolData { + private boolean Lolornot; + private final CommandSender Lolowner; + private final TBMCChatEventBase Chatevent; + private final long Loltime; + } +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java index e39600a..dc27b5c 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java @@ -1,6 +1,6 @@ package buttondevteam.chat.commands.ucmds; -import buttondevteam.lib.chat.Channel; +import buttondevteam.component.channel.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.CommandClass; import lombok.RequiredArgsConstructor; @@ -54,7 +54,7 @@ public class HistoryCommand extends UCommandBase { for (int i = Math.max(0, arr.length - 10); i < arr.length; i++) { HistoryEntry e = arr[i]; val cm = e.chatMessage; - sender.sendMessage("[" + e.channel.DisplayName + "] " + cm.getSender().getName() + ": " + cm.getMessage()); + sender.sendMessage("[" + e.channel.DisplayName().get() + "] " + cm.getSender().getName() + ": " + cm.getMessage()); sent.set(true); } if (!sent.get()) diff --git a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java index fb777d7..a368c83 100644 --- a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java +++ b/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java @@ -2,7 +2,7 @@ package buttondevteam.chat.components; import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.PluginMain; -import buttondevteam.lib.chat.Channel; +import buttondevteam.component.channel.Channel; import buttondevteam.lib.chat.TBMCChatAPI; import com.palmergames.bukkit.towny.TownyLogger; import lombok.val; diff --git a/src/main/java/buttondevteam/chat/listener/PlayerListener.java b/src/main/java/buttondevteam/chat/listener/PlayerListener.java index fd8dfb5..e077f8f 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerListener.java @@ -1,293 +1,297 @@ -package buttondevteam.chat.listener; - -import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.ChatProcessing; -import buttondevteam.chat.PluginMain; -import buttondevteam.chat.commands.ucmds.HistoryCommand; -import buttondevteam.lib.TBMCChatEvent; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.*; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.vexsoftware.votifier.model.Vote; -import com.vexsoftware.votifier.model.VotifierEvent; -import lombok.val; -import net.ess3.api.events.NickChangeEvent; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.*; -import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.help.HelpTopic; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitTask; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Map.Entry; -import java.util.Random; -import java.util.UUID; -import java.util.function.BiPredicate; - -public class PlayerListener implements Listener { - /** - * Does not contain format codes, lowercased - */ - public static BiMap nicknames = HashBiMap.create(); - - public static boolean Enable = false; - - public static int LoginWarningCountTotal = 5; - - public static String NotificationSound; - public static double NotificationPitch; - - public static boolean ShowRPTag = false; - - public final static String[] LaughStrings = new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}; - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerChat(AsyncPlayerChatEvent event) { - if (event.isCancelled()) - return; - ChatPlayer cp = TBMCPlayer.getPlayer(event.getPlayer().getUniqueId(), ChatPlayer.class); - TBMCChatAPI.SendChatMessage(ChatMessage.builder(event.getPlayer(), cp, event.getMessage()).build()); - event.setCancelled(true); // The custom event should only be cancelled when muted or similar - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void PlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (!event.isCancelled()) - event.setCancelled(onCommandPreprocess(event.getPlayer(), event.getMessage())); - } - - private boolean onCommandPreprocess(CommandSender sender, String message) { - if (message.length() < 2) - return false; - int index = message.indexOf(" "); - val mp = ChromaGamerBase.getFromSender(sender); - String cmd; - final BiPredicate checkchid = (chan, cmd1) -> cmd1.equalsIgnoreCase(chan.ID) || (chan.IDs != null && Arrays.stream(chan.IDs).anyMatch(cmd1::equalsIgnoreCase)); - if (index == -1) { // Only the command is run - if (!(sender instanceof Player || sender instanceof ConsoleCommandSender)) - return false; - // ^^ We can only store player or console channels - Directly sending to channels would still work if they had an event - cmd = sender instanceof ConsoleCommandSender ? message : message.substring(1); - for (Channel channel : Channel.getChannels()) { - if (checkchid.test(channel, cmd)) { - Channel oldch = mp.channel().get(); - if (oldch instanceof ChatRoom) - ((ChatRoom) oldch).leaveRoom(sender); - if (oldch.equals(channel)) - mp.channel().set(Channel.GlobalChat); - else { - mp.channel().set(channel); - if (channel instanceof ChatRoom) - ((ChatRoom) channel).joinRoom(sender); - } - sender.sendMessage("§6You are now talking in: §b" + mp.channel().get().DisplayName); - return true; - } - } - } else { // We have arguments - cmd = sender instanceof ConsoleCommandSender ? message.substring(0, index) : message.substring(1, index); - if (cmd.equalsIgnoreCase("tpahere")) { - Player player = Bukkit.getPlayer(message.substring(index + 1)); - if (player != null && sender instanceof Player) - player.sendMessage("§b" + ((Player) sender).getDisplayName() + " §bis in this world: " - + ((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); - Bukkit.broadcastMessage(String.format("* %s %s", sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName(), msg)); - return true; - } else { - sender.sendMessage("§cCan't use /minecraft:me while muted."); - return true; - } - } else if (cmd.equalsIgnoreCase("me")) { //Take over for Discord broadcast - if (!(sender instanceof Player) || !PluginMain.essentials.getUser((Player) sender).isMuted()) { - String msg = message.substring(index + 1); - Bukkit.broadcastMessage(String.format("§5* %s %s", sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName(), msg)); - return true; - } else { - sender.sendMessage("§cCan't use /me while muted."); - return true; - } - } else - for (Channel channel : Channel.getChannels()) { - if (checkchid.test(channel, cmd)) { //Apparently method references don't require final variables - TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, mp, message.substring(index + 1)).build(), channel); - return true; - } - } - // TODO: Target selectors - } - // We don't care if we have arguments - if (cmd.toLowerCase().startsWith("un")) { - for (HelpTopic ht : PluginMain.Instance.getServer().getHelpMap().getHelpTopics()) { - if (ht.getName().equalsIgnoreCase("/" + cmd)) - return false; - } - if (PluginMain.permission.has(sender, "tbmc.admin")) { - String s = cmd.substring(2); - Player target = Bukkit.getPlayer(message.substring(index + 1)); - if (target == null) { - sender.sendMessage("§cError: Player not found. (/un" + s + " )"); - return true; - } - target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10 * 20, 5, false, false)); - Bukkit.broadcastMessage( - (sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName()) + " un" + s - + "'d " + target.getDisplayName()); - return true; - } - } - return false; - } - - @EventHandler - public void onTabComplete(PlayerChatTabCompleteEvent e) { - 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 - } - } - - public static boolean ActiveF = false; - public static ChatPlayer FPlayer = null; - public static BukkitTask Ftask = null; - public static int AlphaDeaths; - public static ArrayList Fs = new ArrayList<>(); - - @EventHandler - public void onPlayerDeath(PlayerDeathEvent e) { - if (e.getEntity().getName().equals("Alpha_Bacca44")) - AlphaDeaths++; - // MinigamePlayer mgp = Minigames.plugin.pdata.getMinigamePlayer(e.getEntity()); - if (/* (mgp != null && !mgp.isInMinigame()) && */ new Random().nextBoolean()) { // Don't store Fs for NPCs - Runnable tt = () -> { - if (ActiveF) { - ActiveF = false; - if (FPlayer != null && FPlayer.FCount().get() < Integer.MAX_VALUE - 1) - FPlayer.FCount().set(FPlayer.FCount().get() + Fs.size()); - Bukkit.broadcastMessage("§b" + Fs.size() + " " + (Fs.size() == 1 ? "person" : "people") - + " paid their respects.§r"); - Fs.clear(); - } - }; - if (Ftask != null) { - Ftask.cancel(); - tt.run(); //Finish previous one - } - ActiveF = true; - Fs.clear(); - FPlayer = TBMCPlayer.getPlayer(e.getEntity().getUniqueId(), ChatPlayer.class); - FPlayer.FDeaths().set(FPlayer.FDeaths().get() + 1); - Bukkit.broadcastMessage("§bPress F to pay respects.§r"); - Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20); - } - } - - @EventHandler - @SuppressWarnings("deprecation") - public void onVotifierEvent(VotifierEvent event) { //TODO: Move to teh Core eh - Vote vote = event.getVote(); - PluginMain.Instance.getLogger().info("Vote: " + vote); - org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(vote.getUsername()); - Player p = Bukkit.getPlayer(vote.getUsername()); - if (op != null) { - PluginMain.economy.depositPlayer(op, 50.0); - } - if (p != null) { - p.sendMessage("§bThanks for voting! $50 was added to your account."); - } - } - - @EventHandler - public void onPlayerMove(PlayerMoveEvent e) { - ChatPlayer mp = TBMCPlayer.getPlayer(e.getPlayer().getUniqueId(), ChatPlayer.class); - if (mp.ChatOnly) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerTeleport(PlayerTeleportEvent e) { - if (TBMCPlayer.getPlayer(e.getPlayer().getUniqueId(), ChatPlayer.class).ChatOnly) { - e.setCancelled(true); - e.getPlayer().sendMessage("§cYou are not allowed to teleport while in chat-only mode."); - } - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onConsoleCommand(ServerCommandEvent event) { - if (onCommandPreprocess(event.getSender(), event.getCommand())) - event.setCommand("dontrunthiscmd"); - } - - @EventHandler - public void onGetInfo(TBMCPlayerGetInfoEvent e) { - try (ChatPlayer cp = e.getPlayer().getAs(ChatPlayer.class)) { - if (cp == null) - return; - e.addInfo("Minecraft name: " + cp.PlayerName().get()); - if (cp.UserName().get() != null && cp.UserName().get().length() > 0) - e.addInfo("Reddit name: " + cp.UserName().get()); - final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand); - if (flair.length() > 0) - e.addInfo("/r/TheButton flair: " + flair); - e.addInfo(String.format("Respect: %.2f", cp.getF())); - } catch (Exception ex) { - TBMCCoreAPI.SendException("Error while providing chat info for player " + e.getPlayer().getFileName(), ex); - } - } - - @EventHandler - public void onPlayerTBMCChat(TBMCChatEvent e) { - try { - if (e.isCancelled()) - return; - HistoryCommand.addChatMessage(e.getCm(), e.getChannel()); - e.setCancelled(ChatProcessing.ProcessChat(e)); - } catch (NoClassDefFoundError | Exception ex) { // Weird things can happen - for (Player p : Bukkit.getOnlinePlayers()) - if (e.shouldSendTo(p)) - p.sendMessage("§c!§r[" - + e.getChannel().DisplayName + "] <" + (e.getSender() instanceof Player - ? ((Player) e.getSender()).getDisplayName() : e.getSender().getName()) - + "> " + e.getMessage()); - 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()); - - Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> { - PlayerJoinLeaveListener.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again - }, 1); - } -} +package buttondevteam.chat.listener; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.ChatProcessing; +import buttondevteam.chat.PluginMain; +import buttondevteam.chat.commands.ucmds.HistoryCommand; +import buttondevteam.component.channel.Channel; +import buttondevteam.component.channel.ChatChannelRegisterEvent; +import buttondevteam.component.channel.ChatRoom; +import buttondevteam.lib.TBMCChatEvent; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.ChatMessage; +import buttondevteam.lib.chat.TBMCChatAPI; +import buttondevteam.lib.player.ChromaGamerBase; +import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.vexsoftware.votifier.model.Vote; +import com.vexsoftware.votifier.model.VotifierEvent; +import lombok.val; +import net.ess3.api.events.NickChangeEvent; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.*; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.help.HelpTopic; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map.Entry; +import java.util.Random; +import java.util.UUID; +import java.util.function.BiPredicate; + +public class PlayerListener implements Listener { + /** + * Does not contain format codes, lowercased + */ + public static BiMap nicknames = HashBiMap.create(); + + public static boolean Enable = false; + + public static int LoginWarningCountTotal = 5; + + public static String NotificationSound; + public static double NotificationPitch; + + public static boolean ShowRPTag = false; + + public final static String[] LaughStrings = new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}; + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + if (event.isCancelled()) + return; + ChatPlayer cp = TBMCPlayer.getPlayer(event.getPlayer().getUniqueId(), ChatPlayer.class); + TBMCChatAPI.SendChatMessage(ChatMessage.builder(event.getPlayer(), cp, event.getMessage()).build()); + event.setCancelled(true); // The custom event should only be cancelled when muted or similar + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void PlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + if (!event.isCancelled()) + event.setCancelled(onCommandPreprocess(event.getPlayer(), event.getMessage())); + } + + private boolean onCommandPreprocess(CommandSender sender, String message) { + if (message.length() < 2) + return false; + int index = message.indexOf(" "); + val mp = ChromaGamerBase.getFromSender(sender); + String cmd; + final BiPredicate checkchid = (chan, cmd1) -> cmd1.equalsIgnoreCase(chan.ID) || (Arrays.stream(chan.IDs().get()).anyMatch(cmd1::equalsIgnoreCase)); + if (index == -1) { // Only the command is run + if (!(sender instanceof Player || sender instanceof ConsoleCommandSender)) + return false; + // ^^ We can only store player or console channels - Directly sending to channels would still work if they had an event + cmd = sender instanceof ConsoleCommandSender ? message : message.substring(1); + for (Channel channel : Channel.getChannels()) { + if (checkchid.test(channel, cmd)) { + Channel oldch = mp.channel().get(); + if (oldch instanceof ChatRoom) + ((ChatRoom) oldch).leaveRoom(sender); + if (oldch.equals(channel)) + mp.channel().set(Channel.GlobalChat); + else { + mp.channel().set(channel); + if (channel instanceof ChatRoom) + ((ChatRoom) channel).joinRoom(sender); + } + sender.sendMessage("§6You are now talking in: §b" + mp.channel().get().DisplayName().get()); + return true; + } + } + } else { // We have arguments + cmd = sender instanceof ConsoleCommandSender ? message.substring(0, index) : message.substring(1, index); + if (cmd.equalsIgnoreCase("tpahere")) { + Player player = Bukkit.getPlayer(message.substring(index + 1)); + if (player != null && sender instanceof Player) + player.sendMessage("§b" + ((Player) sender).getDisplayName() + " §bis in this world: " + + ((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); + Bukkit.broadcastMessage(String.format("* %s %s", sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName(), msg)); + return true; + } else { + sender.sendMessage("§cCan't use /minecraft:me while muted."); + return true; + } + } else if (cmd.equalsIgnoreCase("me")) { //Take over for Discord broadcast + if (!(sender instanceof Player) || !PluginMain.essentials.getUser((Player) sender).isMuted()) { + String msg = message.substring(index + 1); + Bukkit.broadcastMessage(String.format("§5* %s %s", sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName(), msg)); + return true; + } else { + sender.sendMessage("§cCan't use /me while muted."); + return true; + } + } else + for (Channel channel : Channel.getChannels()) { + if (checkchid.test(channel, cmd)) { //Apparently method references don't require final variables + TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, mp, message.substring(index + 1)).build(), channel); + return true; + } + } + // TODO: Target selectors + } + // We don't care if we have arguments + if (cmd.toLowerCase().startsWith("un")) { + for (HelpTopic ht : PluginMain.Instance.getServer().getHelpMap().getHelpTopics()) { + if (ht.getName().equalsIgnoreCase("/" + cmd)) + return false; + } + if (PluginMain.permission.has(sender, "tbmc.admin")) { + String s = cmd.substring(2); + Player target = Bukkit.getPlayer(message.substring(index + 1)); + if (target == null) { + sender.sendMessage("§cError: Player not found. (/un" + s + " )"); + return true; + } + target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10 * 20, 5, false, false)); + Bukkit.broadcastMessage( + (sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName()) + " un" + s + + "'d " + target.getDisplayName()); + return true; + } + } + return false; + } + + @EventHandler + public void onTabComplete(PlayerChatTabCompleteEvent e) { + 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 + } + } + + public static boolean ActiveF = false; + public static ChatPlayer FPlayer = null; + public static BukkitTask Ftask = null; + public static int AlphaDeaths; + public static ArrayList Fs = new ArrayList<>(); + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent e) { + if (e.getEntity().getName().equals("Alpha_Bacca44")) + AlphaDeaths++; + // MinigamePlayer mgp = Minigames.plugin.pdata.getMinigamePlayer(e.getEntity()); + if (/* (mgp != null && !mgp.isInMinigame()) && */ new Random().nextBoolean()) { // Don't store Fs for NPCs + Runnable tt = () -> { + if (ActiveF) { + ActiveF = false; + if (FPlayer != null && FPlayer.FCount().get() < Integer.MAX_VALUE - 1) + FPlayer.FCount().set(FPlayer.FCount().get() + Fs.size()); + Bukkit.broadcastMessage("§b" + Fs.size() + " " + (Fs.size() == 1 ? "person" : "people") + + " paid their respects.§r"); + Fs.clear(); + } + }; + if (Ftask != null) { + Ftask.cancel(); + tt.run(); //Finish previous one + } + ActiveF = true; + Fs.clear(); + FPlayer = TBMCPlayer.getPlayer(e.getEntity().getUniqueId(), ChatPlayer.class); + FPlayer.FDeaths().set(FPlayer.FDeaths().get() + 1); + Bukkit.broadcastMessage("§bPress F to pay respects.§r"); + Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20); + } + } + + @EventHandler + @SuppressWarnings("deprecation") + public void onVotifierEvent(VotifierEvent event) { //TODO: Move to teh Core eh + Vote vote = event.getVote(); + PluginMain.Instance.getLogger().info("Vote: " + vote); + org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(vote.getUsername()); + Player p = Bukkit.getPlayer(vote.getUsername()); + if (op != null) { + PluginMain.economy.depositPlayer(op, 50.0); + } + if (p != null) { + p.sendMessage("§bThanks for voting! $50 was added to your account."); + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent e) { + ChatPlayer mp = TBMCPlayer.getPlayer(e.getPlayer().getUniqueId(), ChatPlayer.class); + if (mp.ChatOnly) + e.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerTeleport(PlayerTeleportEvent e) { + if (TBMCPlayer.getPlayer(e.getPlayer().getUniqueId(), ChatPlayer.class).ChatOnly) { + e.setCancelled(true); + e.getPlayer().sendMessage("§cYou are not allowed to teleport while in chat-only mode."); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onConsoleCommand(ServerCommandEvent event) { + if (onCommandPreprocess(event.getSender(), event.getCommand())) + event.setCommand("dontrunthiscmd"); + } + + @EventHandler + public void onGetInfo(TBMCPlayerGetInfoEvent e) { + try (ChatPlayer cp = e.getPlayer().getAs(ChatPlayer.class)) { + if (cp == null) + return; + e.addInfo("Minecraft name: " + cp.PlayerName().get()); + if (cp.UserName().get() != null && cp.UserName().get().length() > 0) + e.addInfo("Reddit name: " + cp.UserName().get()); + final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand); + if (flair.length() > 0) + e.addInfo("/r/TheButton flair: " + flair); + e.addInfo(String.format("Respect: %.2f", cp.getF())); + } catch (Exception ex) { + TBMCCoreAPI.SendException("Error while providing chat info for player " + e.getPlayer().getFileName(), ex); + } + } + + @EventHandler + public void onPlayerTBMCChat(TBMCChatEvent e) { + try { + if (e.isCancelled()) + return; + HistoryCommand.addChatMessage(e.getCm(), e.getChannel()); + e.setCancelled(ChatProcessing.ProcessChat(e)); + } catch (NoClassDefFoundError | Exception ex) { // Weird things can happen + for (Player p : Bukkit.getOnlinePlayers()) + if (e.shouldSendTo(p)) + p.sendMessage("§c!§r[" + + e.getChannel().DisplayName().get() + "] <" + (e.getSender() instanceof Player + ? ((Player) e.getSender()).getDisplayName() : e.getSender().getName()) + + "> " + e.getMessage()); + 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()); + + Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> { + PlayerJoinLeaveListener.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again + }, 1); + } +} diff --git a/src/test/java/buttondevteam/chat/ChatFormatIT.java b/src/test/java/buttondevteam/chat/ChatFormatIT.java index bb508cc..55e5a86 100644 --- a/src/test/java/buttondevteam/chat/ChatFormatIT.java +++ b/src/test/java/buttondevteam/chat/ChatFormatIT.java @@ -7,8 +7,8 @@ import buttondevteam.chat.formatting.TellrawEvent; import buttondevteam.chat.formatting.TellrawEvent.ClickAction; import buttondevteam.chat.formatting.TellrawEvent.HoverAction; import buttondevteam.chat.formatting.TellrawPart; +import buttondevteam.component.channel.Channel; import buttondevteam.core.TestPrepare; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.Color; import net.milkbowl.vault.permission.Permission; import org.bukkit.command.CommandSender; From 3f387a9775272770caec989961658eb40456a6d7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 13 Jan 2019 01:40:54 +0100 Subject: [PATCH 5/7] C o m p o n e n t s FlairComponent AnnouncerComponent TownyComponent Some fixes Removed old fields and JarUtils #85 #84 #4 --- .../buttondevteam/chat/AnnouncerThread.java | 25 -- .../java/buttondevteam/chat/ChatPlayer.java | 267 ++++++++-------- .../java/buttondevteam/chat/JarUtils.java | 90 ------ .../java/buttondevteam/chat/PluginMain.java | 268 +--------------- .../chat/commands/ucmds/HistoryCommand.java | 4 +- .../chat/commands/ucmds/NColorCommand.java | 3 +- .../commands/ucmds/NationColorCommand.java | 6 +- .../chat/commands/ucmds/TownColorCommand.java | 6 +- .../ucmds/admin/NationColorCommand.java | 3 +- .../ucmds/admin/TownColorCommand.java | 9 +- .../chat/components/TownyComponent.java | 15 - .../announce/AddCommand.java | 73 +++-- .../announce/AnnounceCommandBase.java | 26 +- .../announce/AnnouncerComponent.java | 50 +++ .../announce/EditCommand.java | 89 +++--- .../announce/ListCommand.java | 55 ++-- .../announce/RemoveCommand.java | 58 ++-- .../announce/SetTimeCommand.java | 64 ++-- .../flair}/AcceptCommand.java | 196 ++++++------ .../chat/components/flair/FlairComponent.java | 185 +++++++++++ .../{ => components/flair}/FlairStates.java | 10 +- .../flair}/IgnoreCommand.java | 87 +++--- .../flair}/SetFlairCommand.java | 141 +++++---- .../{ => towny}/TownyAnnouncer.java | 6 +- .../chat/components/towny/TownyComponent.java | 94 ++++++ .../listener/PlayerJoinLeaveListener.java | 293 +++++++++--------- .../chat/listener/PlayerListener.java | 23 +- 27 files changed, 1046 insertions(+), 1100 deletions(-) delete mode 100644 src/main/java/buttondevteam/chat/AnnouncerThread.java delete mode 100644 src/main/java/buttondevteam/chat/JarUtils.java delete mode 100644 src/main/java/buttondevteam/chat/components/TownyComponent.java rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/AddCommand.java (84%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/AnnounceCommandBase.java (84%) create mode 100644 src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/EditCommand.java (79%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/ListCommand.java (72%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/RemoveCommand.java (78%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components}/announce/SetTimeCommand.java (78%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/flair}/AcceptCommand.java (91%) create mode 100644 src/main/java/buttondevteam/chat/components/flair/FlairComponent.java rename src/main/java/buttondevteam/chat/{ => components/flair}/FlairStates.java (64%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/flair}/IgnoreCommand.java (92%) rename src/main/java/buttondevteam/chat/{commands/ucmds/admin => components/flair}/SetFlairCommand.java (87%) rename src/main/java/buttondevteam/chat/components/{ => towny}/TownyAnnouncer.java (86%) create mode 100644 src/main/java/buttondevteam/chat/components/towny/TownyComponent.java diff --git a/src/main/java/buttondevteam/chat/AnnouncerThread.java b/src/main/java/buttondevteam/chat/AnnouncerThread.java deleted file mode 100644 index 60d40e7..0000000 --- a/src/main/java/buttondevteam/chat/AnnouncerThread.java +++ /dev/null @@ -1,25 +0,0 @@ -package buttondevteam.chat; - -import org.bukkit.Bukkit; - -public class AnnouncerThread implements Runnable { - private static int AnnounceMessageIndex = 0; - - @Override - public void run() { - while (!PluginMain.Instance.stop) { - try { - Thread.sleep(PluginMain.AnnounceTime); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - if (Bukkit.getOnlinePlayers().size() == 0) continue; //Don't post to Discord if nobody is on - if (PluginMain.AnnounceMessages.size() > AnnounceMessageIndex) { - Bukkit.broadcastMessage(PluginMain.AnnounceMessages.get(AnnounceMessageIndex)); - AnnounceMessageIndex++; - if (AnnounceMessageIndex == PluginMain.AnnounceMessages.size()) - AnnounceMessageIndex = 0; - } - } - } -} diff --git a/src/main/java/buttondevteam/chat/ChatPlayer.java b/src/main/java/buttondevteam/chat/ChatPlayer.java index 2ffa48d..f3ee87b 100644 --- a/src/main/java/buttondevteam/chat/ChatPlayer.java +++ b/src/main/java/buttondevteam/chat/ChatPlayer.java @@ -1,135 +1,132 @@ -package buttondevteam.chat; - -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.player.EnumPlayerData; -import buttondevteam.lib.player.PlayerClass; -import buttondevteam.lib.player.PlayerData; -import buttondevteam.lib.player.TBMCPlayerBase; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.List; - -@PlayerClass(pluginname = "Button1Chat") -public class ChatPlayer extends TBMCPlayerBase { - public PlayerData UserName() { - return data(null); - } - - public List UserNames() { - return data(new ArrayList()).get(); - } - - public PlayerData FlairTime() { - return data(FlairTimeNone); - } - - public EnumPlayerData FlairState() { - return dataEnum(FlairStates.class, FlairStates.NoComment); - } - - public PlayerData FCount() { - return data(0); - } - - public PlayerData FDeaths() { - return data(0); - } - - public PlayerData FlairCheater() { - return data(false); - } - - public PlayerData> NameColorLocations() { // No byte[], no TIntArrayList - return data(null); - } - - public Location SavedLocation; - public boolean Working; - // public int Tables = 10; - public boolean SendingLink = false; - public boolean RainbowPresserColorMode = false; - public Color OtherColorMode = null; - public boolean ChatOnly = false; - public int LoginWarningCount = 0; - - public static final int FlairTimeNonPresser = -1; - public static final int FlairTimeCantPress = -2; - public static final int FlairTimeNone = -3; - - /** - * Gets the player's flair, optionally formatting for Minecraft. - * - * @param noformats - * The MC formatting codes will be only applied if false - * @return The flair - */ - public String GetFormattedFlair(boolean noformats) { - int time = FlairTime().get(); - if (time == FlairTimeCantPress) - return noformats ? "(can't press)" : "§r(--s)§r"; - if (time == FlairTimeNonPresser) - return noformats ? "(non-presser)" : "§7(--s)§r"; - if (time == FlairTimeNone) - return ""; - return noformats ? String.format("(%ds)", time) : String.format("§%x(%ds)§r", GetFlairColor(), time); - } - - /** - * Gets the player's flair, formatted for Minecraft. - * - * @return The flair - */ - public String GetFormattedFlair() { - return GetFormattedFlair(false); - } - - public void SetFlair(int time) { - FlairTime().set(time); - FlairUpdate(); - } - - public void SetFlair(int time, boolean cheater) { - FlairTime().set(time); - FlairCheater().set(cheater); - FlairUpdate(); - } - - public void FlairUpdate() { - - // Flairs from Command Block The Button - Teams - // PluginMain.Instance.getServer().getScoreboardManager().getMainScoreboard().getTeams().add() - Player p = Bukkit.getPlayer(uuid); - if (p != null) - p.setPlayerListName(String.format("%s%s", p.getDisplayName(), GetFormattedFlair())); - } - - public short GetFlairColor() { - if (FlairCheater().get()) - return 0x5; - final int flairTime = FlairTime().get(); - if (flairTime == FlairTimeNonPresser) - return 0x7; - else if (flairTime == FlairTimeCantPress) - return 0xf; - else if (flairTime <= 60 && flairTime >= 52) - return 0x5; - else if (flairTime <= 51 && flairTime >= 42) - return 0x9; - else if (flairTime <= 41 && flairTime >= 32) - return 0xa; - else if (flairTime <= 31 && flairTime >= 22) - return 0xe; - else if (flairTime <= 21 && flairTime >= 11) - return 0x6; - else if (flairTime <= 11 && flairTime >= 0) - return 0xc; - return 0x00; //Return 0 if none or too high, so names will get aqua default color, not white - } - - public double getF() { - return (double) FCount().get() / (double) FDeaths().get(); - } -} +package buttondevteam.chat; + +import buttondevteam.chat.components.flair.FlairStates; +import buttondevteam.lib.chat.Color; +import buttondevteam.lib.player.EnumPlayerData; +import buttondevteam.lib.player.PlayerClass; +import buttondevteam.lib.player.PlayerData; +import buttondevteam.lib.player.TBMCPlayerBase; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +@PlayerClass(pluginname = "Button1Chat") +public class ChatPlayer extends TBMCPlayerBase { + public PlayerData UserName() { + return data(null); + } + + public List UserNames() { + return data(new ArrayList()).get(); + } + + public PlayerData FlairTime() { + return data(FlairTimeNone); + } + + public EnumPlayerData FlairState() { + return dataEnum(FlairStates.class, FlairStates.NoComment); + } + + public PlayerData FCount() { + return data(0); + } + + public PlayerData FDeaths() { + return data(0); + } + + public PlayerData FlairCheater() { + return data(false); + } + + public PlayerData> NameColorLocations() { // No byte[], no TIntArrayList + return data(null); + } + + public boolean Working; + // public int Tables = 10; + public boolean RainbowPresserColorMode = false; + public Color OtherColorMode = null; + public boolean ChatOnly = false; + + public static final int FlairTimeNonPresser = -1; + public static final int FlairTimeCantPress = -2; + public static final int FlairTimeNone = -3; + + /** + * Gets the player's flair, optionally formatting for Minecraft. + * + * @param noformats + * The MC formatting codes will be only applied if false + * @return The flair + */ + public String GetFormattedFlair(boolean noformats) { + int time = FlairTime().get(); + if (time == FlairTimeCantPress) + return noformats ? "(can't press)" : "§r(--s)§r"; + if (time == FlairTimeNonPresser) + return noformats ? "(non-presser)" : "§7(--s)§r"; + if (time == FlairTimeNone) + return ""; + return noformats ? String.format("(%ds)", time) : String.format("§%x(%ds)§r", GetFlairColor(), time); + } + + /** + * Gets the player's flair, formatted for Minecraft. + * + * @return The flair + */ + public String GetFormattedFlair() { + return GetFormattedFlair(false); + } + + public void SetFlair(int time) { + FlairTime().set(time); + FlairUpdate(); + } + + public void SetFlair(int time, boolean cheater) { + FlairTime().set(time); + FlairCheater().set(cheater); + FlairUpdate(); + } + + public void FlairUpdate() { + + // Flairs from Command Block The Button - Teams + // PluginMain.Instance.getServer().getScoreboardManager().getMainScoreboard().getTeams().add() + Player p = Bukkit.getPlayer(uuid); + if (p != null) + p.setPlayerListName(String.format("%s%s", p.getDisplayName(), GetFormattedFlair())); + } + + public short GetFlairColor() { + if (FlairCheater().get()) + return 0x5; + final int flairTime = FlairTime().get(); + if (flairTime == FlairTimeNonPresser) + return 0x7; + else if (flairTime == FlairTimeCantPress) + return 0xf; + else if (flairTime <= 60 && flairTime >= 52) + return 0x5; + else if (flairTime <= 51 && flairTime >= 42) + return 0x9; + else if (flairTime <= 41 && flairTime >= 32) + return 0xa; + else if (flairTime <= 31 && flairTime >= 22) + return 0xe; + else if (flairTime <= 21 && flairTime >= 11) + return 0x6; + else if (flairTime <= 11 && flairTime >= 0) + return 0xc; + return 0x00; //Return 0 if none or too high, so names will get aqua default color, not white + } + + public double getF() { + return (double) FCount().get() / (double) FDeaths().get(); + } +} diff --git a/src/main/java/buttondevteam/chat/JarUtils.java b/src/main/java/buttondevteam/chat/JarUtils.java deleted file mode 100644 index 5e8c2d6..0000000 --- a/src/main/java/buttondevteam/chat/JarUtils.java +++ /dev/null @@ -1,90 +0,0 @@ -package buttondevteam.chat; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLDecoder; -import java.util.Enumeration; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -public class JarUtils { - - public static boolean extractFromJar(final String fileName, - final String dest) throws IOException { - if (getRunningJar() == null) { - return false; - } - final File file = new File(dest); - if (file.isDirectory()) { - file.mkdir(); - return false; - } - if (!file.exists()) { - file.getParentFile().mkdirs(); - } - - final JarFile jar = getRunningJar(); - final Enumeration e = jar.entries(); - while (e.hasMoreElements()) { - final JarEntry je = e.nextElement(); - if (!je.getName().contains(fileName)) { - continue; - } - final InputStream in = new BufferedInputStream( - jar.getInputStream(je)); - final OutputStream out = new BufferedOutputStream( - new FileOutputStream(file)); - copyInputStream(in, out); - jar.close(); - return true; - } - jar.close(); - return false; - } - - private final static void copyInputStream(final InputStream in, - final OutputStream out) throws IOException { - try { - final byte[] buff = new byte[4096]; - int n; - while ((n = in.read(buff)) > 0) { - out.write(buff, 0, n); - } - } finally { - out.flush(); - out.close(); - in.close(); - } - } - - public static URL getJarUrl(final File file) throws IOException { - return new URL("jar:" + file.toURI().toURL().toExternalForm() + "!/"); - } - - public static JarFile getRunningJar() throws IOException { - if (!RUNNING_FROM_JAR) { - return null; // null if not running from jar - } - String path = new File(JarUtils.class.getProtectionDomain() - .getCodeSource().getLocation().getPath()).getAbsolutePath(); - path = URLDecoder.decode(path, "UTF-8"); - return new JarFile(path); - } - - private static boolean RUNNING_FROM_JAR = false; - - static { - final URL resource = JarUtils.class.getClassLoader().getResource( - "plugin.yml"); - if (resource != null) { - RUNNING_FROM_JAR = true; - } - } - -} diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index 157c743..1599d6f 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -3,52 +3,36 @@ package buttondevteam.chat; import buttondevteam.chat.commands.YeehawCommand; import buttondevteam.chat.commands.ucmds.TownColorCommand; import buttondevteam.chat.components.TownColorComponent; -import buttondevteam.chat.components.TownyComponent; +import buttondevteam.chat.components.announce.AnnouncerComponent; +import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.chat.listener.PlayerListener; import buttondevteam.chat.listener.TownyListener; import buttondevteam.component.channel.Channel; -import buttondevteam.component.channel.Channel.RecipientTestResult; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.TBMCPlayerBase; import com.earth2me.essentials.Essentials; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.palmergames.bukkit.towny.Towny; -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 net.milkbowl.vault.chat.Chat; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scoreboard.Scoreboard; import org.dynmap.towny.DTBridge; import org.dynmap.towny.DynmapTownyPlugin; -import org.htmlcleaner.HtmlCleaner; -import org.htmlcleaner.TagNode; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.net.UnknownHostException; -import java.text.SimpleDateFormat; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @@ -57,26 +41,11 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. // https://www.reddit.com/r/thebutton/comments/31c32v/i_pressed_the_button_without_really_thinking/ public static PluginMain Instance; public static ConsoleCommandSender Console; - private final static String FlairThreadURL = "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"; public static Scoreboard SB; - public static TownyUniverse TU; - private static ArrayList Towns; - private static ArrayList Nations; public static Channel TownChat; public static Channel NationChat; - private static Channel RPChannel; - - /** - *

- * This variable is used as a cache for flair state checking when reading the flair thread. - *

- *

- * It's used because normally it has to load all associated player files every time to read the flair state - *

- */ - private Set PlayersWithFlairs = new HashSet<>(); // Fired when plugin is first enabled @Override @@ -92,18 +61,12 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. LoadFiles(); SB = getServer().getScoreboardManager().getMainScoreboard(); // Main can be detected with @a[score_...] - TU = ((Towny) Bukkit.getPluginManager().getPlugin("Towny")).getTownyUniverse(); - 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 - TownColors.keySet().removeIf(t -> !TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns - NationColor.keySet().removeIf(n -> !TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations + Component.registerComponent(this, new TownyComponent()); + TownColors.keySet().removeIf(t -> !TownyComponent.TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns + NationColor.keySet().removeIf(n -> !TownyComponent.TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations - TBMCChatAPI.RegisterChatChannel( - TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false))); - TBMCChatAPI.RegisterChatChannel( - NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true))); - TBMCChatAPI.RegisterChatChannel(RPChannel = new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global + TBMCChatAPI.RegisterChatChannel(new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global Bukkit.getScheduler().runTask(this, () -> { val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); @@ -116,11 +79,9 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. if (!setupEconomy() || !setupPermissions()) TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up economy or permissions!")); - new Thread(this::FlairGetterThreadMethod).start(); - new Thread(new AnnouncerThread()).start(); - - Component.registerComponent(this, new TownyComponent()); Component.registerComponent(this, new TownColorComponent()); + Component.registerComponent(this, new FlairComponent()); //The original purpose of this plugin + Component.registerComponent(this, new AnnouncerComponent()); } /** @@ -140,152 +101,14 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. } } - public Boolean stop = false; public static Essentials essentials = null; // Fired when plugin is disabled @Override public void onDisable() { SaveFiles(); - stop = true; } - private void FlairGetterThreadMethod() { - int errorcount = 0; - while (!stop) { - try { - String body = TBMCCoreAPI.DownloadString(FlairThreadURL + ".json?limit=1000"); - JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data") - .getAsJsonObject().get("children").getAsJsonArray(); - for (Object obj : json) { - JsonObject item = (JsonObject) obj; - String author = item.get("data").getAsJsonObject().get("author").getAsString(); - String ign = item.get("data").getAsJsonObject().get("body").getAsString(); - int start = ign.indexOf("IGN:") + "IGN:".length(); - if (start == -1 + "IGN:".length()) - continue; - int end = ign.indexOf(' ', start); - if (end == -1 || end == start) - end = ign.indexOf('\n', start); - if (end == -1 || end == start) - ign = ign.substring(start); - else - ign = ign.substring(start, end); - ign = ign.trim(); - if (PlayersWithFlairs.contains(ign)) - continue; - try (ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class)) { // Loads player file - if (mp == null) - continue; - /* - * if (!JoinedBefore(mp, 2015, 6, 5)) continue; - */ - if (!mp.UserNames().contains(author)) - mp.UserNames().add(author); - if (mp.FlairState().get().equals(FlairStates.NoComment)) { - mp.FlairState().set(FlairStates.Commented); - ConfirmUserMessage(mp); - } - PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted - } - } - } catch (Exception e) { - errorcount++; - if (errorcount >= 10) { - errorcount = 0; - if (!e.getMessage().contains("Server returned HTTP response code") - && !(e instanceof UnknownHostException)) - TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e); - } - } - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - - public void DownloadFlair(ChatPlayer mp) throws IOException { - String[] flairdata = TBMCCoreAPI - .DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName().get()) - .replace("\"", "").split(":"); - String flair; - if (flairdata.length > 1) - flair = flairdata[1]; - else - flair = ""; - String flairclass; - if (flairdata.length > 2) - flairclass = flairdata[2]; - else - flairclass = "unknown"; - SetFlair(mp, flair, flairclass, mp.UserName().get()); - } - - private void SetFlair(ChatPlayer p, String text, String flairclass, String username) { - p.UserName().set(username); - p.FlairState().set(FlairStates.Recognised); - switch (flairclass) { - case "cheater": - p.SetFlair(Short.parseShort(text), true); - return; - case "unknown": - try { - if (CheckForJoinDate(p)) { - if (text.equals("-1")) // If true, only non-presser/can't press; if false, any flair (but we can still detect can't press) - p.SetFlair(ChatPlayer.FlairTimeNonPresser); - else - p.SetFlair(ChatPlayer.FlairTimeNone); // Flair unknown - } else { - p.SetFlair(ChatPlayer.FlairTimeCantPress); - } - } catch (Exception e) { - p.FlairState().set(FlairStates.Commented); // Flair unknown - p.SetFlair(ChatPlayer.FlairTimeNone); - TBMCCoreAPI.SendException("Error while checking join date for player " + p.PlayerName() + "!", e); - } - return; - default: - break; - } - p.SetFlair(Short.parseShort(text)); - } - - private static boolean CheckForJoinDate(ChatPlayer mp) throws Exception { - return JoinedBefore(mp, 2015, 4, 1); - } - - private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception { - URL url = new URL("https://www.reddit.com/u/" + mp.UserName()); - URLConnection con = url.openConnection(); - con.setRequestProperty("User-Agent", "TheButtonAutoFlair"); - InputStream in = con.getInputStream(); - HtmlCleaner cleaner = new HtmlCleaner(); - TagNode node = cleaner.clean(in); - - node = node.getElementsByAttValue("class", "age", true, true)[0]; - node = node.getElementsByName("time", false)[0]; - String joindate = node.getAttributeByName("datetime"); - SimpleDateFormat parserSDF = new SimpleDateFormat("yyyy-MM-dd"); - joindate = joindate.split("T")[0]; - Date date = parserSDF.parse(joindate); - return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day) - .build().getTime()); - } - - public static void ConfirmUserMessage(ChatPlayer mp) { - Player p = Bukkit.getPlayer(mp.getUUID()); - if (mp.FlairState().get().equals(FlairStates.Commented) && p != null) - if (mp.UserNames().size() > 1) - p.sendMessage( - "§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r"); - else - p.sendMessage("§9A Reddit user commented your name. Is that you?§r §6Type /u accept or /u ignore§r"); - } - - public static ArrayList AnnounceMessages = new ArrayList<>(); - public static int AnnounceTime = 15 * 60 * 1000; /** * Names lowercased */ @@ -305,9 +128,6 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. yc.load(file); PlayerListener.NotificationSound = yc.getString("notificationsound"); PlayerListener.NotificationPitch = yc.getDouble("notificationpitch"); - AnnounceTime = yc.getInt("announcetime", 15 * 60 * 1000); - AnnounceMessages.addAll(yc.getStringList("announcements")); - PlayerListener.AlphaDeaths = yc.getInt("alphadeaths"); val cs = yc.getConfigurationSection("towncolors"); if (cs != null) TownColors.putAll(cs.getValues(true).entrySet().stream() @@ -333,9 +153,6 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. YamlConfiguration yc = new YamlConfiguration(); yc.set("notificationsound", PlayerListener.NotificationSound); yc.set("notificationpitch", PlayerListener.NotificationPitch); - yc.set("announcetime", AnnounceTime); - yc.set("announcements", AnnounceMessages); - yc.set("alphadeaths", PlayerListener.AlphaDeaths); yc.createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); yc.set("towncolorcount", TownColorCommand.ColorCount); @@ -361,16 +178,6 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. return (permission != null); } - private boolean setupChat() { - RegisteredServiceProvider chatProvider = getServer().getServicesManager() - .getRegistration(net.milkbowl.vault.chat.Chat.class); - if (chatProvider != null) { - chat = chatProvider.getProvider(); - } - - return (chat != null); - } - private boolean setupEconomy() { RegisteredServiceProvider economyProvider = getServer().getServicesManager() .getRegistration(net.milkbowl.vault.economy.Economy.class); @@ -381,53 +188,4 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. return (economy != null); } - /** - * Return the error message for the message sender if they can't send it and the score - */ - private static RecipientTestResult checkTownNationChat(CommandSender sender, boolean nationchat) { - if (!(sender instanceof Player)) - return new RecipientTestResult("§cYou are not a player!"); - Resident resident = PluginMain.TU.getResidentMap().get(sender.getName().toLowerCase()); - RecipientTestResult result = checkTownNationChatInternal(sender, nationchat, resident); - if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it - result = new RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably - return result; - } - - private static RecipientTestResult checkTownNationChatInternal(CommandSender sender, boolean nationchat, - Resident resident) { - try { - /* - * p.sendMessage(String.format("[SPY-%s] - %s: %s", channel.DisplayName, ((Player) sender).getDisplayName(), message)); - */ - Town town = null; - if (resident != null && resident.hasTown()) - town = resident.getTown(); - if (town == null) - return new RecipientTestResult("You aren't in a town."); - Nation nation = null; - int index; - if (nationchat) { - if (town.hasNation()) - nation = town.getNation(); - if (nation == null) - return new RecipientTestResult("Your town isn't in a nation."); - index = getTownNationIndex(nation.getName(), true); - } else - index = getTownNationIndex(town.getName(), false); - return new RecipientTestResult(index, nationchat ? nation.getName() : town.getName()); - } catch (NotRegisteredException e) { - return new RecipientTestResult("You (probably) aren't knwon by Towny! (Not in a town)"); - } - } - - public static int getTownNationIndex(String name, boolean nation) { - val list = nation ? Nations : Towns; - int index = list.indexOf(name); - if (index < 0) { - list.add(name); - index = list.size() - 1; - } - return index; - } } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java index dc27b5c..5bbe364 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/HistoryCommand.java @@ -39,9 +39,9 @@ public class HistoryCommand extends UCommandBase { sender.sendMessage("§6---- Chat History ----"); Stream stream; if (args.length == 0) { - stream = Channel.getChannels().stream(); + stream = Channel.getChannels(); } else { - Optional och = Channel.getChannels().stream().filter(chan -> chan.ID.equalsIgnoreCase(args[0])).findAny(); + Optional och = Channel.getChannels().filter(chan -> chan.ID.equalsIgnoreCase(args[0])).findAny(); if (!och.isPresent()) { sender.sendMessage("§cChannel not found. Use the ID, for example: /" + (hc == null ? "u history" : hc.GetCommandPath()) + " ooc"); return true; diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java index 88403b1..4c9943e 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java @@ -2,6 +2,7 @@ package buttondevteam.chat.commands.ucmds; import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.CommandClass; @@ -34,7 +35,7 @@ public class NColorCommand extends UCommandBase { Resident res; Town town; try { - if ((res = PluginMain.TU.getResidentMap().get(player.getName().toLowerCase())) == null || !res.hasTown() + if ((res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())) == null || !res.hasTown() || (town = res.getTown()) == null) { player.sendMessage("§cYou need to be in a town."); return true; diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java index cbfb0de..8cba718 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java @@ -1,6 +1,6 @@ package buttondevteam.chat.commands.ucmds; -import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.OptionallyPlayerCommandClass; @@ -26,8 +26,8 @@ public class NationColorCommand extends UCommandBase { @Override public boolean OnCommand(Player player, String alias, String[] args) { Resident res; - if (!(PluginMain.TU.getResidentMap().containsKey(player.getName().toLowerCase()) - && (res = PluginMain.TU.getResidentMap().get(player.getName().toLowerCase())).isKing())) { + if (!(TownyComponent.TU.getResidentMap().containsKey(player.getName().toLowerCase()) + && (res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())).isKing())) { player.sendMessage("§cYou need to be the king of a nation to set it's colors."); return true; } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java index 648daf1..bdda3d8 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java @@ -1,6 +1,6 @@ package buttondevteam.chat.commands.ucmds; -import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.OptionallyPlayerCommandClass; @@ -31,8 +31,8 @@ public class TownColorCommand extends UCommandBase { @Override public boolean OnCommand(Player player, String alias, String[] args) { Resident res; - if (!(PluginMain.TU.getResidentMap().containsKey(player.getName().toLowerCase()) - && (res = PluginMain.TU.getResidentMap().get(player.getName().toLowerCase())).isMayor())) { + if (!(TownyComponent.TU.getResidentMap().containsKey(player.getName().toLowerCase()) + && (res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())).isMayor())) { player.sendMessage("§cYou need to be the mayor of a town to set it's colors."); return true; } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java index ddc8e5b..9c9d4b1 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java @@ -1,6 +1,7 @@ package buttondevteam.chat.commands.ucmds.admin; import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.listener.TownyListener; import buttondevteam.lib.chat.Color; import com.palmergames.bukkit.towny.object.Nation; @@ -31,7 +32,7 @@ public class NationColorCommand extends AdminCommandBase { sender.sendMessage("§cYou can only use one color as a nation color."); return true; } - final Nation nation = PluginMain.TU.getNationsMap().get(args[0].toLowerCase()); + final Nation nation = TownyComponent.TU.getNationsMap().get(args[0].toLowerCase()); if (nation == null) { sender.sendMessage("§cThe nation '" + args[0] + "' cannot be found."); return true; diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java index 97224ad..21b7659 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java +++ b/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java @@ -1,6 +1,7 @@ package buttondevteam.chat.commands.ucmds.admin; import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.listener.TownyListener; import buttondevteam.lib.chat.Color; import com.palmergames.bukkit.towny.object.Town; @@ -35,12 +36,12 @@ public class TownColorCommand extends AdminCommandBase { public static boolean SetTownColor(CommandSender sender, String alias, String[] args) { if (args.length < 2) return false; - if (!PluginMain.TU.getTownsMap().containsKey(args[0].toLowerCase())) { + if (!TownyComponent.TU.getTownsMap().containsKey(args[0].toLowerCase())) { sender.sendMessage("§cThe town '" + args[0] + "' cannot be found."); return true; } Color[] clrs = new Color[args.length - 1]; - Town targetTown = PluginMain.TU.getTownsMap().get(args[0].toLowerCase()); + Town targetTown = TownyComponent.TU.getTownsMap().get(args[0].toLowerCase()); for (int i = 1; i < args.length; i++) { val c = getColorOrSendError(args[i], sender); if (!c.isPresent()) @@ -50,7 +51,7 @@ public class TownColorCommand extends AdminCommandBase { for (Map.Entry other : PluginMain.TownColors.entrySet()) { Color nc, tnc; try { - nc = PluginMain.NationColor.get(PluginMain.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase()); + nc = PluginMain.NationColor.get(TownyComponent.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase()); } catch (Exception e) { //Too lazy for lots of null-checks and it may throw exceptions anyways nc = null; } @@ -103,6 +104,6 @@ public class TownColorCommand extends AdminCommandBase { } public static String getTownNameCased(String name) { - return PluginMain.TU.getTownsMap().get(name.toLowerCase()).getName(); + return TownyComponent.TU.getTownsMap().get(name.toLowerCase()).getName(); } } diff --git a/src/main/java/buttondevteam/chat/components/TownyComponent.java b/src/main/java/buttondevteam/chat/components/TownyComponent.java deleted file mode 100644 index b176710..0000000 --- a/src/main/java/buttondevteam/chat/components/TownyComponent.java +++ /dev/null @@ -1,15 +0,0 @@ -package buttondevteam.chat.components; - -import buttondevteam.lib.architecture.Component; - -public class TownyComponent extends Component { - @Override - protected void enable() { - TownyAnnouncer.setup(); - } - - @Override - protected void disable() { - TownyAnnouncer.setdown(); - } -} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/AddCommand.java b/src/main/java/buttondevteam/chat/components/announce/AddCommand.java similarity index 84% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/AddCommand.java rename to src/main/java/buttondevteam/chat/components/announce/AddCommand.java index d86fcf2..d236f56 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/AddCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/AddCommand.java @@ -1,37 +1,36 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class AddCommand extends AnnounceCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { - "§6---- Add announcement ----", - "This command adds a new announcement", - "Note: Please avoid using this command, if possible", - "Instead, use the command blocks in flatworld to set announcements", - "This makes editing announcements easier" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - if (args.length < 1) { - return false; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < args.length; i++) { - sb.append(args[i]); - if (i != args.length - 1) - sb.append(" "); - } - String finalmessage = sb.toString().replace('&', '§'); - PluginMain.AnnounceMessages.add(finalmessage); - sender.sendMessage("§bAnnouncement added. - Plase avoid using this command if possible, see /u announce add without args.§r"); - return true; - } - -} +package buttondevteam.chat.components.announce; + +import org.bukkit.command.CommandSender; + +public class AddCommand extends AnnounceCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { + "§6---- Add announcement ----", + "This command adds a new announcement", + "Note: Please avoid using this command, if possible", + "Instead, use the command blocks in flatworld to set announcements", + "This makes editing announcements easier" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, + String[] args) { + if (args.length < 1) { + return false; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < args.length; i++) { + sb.append(args[i]); + if (i != args.length - 1) + sb.append(" "); + } + String finalmessage = sb.toString().replace('&', '§'); + AnnouncerComponent component = (AnnouncerComponent) getComponent(); + component.AnnounceMessages().get().add(finalmessage); + sender.sendMessage("§bAnnouncement added. - Plase avoid using this command if possible, see /u announce add without args.§r"); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/AnnounceCommandBase.java b/src/main/java/buttondevteam/chat/components/announce/AnnounceCommandBase.java similarity index 84% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/AnnounceCommandBase.java rename to src/main/java/buttondevteam/chat/components/announce/AnnounceCommandBase.java index c721891..308a845 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/AnnounceCommandBase.java +++ b/src/main/java/buttondevteam/chat/components/announce/AnnounceCommandBase.java @@ -1,13 +1,13 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import buttondevteam.chat.commands.ucmds.UCommandBase; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.OptionallyPlayerCommandClass; - -@CommandClass(modOnly = true) -@OptionallyPlayerCommandClass(playerOnly = false) -public abstract class AnnounceCommandBase extends UCommandBase { - - public abstract String[] GetHelpText(String alias); - -} +package buttondevteam.chat.components.announce; + +import buttondevteam.chat.commands.ucmds.UCommandBase; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.OptionallyPlayerCommandClass; + +@CommandClass(modOnly = true) +@OptionallyPlayerCommandClass(playerOnly = false) +public abstract class AnnounceCommandBase extends UCommandBase { + + public abstract String[] GetHelpText(String alias); + +} diff --git a/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java b/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java new file mode 100644 index 0000000..fce4422 --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/announce/AnnouncerComponent.java @@ -0,0 +1,50 @@ +package buttondevteam.chat.components.announce; + +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import org.bukkit.Bukkit; + +import java.util.ArrayList; + +public class AnnouncerComponent extends Component implements Runnable { + public ConfigData> AnnounceMessages() { + return getConfig().getData("announceMessages", new ArrayList<>(0)); + } + + public ConfigData AnnounceTime() { + return getConfig().getData("announceTime", 15 * 60 * 1000); + } + private static int AnnounceMessageIndex = 0; + + @Override + public void run() { + while (isEnabled()) { + try { + 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) { + Bukkit.broadcastMessage(AnnounceMessages().get().get(AnnounceMessageIndex)); + AnnounceMessageIndex++; + if (AnnounceMessageIndex == AnnounceMessages().get().size()) + AnnounceMessageIndex = 0; + } + } + } + + @Override + protected void enable() { + registerCommand(new AddCommand()); + registerCommand(new EditCommand()); + registerCommand(new ListCommand()); + registerCommand(new RemoveCommand()); + registerCommand(new SetTimeCommand()); + new Thread(this).start(); + } + + @Override + protected void disable() { + } +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/EditCommand.java b/src/main/java/buttondevteam/chat/components/announce/EditCommand.java similarity index 79% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/EditCommand.java rename to src/main/java/buttondevteam/chat/components/announce/EditCommand.java index 0bb0c32..a53793b 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/EditCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/EditCommand.java @@ -1,45 +1,44 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class EditCommand extends AnnounceCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Edit announcement ----", - "This command can only be used in a command block.", - "Usage: /u annonunce edit " }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - if (!(sender instanceof BlockCommandSender)) { - sender.sendMessage("§cError: This command can only be used from a command block. You can use add and remove, though it's not recommended."); - return true; - } - if (args.length < 1) { - return false; - } - StringBuilder sb1 = new StringBuilder(); - for (int i1 = 1; i1 < args.length; i1++) { - sb1.append(args[i1]); - if (i1 != args.length - 1) - sb1.append(" "); - } - String finalmessage1 = sb1.toString().replace('&', '§'); - int index = Integer.parseInt(args[0]); - if (index > 100) - return false; - while (PluginMain.AnnounceMessages.size() <= index) - PluginMain.AnnounceMessages.add(""); - PluginMain.AnnounceMessages.set(Integer.parseInt(args[0]), - finalmessage1); - sender.sendMessage("Announcement edited."); - return true; - } - -} +package buttondevteam.chat.components.announce; + +import org.bukkit.command.BlockCommandSender; +import org.bukkit.command.CommandSender; + +public class EditCommand extends AnnounceCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Edit announcement ----", + "This command can only be used in a command block.", + "Usage: /u annonunce edit " }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, + String[] args) { + if (!(sender instanceof BlockCommandSender)) { + sender.sendMessage("§cError: This command can only be used from a command block. You can use add and remove, though it's not recommended."); + return true; + } + if (args.length < 1) { + return false; + } + StringBuilder sb1 = new StringBuilder(); + for (int i1 = 1; i1 < args.length; i1++) { + sb1.append(args[i1]); + if (i1 != args.length - 1) + sb1.append(" "); + } + String finalmessage1 = sb1.toString().replace('&', '§'); + int index = Integer.parseInt(args[0]); + if (index > 100) + return false; + AnnouncerComponent component = (AnnouncerComponent) getComponent(); + while (component.AnnounceMessages().get().size() <= index) + component.AnnounceMessages().get().add(""); + component.AnnounceMessages().get().set(Integer.parseInt(args[0]), + finalmessage1); + sender.sendMessage("Announcement edited."); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/ListCommand.java b/src/main/java/buttondevteam/chat/components/announce/ListCommand.java similarity index 72% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/ListCommand.java rename to src/main/java/buttondevteam/chat/components/announce/ListCommand.java index 079e2a2..6c15593 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/ListCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/ListCommand.java @@ -1,28 +1,27 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class ListCommand extends AnnounceCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- List announcements ----", - "This command lists the announcements and the time between them" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - sender.sendMessage("§bList of announce messages:§r"); - sender.sendMessage("§bFormat: [index] message§r"); - int i = 0; - for (String message : PluginMain.AnnounceMessages) - sender.sendMessage("[" + i++ + "] " + message); - sender.sendMessage("§bCurrent wait time between announcements: " - + PluginMain.AnnounceTime / 60 / 1000 + " minute(s)§r"); - return true; - } - -} +package buttondevteam.chat.components.announce; + +import org.bukkit.command.CommandSender; + +public class ListCommand extends AnnounceCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- List announcements ----", + "This command lists the announcements and the time between them" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, + String[] args) { + sender.sendMessage("§bList of announce messages:§r"); + sender.sendMessage("§bFormat: [index] message§r"); + int i = 0; + AnnouncerComponent component = (AnnouncerComponent) getComponent(); + 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"); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/RemoveCommand.java b/src/main/java/buttondevteam/chat/components/announce/RemoveCommand.java similarity index 78% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/RemoveCommand.java rename to src/main/java/buttondevteam/chat/components/announce/RemoveCommand.java index 3e4cda1..6f7ba30 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/RemoveCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/RemoveCommand.java @@ -1,30 +1,28 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class RemoveCommand extends AnnounceCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { - "§6---- Remove announcement ----", - "This command removes an announcement", - "Note: Please avoid using this command, if possible", - "Instead, use the command blocks in flatworld to set announcements", - "This makes editing announcements easier" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - if (args.length < 1) { - sender.sendMessage("§cUsage: /u announce remove "); - return true; - } - PluginMain.AnnounceMessages.remove(Integer.parseInt(args[0])); - return true; - } - -} +package buttondevteam.chat.components.announce; + +import org.bukkit.command.CommandSender; + +public class RemoveCommand extends AnnounceCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { + "§6---- Remove announcement ----", + "This command removes an announcement", + "Note: Please avoid using this command, if possible", + "Instead, use the command blocks in flatworld to set announcements", + "This makes editing announcements easier" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, + String[] args) { + if (args.length < 1) { + sender.sendMessage("§cUsage: /u announce remove "); + return true; + } + ((AnnouncerComponent) getComponent()).AnnounceMessages().get().remove(Integer.parseInt(args[0])); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/announce/SetTimeCommand.java b/src/main/java/buttondevteam/chat/components/announce/SetTimeCommand.java similarity index 78% rename from src/main/java/buttondevteam/chat/commands/ucmds/announce/SetTimeCommand.java rename to src/main/java/buttondevteam/chat/components/announce/SetTimeCommand.java index 4e36a0b..ee8b849 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/announce/SetTimeCommand.java +++ b/src/main/java/buttondevteam/chat/components/announce/SetTimeCommand.java @@ -1,33 +1,31 @@ -package buttondevteam.chat.commands.ucmds.announce; - -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class SetTimeCommand extends AnnounceCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Set time ----", - "This command sets the time between the announcements", - "Usage: /u anonunce settime ", "Default: 15" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - if (args.length < 1) { - return false; - } - try { - PluginMain.AnnounceTime = Integer.parseInt(args[0]) * 60 * 1000; - } catch (Exception e) { - sender.sendMessage("§cMinutes argument must be a number. Got: " - + args[0]); - return true; - } - sender.sendMessage("Time set between announce messages"); - return true; - } - -} +package buttondevteam.chat.components.announce; + +import org.bukkit.command.CommandSender; + +public class SetTimeCommand extends AnnounceCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Set time ----", + "This command sets the time between the announcements", + "Usage: /u anonunce settime ", "Default: 15" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, + String[] args) { + if (args.length < 1) { + return false; + } + try { + ((AnnouncerComponent) getComponent()).AnnounceTime().set(Integer.parseInt(args[0]) * 60 * 1000); + } catch (Exception e) { + sender.sendMessage("§cMinutes argument must be a number. Got: " + + args[0]); + return true; + } + sender.sendMessage("Time set between announce messages"); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/AcceptCommand.java b/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java similarity index 91% rename from src/main/java/buttondevteam/chat/commands/ucmds/AcceptCommand.java rename to src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java index a588b6c..51ae309 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/AcceptCommand.java +++ b/src/main/java/buttondevteam/chat/components/flair/AcceptCommand.java @@ -1,99 +1,97 @@ -package buttondevteam.chat.commands.ucmds; - -import java.util.Timer; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.FlairStates; -import buttondevteam.chat.PlayerJoinTimerTask; -import buttondevteam.chat.PluginMain; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.OptionallyPlayerCommandClass; -import buttondevteam.lib.player.TBMCPlayer; - -@CommandClass(modOnly = false) -@OptionallyPlayerCommandClass(playerOnly = true) -public class AcceptCommand extends UCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Accept flair ----", // - "Accepts a flair from Reddit", // - "Use /u accept if you commented from multiple accounts" // - }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - final Player player = (Player) sender; - ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); - if (args.length < 1 && p.UserNames().size() > 1) { - player.sendMessage("§9Multiple users commented your name. §bPlease pick one using /u accept "); - StringBuilder sb = new StringBuilder(); - sb.append("§6Usernames:"); - for (String username : p.UserNames()) - sb.append(" ").append(username); - player.sendMessage(sb.toString()); - return true; - } - if (p.FlairState().get().equals(FlairStates.NoComment) || p.UserNames().size() == 0) { - player.sendMessage("§cError: You need to write your username to the reddit thread at /r/ChromaGamers§r"); - return true; - } - if (args.length > 0 && !p.UserNames().contains(args[0])) { - player.sendMessage("§cError: Unknown name: " + args[0] + "§r"); - return true; - } - if (p.Working) { - player.sendMessage("§cError: Something is already in progress.§r"); - return true; - } - - if ((args.length > 0 ? args[0] : p.UserNames().get(0)).equals(p.UserName().get())) { - player.sendMessage("§cYou already have this user's flair.§r"); - return true; - } - if (args.length > 0) - p.UserName().set(args[0]); - else - p.UserName().set(p.UserNames().get(0)); - - player.sendMessage("§bObtaining flair..."); - p.Working = true; - Timer timer = new Timer(); - PlayerJoinTimerTask tt = new PlayerJoinTimerTask() { - @Override - public void run() { - try { - PluginMain.Instance.DownloadFlair(mp); - } catch (Exception e) { - TBMCCoreAPI.SendException( - "An error occured while downloading flair for " + player.getCustomName() + "!", e); - player.sendMessage( - "Sorry, but an error occured while trying to get your flair. Please contact a mod."); - mp.Working = false; - return; - } - - if (mp.FlairState().get().equals(FlairStates.Commented)) { - player.sendMessage( - "Sorry, but your flair isn't recorded. Please ask an admin to set it for you. Also, prepare a comment on /r/thebutton, if possible."); - mp.Working = false; - return; - } - String flair = mp.GetFormattedFlair(); - mp.FlairState().set(FlairStates.Accepted); - PluginMain.ConfirmUserMessage(mp); - player.sendMessage("§bYour flair has been set:§r " + flair); - mp.Working = false; - } - }; - tt.mp = p; - timer.schedule(tt, 20); - return true; - } - -} +package buttondevteam.chat.components.flair; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.PlayerJoinTimerTask; +import buttondevteam.chat.commands.ucmds.UCommandBase; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.OptionallyPlayerCommandClass; +import buttondevteam.lib.player.TBMCPlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Timer; + +@CommandClass(modOnly = false) +@OptionallyPlayerCommandClass(playerOnly = true) +public class AcceptCommand extends UCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Accept flair ----", // + "Accepts a flair from Reddit", // + "Use /u accept if you commented from multiple accounts" // + }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, String[] args) { + final Player player = (Player) sender; + ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); + if (args.length < 1 && p.UserNames().size() > 1) { + player.sendMessage("§9Multiple users commented your name. §bPlease pick one using /u accept "); + StringBuilder sb = new StringBuilder(); + sb.append("§6Usernames:"); + for (String username : p.UserNames()) + sb.append(" ").append(username); + player.sendMessage(sb.toString()); + return true; + } + if (p.FlairState().get().equals(FlairStates.NoComment) || p.UserNames().size() == 0) { + player.sendMessage("§cError: You need to write your username to the reddit thread at /r/ChromaGamers§r"); + return true; + } + if (args.length > 0 && !p.UserNames().contains(args[0])) { + player.sendMessage("§cError: Unknown name: " + args[0] + "§r"); + return true; + } + if (p.Working) { + player.sendMessage("§cError: Something is already in progress.§r"); + return true; + } + + if ((args.length > 0 ? args[0] : p.UserNames().get(0)).equals(p.UserName().get())) { + player.sendMessage("§cYou already have this user's flair.§r"); + return true; + } + if (args.length > 0) + p.UserName().set(args[0]); + else + p.UserName().set(p.UserNames().get(0)); + + player.sendMessage("§bObtaining flair..."); + p.Working = true; + Timer timer = new Timer(); + PlayerJoinTimerTask tt = new PlayerJoinTimerTask() { + @Override + public void run() { + try { + FlairComponent.DownloadFlair(mp); + } catch (Exception e) { + TBMCCoreAPI.SendException( + "An error occured while downloading flair for " + player.getCustomName() + "!", e); + player.sendMessage( + "Sorry, but an error occured while trying to get your flair. Please contact a mod."); + mp.Working = false; + return; + } + + if (mp.FlairState().get().equals(FlairStates.Commented)) { + player.sendMessage( + "Sorry, but your flair isn't recorded. Please ask an admin to set it for you. Also, prepare a comment on /r/thebutton, if possible."); + mp.Working = false; + return; + } + String flair = mp.GetFormattedFlair(); + mp.FlairState().set(FlairStates.Accepted); + FlairComponent.ConfirmUserMessage(mp); + player.sendMessage("§bYour flair has been set:§r " + flair); + mp.Working = false; + } + }; + tt.mp = p; + timer.schedule(tt, 20); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java b/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java new file mode 100644 index 0000000..3243205 --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/flair/FlairComponent.java @@ -0,0 +1,185 @@ +package buttondevteam.chat.components.flair; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.player.TBMCPlayerBase; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.htmlcleaner.HtmlCleaner; +import org.htmlcleaner.TagNode; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class FlairComponent extends Component { + private ConfigData FlairThreadURL() { + return getConfig().getData("flairThreadURL", "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"); + } + + /** + *

+ * This variable is used as a cache for flair state checking when reading the flair thread. + *

+ *

+ * It's used because normally it has to load all associated player files every time to read the flair state + *

+ */ + private Set PlayersWithFlairs = new HashSet<>(); + + @Override + protected void enable() { + registerCommand(new AcceptCommand()); + registerCommand(new IgnoreCommand()); + registerCommand(new SetFlairCommand()); + new Thread(this::FlairGetterThreadMethod).start(); + } + + @Override + protected void disable() { + + } + + private void FlairGetterThreadMethod() { + int errorcount = 0; + while (isEnabled()) { + try { + 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) { + JsonObject item = (JsonObject) obj; + String author = item.get("data").getAsJsonObject().get("author").getAsString(); + String ign = item.get("data").getAsJsonObject().get("body").getAsString(); + int start = ign.indexOf("IGN:") + "IGN:".length(); + if (start == -1 + "IGN:".length()) + continue; + int end = ign.indexOf(' ', start); + if (end == -1 || end == start) + end = ign.indexOf('\n', start); + if (end == -1 || end == start) + ign = ign.substring(start); + else + ign = ign.substring(start, end); + ign = ign.trim(); + if (PlayersWithFlairs.contains(ign)) + continue; + try (ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class)) { // Loads player file + if (mp == null) + continue; + /* + * if (!JoinedBefore(mp, 2015, 6, 5)) continue; + */ + if (!mp.UserNames().contains(author)) + mp.UserNames().add(author); + if (mp.FlairState().get().equals(FlairStates.NoComment)) { + mp.FlairState().set(FlairStates.Commented); + ConfirmUserMessage(mp); + } + PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted + } + } + } catch (Exception e) { + errorcount++; + if (errorcount >= 10) { + errorcount = 0; + if (!e.getMessage().contains("Server returned HTTP response code") + && !(e instanceof UnknownHostException)) + TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e); + } + } + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + public static void DownloadFlair(ChatPlayer mp) throws IOException { + String[] flairdata = TBMCCoreAPI + .DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName().get()) + .replace("\"", "").split(":"); + String flair; + if (flairdata.length > 1) + flair = flairdata[1]; + else + flair = ""; + String flairclass; + if (flairdata.length > 2) + flairclass = flairdata[2]; + else + flairclass = "unknown"; + SetFlair(mp, flair, flairclass, mp.UserName().get()); + } + + private static void SetFlair(ChatPlayer p, String text, String flairclass, String username) { + p.UserName().set(username); + p.FlairState().set(FlairStates.Recognised); + switch (flairclass) { + case "cheater": + p.SetFlair(Short.parseShort(text), true); + return; + case "unknown": + try { + if (CheckForJoinDate(p)) { + if (text.equals("-1")) // If true, only non-presser/can't press; if false, any flair (but we can still detect can't press) + p.SetFlair(ChatPlayer.FlairTimeNonPresser); + else + p.SetFlair(ChatPlayer.FlairTimeNone); // Flair unknown + } else { + p.SetFlair(ChatPlayer.FlairTimeCantPress); + } + } catch (Exception e) { + p.FlairState().set(FlairStates.Commented); // Flair unknown + p.SetFlair(ChatPlayer.FlairTimeNone); + TBMCCoreAPI.SendException("Error while checking join date for player " + p.PlayerName() + "!", e); + } + return; + default: + break; + } + p.SetFlair(Short.parseShort(text)); + } + + private static boolean CheckForJoinDate(ChatPlayer mp) throws Exception { + return JoinedBefore(mp, 2015, 4, 1); + } + + private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception { + URL url = new URL("https://www.reddit.com/u/" + mp.UserName()); + URLConnection con = url.openConnection(); + con.setRequestProperty("User-Agent", "TheButtonAutoFlair"); + InputStream in = con.getInputStream(); + HtmlCleaner cleaner = new HtmlCleaner(); + TagNode node = cleaner.clean(in); + + node = node.getElementsByAttValue("class", "age", true, true)[0]; + node = node.getElementsByName("time", false)[0]; + String joindate = node.getAttributeByName("datetime"); + SimpleDateFormat parserSDF = new SimpleDateFormat("yyyy-MM-dd"); + joindate = joindate.split("T")[0]; + Date date = parserSDF.parse(joindate); + return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day) + .build().getTime()); + } + + public static void ConfirmUserMessage(ChatPlayer mp) { + Player p = Bukkit.getPlayer(mp.getUUID()); + if (mp.FlairState().get().equals(FlairStates.Commented) && p != null) + if (mp.UserNames().size() > 1) + p.sendMessage( + "§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r"); + else + p.sendMessage("§9A Reddit user commented your name. Is that you?§r §6Type /u accept or /u ignore§r"); + } +} diff --git a/src/main/java/buttondevteam/chat/FlairStates.java b/src/main/java/buttondevteam/chat/components/flair/FlairStates.java similarity index 64% rename from src/main/java/buttondevteam/chat/FlairStates.java rename to src/main/java/buttondevteam/chat/components/flair/FlairStates.java index b217d95..3830e2d 100644 --- a/src/main/java/buttondevteam/chat/FlairStates.java +++ b/src/main/java/buttondevteam/chat/components/flair/FlairStates.java @@ -1,5 +1,5 @@ -package buttondevteam.chat; - -public enum FlairStates { - Accepted, Ignored, Recognised, Commented, NoComment -} +package buttondevteam.chat.components.flair; + +public enum FlairStates { + Accepted, Ignored, Recognised, Commented, NoComment +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/IgnoreCommand.java b/src/main/java/buttondevteam/chat/components/flair/IgnoreCommand.java similarity index 92% rename from src/main/java/buttondevteam/chat/commands/ucmds/IgnoreCommand.java rename to src/main/java/buttondevteam/chat/components/flair/IgnoreCommand.java index 4ea2973..a556455 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/IgnoreCommand.java +++ b/src/main/java/buttondevteam/chat/components/flair/IgnoreCommand.java @@ -1,44 +1,43 @@ -package buttondevteam.chat.commands.ucmds; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.FlairStates; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.OptionallyPlayerCommandClass; -import buttondevteam.lib.player.TBMCPlayer; - -@CommandClass(modOnly = false) -@OptionallyPlayerCommandClass(playerOnly = true) -public final class IgnoreCommand extends UCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Ignore flair ----", - "Stop the \"write your name in the thread\" message from showing up" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - final Player player = (Player) sender; - ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); - if (p.FlairState().get().equals(FlairStates.Accepted)) { - player.sendMessage("§cYou can only ignore the \"write your name in the thread\" message."); - return true; - } - if (p.FlairState().get().equals(FlairStates.Commented)) { - player.sendMessage("Sorry, but your flair isn't recorded. Please ask a mod to set it for you."); - return true; - } - if (!p.FlairState().get().equals(FlairStates.Ignored)) { - p.FlairState().set(FlairStates.Ignored); - p.SetFlair(ChatPlayer.FlairTimeNone); - p.UserName().set(""); - player.sendMessage("§bYou have ignored the message.§r"); - } else - player.sendMessage("§cYou already ignored the message.§r"); - return true; - } - -} +package buttondevteam.chat.components.flair; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.commands.ucmds.UCommandBase; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.OptionallyPlayerCommandClass; +import buttondevteam.lib.player.TBMCPlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@CommandClass(modOnly = false) +@OptionallyPlayerCommandClass(playerOnly = true) +public final class IgnoreCommand extends UCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Ignore flair ----", + "Stop the \"write your name in the thread\" message from showing up" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, String[] args) { + final Player player = (Player) sender; + ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); + if (p.FlairState().get().equals(FlairStates.Accepted)) { + player.sendMessage("§cYou can only ignore the \"write your name in the thread\" message."); + return true; + } + if (p.FlairState().get().equals(FlairStates.Commented)) { + player.sendMessage("Sorry, but your flair isn't recorded. Please ask a mod to set it for you."); + return true; + } + if (!p.FlairState().get().equals(FlairStates.Ignored)) { + p.FlairState().set(FlairStates.Ignored); + p.SetFlair(ChatPlayer.FlairTimeNone); + p.UserName().set(""); + player.sendMessage("§bYou have ignored the message.§r"); + } else + player.sendMessage("§cYou already ignored the message.§r"); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/SetFlairCommand.java b/src/main/java/buttondevteam/chat/components/flair/SetFlairCommand.java similarity index 87% rename from src/main/java/buttondevteam/chat/commands/ucmds/admin/SetFlairCommand.java rename to src/main/java/buttondevteam/chat/components/flair/SetFlairCommand.java index e932138..dcd22ac 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/SetFlairCommand.java +++ b/src/main/java/buttondevteam/chat/components/flair/SetFlairCommand.java @@ -1,71 +1,70 @@ -package buttondevteam.chat.commands.ucmds.admin; - -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.FlairStates; -import buttondevteam.lib.player.TBMCPlayerBase; - -public class SetFlairCommand extends AdminCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Set flair -----", "Set a flair for a player", - "Usage: /u admin setflair [username]", - "Example 1: /u admin setflair NorbiPeti 19 false NorbiPeti --> orange (19s)", - "Example 2: /u admin setflair iie 0 true asde --> purple (0s)" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - if (args.length < 3) { - return false; - } - Player p = Bukkit.getPlayer(args[0]); - if (p == null) { - sender.sendMessage("§cPlayer not found.&r"); - return true; - } - short flairtime = 0x00; - if (args[1].equalsIgnoreCase("non-presser")) - flairtime = ChatPlayer.FlairTimeNonPresser; - else if (args[1].equalsIgnoreCase("cant-press")) - flairtime = ChatPlayer.FlairTimeCantPress; - else if (args[1].equalsIgnoreCase("none")) - flairtime = ChatPlayer.FlairTimeNone; - else { - try { - flairtime = Short.parseShort(args[1]); - } catch (Exception e) { - sender.sendMessage( - "§cFlairtime must be a number, \"non-presser\", \"cant-press\" or \"none\". Run without args to see usage."); - return true; - } - } - boolean cheater = false; - if (args[2].equalsIgnoreCase("true")) - cheater = true; - else if (args[2].equalsIgnoreCase("false")) - cheater = false; - else { - sender.sendMessage("§cUnknown value for cheater parameter. Run without args to see usage."); - return true; - } - ChatPlayer mp = TBMCPlayerBase.getPlayer(p.getUniqueId(), ChatPlayer.class); - mp.SetFlair(flairtime, cheater); - mp.FlairState().set(FlairStates.Accepted); - if (args.length < 4) - mp.UserName().set(""); - else { - mp.UserName().set(args[3]); - if (!mp.UserNames().contains(args[3])) - mp.UserNames().add(args[3]); - } - sender.sendMessage( - "§bThe flair has been set. Player: " + mp.PlayerName() + " Flair: " + mp.GetFormattedFlair() + "§r"); - return true; - } - -} +package buttondevteam.chat.components.flair; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.commands.ucmds.admin.AdminCommandBase; +import buttondevteam.lib.player.TBMCPlayerBase; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class SetFlairCommand extends AdminCommandBase { + + @Override + public String[] GetHelpText(String alias) { + return new String[] { "§6---- Set flair -----", "Set a flair for a player", + "Usage: /u admin setflair [username]", + "Example 1: /u admin setflair NorbiPeti 19 false NorbiPeti --> orange (19s)", + "Example 2: /u admin setflair iie 0 true asde --> purple (0s)" }; + } + + @Override + public boolean OnCommand(CommandSender sender, String alias, String[] args) { + if (args.length < 3) { + return false; + } + Player p = Bukkit.getPlayer(args[0]); + if (p == null) { + sender.sendMessage("§cPlayer not found.&r"); + return true; + } + short flairtime = 0x00; + if (args[1].equalsIgnoreCase("non-presser")) + flairtime = ChatPlayer.FlairTimeNonPresser; + else if (args[1].equalsIgnoreCase("cant-press")) + flairtime = ChatPlayer.FlairTimeCantPress; + else if (args[1].equalsIgnoreCase("none")) + flairtime = ChatPlayer.FlairTimeNone; + else { + try { + flairtime = Short.parseShort(args[1]); + } catch (Exception e) { + sender.sendMessage( + "§cFlairtime must be a number, \"non-presser\", \"cant-press\" or \"none\". Run without args to see usage."); + return true; + } + } + boolean cheater; + if (args[2].equalsIgnoreCase("true")) + cheater = true; + else if (args[2].equalsIgnoreCase("false")) + cheater = false; + else { + sender.sendMessage("§cUnknown value for cheater parameter."); + return false; + } + ChatPlayer mp = TBMCPlayerBase.getPlayer(p.getUniqueId(), ChatPlayer.class); + mp.SetFlair(flairtime, cheater); + mp.FlairState().set(FlairStates.Accepted); + if (args.length < 4) + mp.UserName().set(""); + else { + mp.UserName().set(args[3]); + if (!mp.UserNames().contains(args[3])) + mp.UserNames().add(args[3]); + } + sender.sendMessage( + "§bThe flair has been set. Player: " + mp.PlayerName() + " Flair: " + mp.GetFormattedFlair() + "§r"); + return true; + } + +} diff --git a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java b/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java similarity index 86% rename from src/main/java/buttondevteam/chat/components/TownyAnnouncer.java rename to src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java index a368c83..dc579d3 100644 --- a/src/main/java/buttondevteam/chat/components/TownyAnnouncer.java +++ b/src/main/java/buttondevteam/chat/components/towny/TownyAnnouncer.java @@ -1,4 +1,4 @@ -package buttondevteam.chat.components; +package buttondevteam.chat.components.towny; import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.PluginMain; @@ -23,12 +23,12 @@ public class TownyAnnouncer { switch (String.valueOf(m.group(1))) { //valueOf: Handles null case "Town": TBMCChatAPI.SendSystemMessage(PluginMain.TownChat, - new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, false), groupID), + new Channel.RecipientTestResult(TownyComponent.getTownNationIndex(groupID, false), groupID), logRecord.getMessage(), ChatProcessing.MCORIGIN); break; case "Nation": TBMCChatAPI.SendSystemMessage(PluginMain.NationChat, - new Channel.RecipientTestResult(PluginMain.getTownNationIndex(groupID, true), groupID), + new Channel.RecipientTestResult(TownyComponent.getTownNationIndex(groupID, true), groupID), logRecord.getMessage(), ChatProcessing.MCORIGIN); break; case "Global": diff --git a/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java b/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java new file mode 100644 index 0000000..c93cf7e --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/towny/TownyComponent.java @@ -0,0 +1,94 @@ +package buttondevteam.chat.components.towny; + +import buttondevteam.chat.PluginMain; +import buttondevteam.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.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.stream.Collectors; + +public class TownyComponent extends Component { + public static TownyUniverse TU; + private static ArrayList Towns; + private static ArrayList Nations; + + @Override + protected void enable() { + TU = ((Towny) Bukkit.getPluginManager().getPlugin("Towny")).getTownyUniverse(); + 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( + PluginMain.TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false))); + TBMCChatAPI.RegisterChatChannel( + PluginMain.NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true))); + TownyAnnouncer.setup(); + } + + @Override + protected void disable() { + TownyAnnouncer.setdown(); + } + + + /** + * Return the error message for the message sender if they can't send it and the score + */ + private static Channel.RecipientTestResult checkTownNationChat(CommandSender sender, boolean nationchat) { + if (!(sender instanceof Player)) + return new Channel.RecipientTestResult("§cYou are not a player!"); + Resident resident = TU.getResidentMap().get(sender.getName().toLowerCase()); + Channel.RecipientTestResult result = checkTownNationChatInternal(sender, nationchat, resident); + if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it + result = new Channel.RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably + return result; + } + + private static Channel.RecipientTestResult checkTownNationChatInternal(CommandSender sender, boolean nationchat, + Resident resident) { + try { + /* + * p.sendMessage(String.format("[SPY-%s] - %s: %s", channel.DisplayName, ((Player) sender).getDisplayName(), message)); + */ + Town town = null; + if (resident != null && resident.hasTown()) + town = resident.getTown(); + if (town == null) + return new Channel.RecipientTestResult("You aren't in a town."); + Nation nation = null; + int index; + if (nationchat) { + if (town.hasNation()) + nation = town.getNation(); + if (nation == null) + return new Channel.RecipientTestResult("Your town isn't in a nation."); + index = getTownNationIndex(nation.getName(), true); + } else + index = getTownNationIndex(town.getName(), false); + return new Channel.RecipientTestResult(index, nationchat ? nation.getName() : town.getName()); + } catch (NotRegisteredException e) { + return new Channel.RecipientTestResult("You (probably) aren't knwon by Towny! (Not in a town)"); + } + } + + public static int getTownNationIndex(String name, boolean nation) { + val list = nation ? Nations : Towns; + int index = list.indexOf(name); + if (index < 0) { + list.add(name); + index = list.size() - 1; + } + return index; + } +} diff --git a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java index 3a49a4a..196a8d0 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java @@ -1,144 +1,149 @@ -package buttondevteam.chat.listener; - -import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.FlairStates; -import buttondevteam.chat.PlayerJoinTimerTask; -import buttondevteam.chat.PluginMain; -import buttondevteam.chat.commands.UnlolCommand; -import buttondevteam.chat.commands.ucmds.HistoryCommand; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.player.TBMCPlayerJoinEvent; -import buttondevteam.lib.player.TBMCPlayerLoadEvent; -import buttondevteam.lib.player.TBMCPlayerSaveEvent; -import com.earth2me.essentials.User; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Arrays; -import java.util.Optional; -import java.util.Timer; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiFunction; - -public class PlayerJoinLeaveListener implements Listener { - - @EventHandler - public void onPlayerLoad(TBMCPlayerLoadEvent e) { - ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class); - cp.FlairUpdate(); - } - - @EventHandler - public void onPlayerTBMCJoin(TBMCPlayerJoinEvent e) { - ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class); - Player p = Bukkit.getPlayer(cp.getUUID()); - - if (!cp.FlairState().get().equals(FlairStates.NoComment)) { - PluginMain.ConfirmUserMessage(cp); - Timer timer = new Timer(); - PlayerJoinTimerTask tt = new PlayerJoinTimerTask() { - @Override - public void run() { - mp.FlairUpdate(); - } - }; - tt.mp = cp; - timer.schedule(tt, 1000); - } //TODO: Better Reddit integration (OAuth) - - String nwithoutformatting = PluginMain.essentials.getUser(p).getNickname(); - - int index; - if (nwithoutformatting != null) { - while ((index = nwithoutformatting.indexOf("§k")) != -1) - nwithoutformatting = nwithoutformatting.replace("§k" + nwithoutformatting.charAt(index + 2), ""); // Support for one random char - while ((index = nwithoutformatting.indexOf('§')) != -1) - nwithoutformatting = nwithoutformatting.replace("§" + nwithoutformatting.charAt(index + 1), ""); - } else - nwithoutformatting = p.getName(); - PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); - - updatePlayerColors(p, cp); //TO!DO: Doesn't have effect - It can help to register the listener - - if (cp.ChatOnly || p.getGameMode().equals(GameMode.SPECTATOR)) { - cp.ChatOnly = false; - p.setGameMode(GameMode.SURVIVAL); - } - - HistoryCommand.showHistory(e.getPlayer(), "u history", new String[0], null); - } - - @EventHandler - public void onPlayerSave(TBMCPlayerSaveEvent e) { - } - - @EventHandler - public void onPlayerLeave(PlayerQuitEvent event) { - PlayerListener.nicknames.inverse().remove(event.getPlayer().getUniqueId()); - UnlolCommand.Lastlol.values().removeIf(lld -> lld.getLolowner().equals(event.getPlayer())); - } - - private static String getPlayerNickname(Player player, User user, ChatPlayer cp) { - String nickname = user.getNick(true); - if (nickname.contains("~")) //StartsWith doesn't work because of color codes - nickname = nickname.replace("~", ""); //It gets stacked otherwise - String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members - val res = PluginMain.TU.getResidentMap().get(player.getName().toLowerCase()); - if (res == null || !res.hasTown()) - return name; - try { - Color[] clrs = Optional.ofNullable( - PluginMain.TownColors.get(res.getTown().getName().toLowerCase()) - ).orElse(new Color[]{Color.White}); //Use white as default town color - StringBuilder ret = new StringBuilder(); - AtomicInteger prevlen = new AtomicInteger(); - BiFunction anyColoredNamePart = (c, len) -> "§" //Len==0 if last part - + Integer.toHexString(c.ordinal()) // 'Odds' are the last character is chopped off so we make sure to include all chars at the end - + (len == 0 ? name.substring(prevlen.get()) - : name.substring(prevlen.get(), prevlen.addAndGet(len))); - BiFunction coloredNamePart = (len, i) - -> anyColoredNamePart.apply(clrs[i], i + 1 == clrs.length ? 0 : len); - final int len = name.length() / (clrs.length + 1); //The above param is needed because this isn't always passed - Color nc; - /*if(res.getTown().hasNation() - &&(nc=PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase()))!=null) - len = name.length() / (clrs.length+1); - else - len = name.length() / clrs.length;*/ - val nclar = cp.NameColorLocations().get(); - int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray(); - if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + 1)) //+1: Nation color - ncl = null; // Reset if name length changed - //System.out.println("ncl: "+Arrays.toString(ncl)+" - sum: "+Arrays.stream(ncl).sum()+" - name len: "+name.length()); - if (!res.getTown().hasNation() - || (nc = PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase())) == null) - nc = Color.White; - ret.append(anyColoredNamePart.apply(nc, ncl == null ? len : ncl[0])); //Make first color the nation color - for (int i = 0; i < clrs.length; i++) - //ret.append(coloredNamePart.apply(ncl == null ? len : (nc==null?ncl[i]:ncl[i+1]), i)); - ret.append(coloredNamePart.apply(ncl == null ? len : ncl[i + 1], i)); - return ret.toString(); - } catch (NotRegisteredException e) { - return nickname; - } - } - - public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor) - updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class)); - } - - @SuppressWarnings("WeakerAccess") - public static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames - User user = PluginMain.essentials.getUser(player); - user.setNickname(getPlayerNickname(player, user, cp)); - user.setDisplayNick(); //These won't fire the nick change event - cp.FlairUpdate(); //Update in list - } -} +package buttondevteam.chat.listener; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.PlayerJoinTimerTask; +import buttondevteam.chat.PluginMain; +import buttondevteam.chat.commands.UnlolCommand; +import buttondevteam.chat.commands.ucmds.HistoryCommand; +import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.flair.FlairStates; +import buttondevteam.chat.components.towny.TownyComponent; +import buttondevteam.core.ComponentManager; +import buttondevteam.lib.chat.Color; +import buttondevteam.lib.player.TBMCPlayerJoinEvent; +import buttondevteam.lib.player.TBMCPlayerLoadEvent; +import buttondevteam.lib.player.TBMCPlayerSaveEvent; +import com.earth2me.essentials.User; +import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.Arrays; +import java.util.Optional; +import java.util.Timer; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; + +public class PlayerJoinLeaveListener implements Listener { + + @EventHandler + public void onPlayerLoad(TBMCPlayerLoadEvent e) { + ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class); + cp.FlairUpdate(); + } + + @EventHandler + public void onPlayerTBMCJoin(TBMCPlayerJoinEvent e) { + ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class); + Player p = Bukkit.getPlayer(cp.getUUID()); + + if (ComponentManager.isEnabled(FlairComponent.class)) { + if (!cp.FlairState().get().equals(FlairStates.NoComment)) { + FlairComponent.ConfirmUserMessage(cp); + Timer timer = new Timer(); + PlayerJoinTimerTask tt = new PlayerJoinTimerTask() { + @Override + public void run() { + mp.FlairUpdate(); + } + }; + tt.mp = cp; + timer.schedule(tt, 1000); + } //TODO: Better Reddit integration (OAuth) + } + + String nwithoutformatting = PluginMain.essentials.getUser(p).getNickname(); + + int index; + if (nwithoutformatting != null) { + while ((index = nwithoutformatting.indexOf("§k")) != -1) + nwithoutformatting = nwithoutformatting.replace("§k" + nwithoutformatting.charAt(index + 2), ""); // Support for one random char + while ((index = nwithoutformatting.indexOf('§')) != -1) + nwithoutformatting = nwithoutformatting.replace("§" + nwithoutformatting.charAt(index + 1), ""); + } else + nwithoutformatting = p.getName(); + PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); + + updatePlayerColors(p, cp); //TO!DO: Doesn't have effect - It can help to register the listener + + if (cp.ChatOnly || p.getGameMode().equals(GameMode.SPECTATOR)) { + cp.ChatOnly = false; + p.setGameMode(GameMode.SURVIVAL); + } + + HistoryCommand.showHistory(e.getPlayer(), "u history", new String[0], null); + } + + @EventHandler + public void onPlayerSave(TBMCPlayerSaveEvent e) { + } + + @EventHandler + public void onPlayerLeave(PlayerQuitEvent event) { + PlayerListener.nicknames.inverse().remove(event.getPlayer().getUniqueId()); + UnlolCommand.Lastlol.values().removeIf(lld -> lld.getLolowner().equals(event.getPlayer())); + } + + private static String getPlayerNickname(Player player, User user, ChatPlayer cp) { + String nickname = user.getNick(true); + if (nickname.contains("~")) //StartsWith doesn't work because of color codes + nickname = nickname.replace("~", ""); //It gets stacked otherwise + String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members + val res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase()); + if (res == null || !res.hasTown()) + return name; + try { + Color[] clrs = Optional.ofNullable( + PluginMain.TownColors.get(res.getTown().getName().toLowerCase()) + ).orElse(new Color[]{Color.White}); //Use white as default town color + StringBuilder ret = new StringBuilder(); + AtomicInteger prevlen = new AtomicInteger(); + BiFunction anyColoredNamePart = (c, len) -> "§" //Len==0 if last part + + Integer.toHexString(c.ordinal()) // 'Odds' are the last character is chopped off so we make sure to include all chars at the end + + (len == 0 ? name.substring(prevlen.get()) + : name.substring(prevlen.get(), prevlen.addAndGet(len))); + BiFunction coloredNamePart = (len, i) + -> anyColoredNamePart.apply(clrs[i], i + 1 == clrs.length ? 0 : len); + final int len = name.length() / (clrs.length + 1); //The above param is needed because this isn't always passed + Color nc; + /*if(res.getTown().hasNation() + &&(nc=PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase()))!=null) + len = name.length() / (clrs.length+1); + else + len = name.length() / clrs.length;*/ + val nclar = cp.NameColorLocations().get(); + int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray(); + if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + 1)) //+1: Nation color + ncl = null; // Reset if name length changed + //System.out.println("ncl: "+Arrays.toString(ncl)+" - sum: "+Arrays.stream(ncl).sum()+" - name len: "+name.length()); + if (!res.getTown().hasNation() + || (nc = PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase())) == null) + nc = Color.White; + ret.append(anyColoredNamePart.apply(nc, ncl == null ? len : ncl[0])); //Make first color the nation color + for (int i = 0; i < clrs.length; i++) + //ret.append(coloredNamePart.apply(ncl == null ? len : (nc==null?ncl[i]:ncl[i+1]), i)); + ret.append(coloredNamePart.apply(ncl == null ? len : ncl[i + 1], i)); + return ret.toString(); + } catch (NotRegisteredException e) { + return nickname; + } + } + + public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor) + updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class)); + } + + @SuppressWarnings("WeakerAccess") + public static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames + User user = PluginMain.essentials.getUser(player); + user.setNickname(getPlayerNickname(player, user, cp)); + user.setDisplayNick(); //These won't fire the nick change event + cp.FlairUpdate(); //Update in list + } +} diff --git a/src/main/java/buttondevteam/chat/listener/PlayerListener.java b/src/main/java/buttondevteam/chat/listener/PlayerListener.java index e077f8f..42dd4ef 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerListener.java @@ -4,9 +4,11 @@ import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.PluginMain; import buttondevteam.chat.commands.ucmds.HistoryCommand; +import buttondevteam.chat.components.flair.FlairComponent; import buttondevteam.component.channel.Channel; import buttondevteam.component.channel.ChatChannelRegisterEvent; import buttondevteam.component.channel.ChatRoom; +import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.ChatMessage; @@ -50,15 +52,9 @@ public class PlayerListener implements Listener { */ public static BiMap nicknames = HashBiMap.create(); - public static boolean Enable = false; - - public static int LoginWarningCountTotal = 5; - public static String NotificationSound; public static double NotificationPitch; - public static boolean ShowRPTag = false; - public final static String[] LaughStrings = new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}; @EventHandler(priority = EventPriority.HIGHEST) @@ -88,7 +84,7 @@ public class PlayerListener implements Listener { return false; // ^^ We can only store player or console channels - Directly sending to channels would still work if they had an event cmd = sender instanceof ConsoleCommandSender ? message : message.substring(1); - for (Channel channel : Channel.getChannels()) { + for (Channel channel : ((Iterable) Channel.getChannels()::iterator)) { //Using Stream.forEach would be too easy if (checkchid.test(channel, cmd)) { Channel oldch = mp.channel().get(); if (oldch instanceof ChatRoom) @@ -130,7 +126,7 @@ public class PlayerListener implements Listener { return true; } } else - for (Channel channel : Channel.getChannels()) { + for (Channel channel : (Iterable) Channel.getChannels()::iterator) { if (checkchid.test(channel, cmd)) { //Apparently method references don't require final variables TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, mp, message.substring(index + 1)).build(), channel); return true; @@ -173,13 +169,10 @@ public class PlayerListener implements Listener { public static boolean ActiveF = false; public static ChatPlayer FPlayer = null; public static BukkitTask Ftask = null; - public static int AlphaDeaths; public static ArrayList Fs = new ArrayList<>(); @EventHandler public void onPlayerDeath(PlayerDeathEvent e) { - if (e.getEntity().getName().equals("Alpha_Bacca44")) - AlphaDeaths++; // MinigamePlayer mgp = Minigames.plugin.pdata.getMinigamePlayer(e.getEntity()); if (/* (mgp != null && !mgp.isInMinigame()) && */ new Random().nextBoolean()) { // Don't store Fs for NPCs Runnable tt = () -> { @@ -249,9 +242,11 @@ public class PlayerListener implements Listener { e.addInfo("Minecraft name: " + cp.PlayerName().get()); if (cp.UserName().get() != null && cp.UserName().get().length() > 0) e.addInfo("Reddit name: " + cp.UserName().get()); - final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand); - if (flair.length() > 0) - e.addInfo("/r/TheButton flair: " + flair); + if (ComponentManager.isEnabled(FlairComponent.class)) { + final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand); + if (flair.length() > 0) + e.addInfo("/r/TheButton flair: " + flair); + } e.addInfo(String.format("Respect: %.2f", cp.getF())); } catch (Exception ex) { TBMCCoreAPI.SendException("Error while providing chat info for player " + e.getPlayer().getFileName(), ex); From 0802de4b6f5442db4b24535fefe3db0fbc51bad8 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 17 Jan 2019 22:23:04 +0100 Subject: [PATCH 6/7] TC/NC & Removed old config stuff Moved town/nation colors into their component Removed save command that was apparently there since 2015 It still loads the town/nation colors from the old config if needed Notification sound/pitch were the last config options to be converted over #85 --- pom.xml | 542 +++++++++--------- .../buttondevteam/chat/ChatProcessing.java | 18 +- .../java/buttondevteam/chat/PluginMain.java | 119 +--- .../commands/ucmds/admin/SaveCommand.java | 23 - .../chat/components/TownColorComponent.java | 24 - .../towncolors}/NColorCommand.java | 11 +- .../towncolors}/NationColorCommand.java | 5 +- .../towncolors}/TownColorCommand.java | 16 +- .../towncolors/TownColorComponent.java | 201 +++++++ .../towncolors}/TownyListener.java | 18 +- .../towncolors}/admin/NationColorCommand.java | 10 +- .../towncolors}/admin/TCCount.java | 8 +- .../towncolors}/admin/TownColorCommand.java | 16 +- .../listener/PlayerJoinLeaveListener.java | 69 +-- .../chat/listener/PlayerListener.java | 6 +- 15 files changed, 556 insertions(+), 530 deletions(-) delete mode 100644 src/main/java/buttondevteam/chat/commands/ucmds/admin/SaveCommand.java delete mode 100644 src/main/java/buttondevteam/chat/components/TownColorComponent.java rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/NColorCommand.java (87%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/NationColorCommand.java (89%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/TownColorCommand.java (76%) create mode 100644 src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java rename src/main/java/buttondevteam/chat/{listener => components/towncolors}/TownyListener.java (77%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/admin/NationColorCommand.java (82%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/admin/TCCount.java (67%) rename src/main/java/buttondevteam/chat/{commands/ucmds => components/towncolors}/admin/TownColorCommand.java (85%) diff --git a/pom.xml b/pom.xml index 67ca3b2..b8cbcb0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,263 +1,281 @@ - - 4.0.0 - 0.0.1-SNAPSHOT - The Button Minecraft Chat Plugin - The Button Minecraft Chat Plugin - - src/main/java - - - src - - **/*.java - - - - src/main/resources - - *.properties - *.yml - *.csv - *.txt - - true - - - ButtonChat - - - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.2 - - - package - - shade - - - - - net.sourceforge.htmlcleaner:htmlcleaner - org.javassist:javassist - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.1 - - - copy - compile - - copy-resources - - - target - - - resources - - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.12.4 - - - - integration-test - verify - - test - - - - true - false - - - - - - - - buttondevteam - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - jitpack - https://jitpack.io/ - - - Essentials - http://repo.ess3.net/content/repositories/essrel/ - - - Votifier - https://dl.bintray.com/nuvotifier/maven/ - - - Minigames - http://maven.addstar.com.au/artifactory/release - - - vault-repo - http://nexus.hc.to/content/repositories/pub_releases - - - - projectlombok.org - http://projectlombok.org/mavenrepo - - - - - org.spigotmc - spigot-api - 1.12.2-R0.1-SNAPSHOT - - - com.github.TBMCPlugins.ButtonCore - ButtonCore - ${env.TRAVIS_BRANCH}-SNAPSHOT - - - - net.sourceforge.htmlcleaner - htmlcleaner - 2.16 - - - - org.reflections - reflections - 0.9.10 - - - net.ess3 - Essentials - 2.13.1 - - - com.github.TBMCPlugins.ButtonCore - Towny - 8d3b6b6 - - - com.vexsoftware - nuvotifier-universal - 2.3.4 - - - - net.milkbowl.vault - VaultAPI - 1.6 - provided - - - org.projectlombok - lombok - 1.16.16 - provided - - - org.spigotmc - spigot - 1.12.2-R0.1-SNAPSHOT - provided - - - com.github.webbukkit - Dynmap-Towny - master-SNAPSHOT - - - com.github.webbukkit - Dynmap - v2.5 - - - - junit - junit - 4.12 - test - - - ButtonChat - - TBMCPlugins - https://github.com/TBMCPlugins - - - - githubo - UTF-8 - + + 4.0.0 + 0.0.1-SNAPSHOT + The Button Minecraft Chat Plugin + The Button Minecraft Chat Plugin + + src/main/java + + + src + + **/*.java + + + + src/main/resources + + *.properties + *.yml + *.csv + *.txt + + true + + + ButtonChat + + + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.2 + + + package + + shade + + + + + net.sourceforge.htmlcleaner:htmlcleaner + org.javassist:javassist + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + + copy + compile + + copy-resources + + + target + + + resources + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.12.4 + + + + integration-test + verify + + test + + + + true + false + + + + + + + + buttondevteam + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + jitpack + https://jitpack.io/ + + + Essentials + http://repo.ess3.net/content/repositories/essrel/ + + + Votifier + https://dl.bintray.com/nuvotifier/maven/ + + + Minigames + http://maven.addstar.com.au/artifactory/release + + + vault-repo + http://nexus.hc.to/content/repositories/pub_releases + + + + projectlombok.org + http://projectlombok.org/mavenrepo + + + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + + + com.github.TBMCPlugins.ButtonCore + ButtonCore + ${branch}-SNAPSHOT + + + + net.sourceforge.htmlcleaner + htmlcleaner + 2.16 + + + + org.reflections + reflections + 0.9.10 + + + net.ess3 + Essentials + 2.13.1 + + + com.github.TBMCPlugins.ButtonCore + Towny + 8d3b6b6 + + + com.vexsoftware + nuvotifier-universal + 2.3.4 + + + + net.milkbowl.vault + VaultAPI + 1.6 + provided + + + org.projectlombok + lombok + 1.16.16 + provided + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + + com.github.webbukkit + Dynmap-Towny + master-SNAPSHOT + + + com.github.webbukkit + Dynmap + v2.5 + + + + junit + junit + 4.12 + test + + + ButtonChat + + TBMCPlugins + https://github.com/TBMCPlugins + + + + githubo + UTF-8 + + master + + + + + + ci + + + env.TRAVIS_BRANCH + + + + + ${env.TRAVIS_BRANCH} + + + \ No newline at end of file diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index 5bcf174..0fc251c 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -46,7 +46,7 @@ public class ChatProcessing { 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 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 Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, @@ -285,11 +285,11 @@ public class ChatProcessing { } ChatPlayer mpp = TBMCPlayer.getPlayer(nottest ? p.getUniqueId() : new UUID(0, 0), ChatPlayer.class); if (nottest) { - if (PlayerListener.NotificationSound == null) + 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(), PlayerListener.NotificationSound, 1.0f, - (float) PlayerListener.NotificationPitch); + p.playSound(p.getLocation(), PluginMain.Instance.notificationSound().get(), 1.0f, + PluginMain.Instance.notificationPitch().get()); } 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 @@ -305,11 +305,11 @@ public class ChatProcessing { + match.toLowerCase() + " but was reported as online."); return "§c" + match + "§r"; } - if (PlayerListener.NotificationSound == null) - p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f); - else - p.playSound(p.getLocation(), PlayerListener.NotificationSound, 1.0f, - (float) PlayerListener.NotificationPitch); + 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()); return PluginMain.essentials.getUser(p).getNickname(); } error.accept("Player nicknamed " + match.toLowerCase() diff --git a/src/main/java/buttondevteam/chat/PluginMain.java b/src/main/java/buttondevteam/chat/PluginMain.java index 1599d6f..16cd62f 100644 --- a/src/main/java/buttondevteam/chat/PluginMain.java +++ b/src/main/java/buttondevteam/chat/PluginMain.java @@ -1,42 +1,30 @@ package buttondevteam.chat; import buttondevteam.chat.commands.YeehawCommand; -import buttondevteam.chat.commands.ucmds.TownColorCommand; -import buttondevteam.chat.components.TownColorComponent; import buttondevteam.chat.components.announce.AnnouncerComponent; import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.towncolors.TownColorComponent; +import buttondevteam.chat.components.towncolors.TownyListener; import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.chat.listener.PlayerListener; -import buttondevteam.chat.listener.TownyListener; import buttondevteam.component.channel.Channel; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; import com.earth2me.essentials.Essentials; -import lombok.val; import net.milkbowl.vault.chat.Chat; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scoreboard.Scoreboard; -import org.dynmap.towny.DTBridge; -import org.dynmap.towny.DynmapTownyPlugin; -import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. +public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15. // A user, which flair isn't obtainable: // https://www.reddit.com/r/thebutton/comments/31c32v/i_pressed_the_button_without_really_thinking/ public static PluginMain Instance; @@ -47,9 +35,17 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. public static Channel TownChat; public static Channel NationChat; + public ConfigData notificationSound() { + return getIConfig().getData("notificationSound", ""); + } + + public ConfigData notificationPitch() { + return getIConfig().getData("notificationPitch", 1.0f); + } + // Fired when plugin is first enabled @Override - public void onEnable() { + public void pluginEnable() { Instance = this; PluginMain.essentials = (Essentials) (Bukkit.getPluginManager().getPlugin("Essentials")); @@ -58,24 +54,13 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. TBMCCoreAPI.RegisterEventsForExceptions(new TownyListener(), this); TBMCChatAPI.AddCommands(this, YeehawCommand.class); Console = this.getServer().getConsoleSender(); - LoadFiles(); SB = getServer().getScoreboardManager().getMainScoreboard(); // Main can be detected with @a[score_...] Component.registerComponent(this, new TownyComponent()); - TownColors.keySet().removeIf(t -> !TownyComponent.TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns - NationColor.keySet().removeIf(n -> !TownyComponent.TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations TBMCChatAPI.RegisterChatChannel(new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global - Bukkit.getScheduler().runTask(this, () -> { - val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); - if (dtp == null) - return; - for (val entry : TownColors.entrySet()) - setTownColor(dtp, buttondevteam.chat.commands.ucmds.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue()); - }); - if (!setupEconomy() || !setupPermissions()) TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up economy or permissions!")); @@ -84,85 +69,11 @@ public class PluginMain extends JavaPlugin { // Translated to Java: 2015.07.15. Component.registerComponent(this, new AnnouncerComponent()); } - /** - * Sets a town's color on Dynmap. - * - * @param dtp A reference for the Dynmap-Towny plugin - * @param town The town's name using the correct casing - * @param colors The town's colors - */ - public static void setTownColor(DynmapTownyPlugin dtp, String town, Color[] colors) { - Function c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue(); - try { - DTBridge.setTownColor(dtp, town, c2i.apply(colors[0]), - c2i.apply(colors.length > 1 ? colors[1] : colors[0])); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e); - } - } - public static Essentials essentials = null; // Fired when plugin is disabled @Override - public void onDisable() { - SaveFiles(); - } - - /** - * Names lowercased - */ - public static Map TownColors = new HashMap<>(); - /** - * Names lowercased - nation color gets added to town colors when needed - */ - public static Map NationColor = new HashMap<>(); - - @SuppressWarnings("unchecked") - private static void LoadFiles() { - PluginMain.Instance.getLogger().info("Loading files..."); - try { - File file = new File("TBMC/chatsettings.yml"); - if (file.exists()) { - YamlConfiguration yc = new YamlConfiguration(); - yc.load(file); - PlayerListener.NotificationSound = yc.getString("notificationsound"); - PlayerListener.NotificationPitch = yc.getDouble("notificationpitch"); - val cs = yc.getConfigurationSection("towncolors"); - if (cs != null) - TownColors.putAll(cs.getValues(true).entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, v -> ((List) v.getValue()).stream() - .map(Color::valueOf).toArray(Color[]::new)))); - TownColorCommand.ColorCount = (byte) yc.getInt("towncolorcount", 1); - val ncs = yc.getConfigurationSection("nationcolors"); - if (ncs != null) - NationColor.putAll(ncs.getValues(true).entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue())))); - PluginMain.Instance.getLogger().info("Loaded files!"); - } else - PluginMain.Instance.getLogger().info("No files to load, first run probably."); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while loading chat files!", e); - } - } - - public static void SaveFiles() { - PluginMain.Instance.getLogger().info("Saving files..."); - try { - File file = new File("TBMC/chatsettings.yml"); - YamlConfiguration yc = new YamlConfiguration(); - yc.set("notificationsound", PlayerListener.NotificationSound); - yc.set("notificationpitch", PlayerListener.NotificationPitch); - yc.createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, - v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); - yc.set("towncolorcount", TownColorCommand.ColorCount); - yc.createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, - v -> v.getValue().toString()))); - yc.save(file); - PluginMain.Instance.getLogger().info("Saved files!"); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while loading chat files!", e); - } + public void pluginDisable() { } public static Permission permission = null; diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/SaveCommand.java b/src/main/java/buttondevteam/chat/commands/ucmds/admin/SaveCommand.java deleted file mode 100644 index 552d1b6..0000000 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/SaveCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package buttondevteam.chat.commands.ucmds.admin; - -import org.bukkit.command.CommandSender; - -import buttondevteam.chat.PluginMain; - -public class SaveCommand extends AdminCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { "§6---- Save config ----", - "This command saves the config file(s)" }; - } - - @Override - public boolean OnCommand(CommandSender sender, String alias, - String[] args) { - PluginMain.SaveFiles(); // 2015.08.09. - sender.sendMessage("§bSaved files. Now you can edit them and reload if you want.§r"); - return true; - } - -} diff --git a/src/main/java/buttondevteam/chat/components/TownColorComponent.java b/src/main/java/buttondevteam/chat/components/TownColorComponent.java deleted file mode 100644 index 8a82040..0000000 --- a/src/main/java/buttondevteam/chat/components/TownColorComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -package buttondevteam.chat.components; - -import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.architecture.ConfigData; - -public class TownColorComponent extends Component { - public ConfigData colorCount() { //TODO - return getConfig().getData("colorCount", (byte) 1, cc -> (byte) cc, cc -> (int) cc); - } - - public ConfigData useNationColors() { //TODO - return getConfig().getData("useNationColors", true); - } - - @Override - protected void enable() { - //TODO: Don't register all commands automatically (welp) - } - - @Override - protected void disable() { - - } -} diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/NColorCommand.java similarity index 87% rename from src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java rename to src/main/java/buttondevteam/chat/components/towncolors/NColorCommand.java index 4c9943e..5234490 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/NColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/NColorCommand.java @@ -1,9 +1,8 @@ -package buttondevteam.chat.commands.ucmds; +package buttondevteam.chat.components.towncolors; import buttondevteam.chat.ChatPlayer; -import buttondevteam.chat.PluginMain; +import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.components.towny.TownyComponent; -import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.OptionallyPlayerCommandClass; @@ -54,7 +53,7 @@ public class NColorCommand extends UCommandBase { return true; } String[] nameparts = arg.split("[|:]"); - Color[] towncolors = PluginMain.TownColors.get(town.getName().toLowerCase()); + Color[] towncolors = TownColorComponent.TownColors.get(town.getName().toLowerCase()); if (towncolors == null) { player.sendMessage("§cYour town doesn't have a color set. The town mayor can set it using /u towncolor."); return true; @@ -72,8 +71,8 @@ public class NColorCommand extends UCommandBase { return true; } ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class).NameColorLocations() - .set(new ArrayList<>(Arrays.stream(nameparts).map(np -> np.length()).collect(Collectors.toList()))); // No byte[], no TIntArrayList - PlayerJoinLeaveListener.updatePlayerColors(player); + .set(new ArrayList<>(Arrays.stream(nameparts).map(String::length).collect(Collectors.toList()))); // No byte[], no TIntArrayList + TownColorComponent.updatePlayerColors(player); player.sendMessage("§bName colors set: " + player.getDisplayName()); return true; } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/NationColorCommand.java similarity index 89% rename from src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java rename to src/main/java/buttondevteam/chat/components/towncolors/NationColorCommand.java index 8cba718..4c4c1ad 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/NationColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/NationColorCommand.java @@ -1,5 +1,6 @@ -package buttondevteam.chat.commands.ucmds; +package buttondevteam.chat.components.towncolors; +import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.CommandClass; @@ -44,6 +45,6 @@ public class NationColorCommand extends UCommandBase { player.sendMessage("§cCouldn't find your town/nation... Error reported."); return true; } - return buttondevteam.chat.commands.ucmds.admin.NationColorCommand.SetNationColor(player, alias, a); + return buttondevteam.chat.components.towncolors.admin.NationColorCommand.SetNationColor(player, alias, a); } } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/TownColorCommand.java similarity index 76% rename from src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java rename to src/main/java/buttondevteam/chat/components/towncolors/TownColorCommand.java index bdda3d8..685d5ac 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/TownColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/TownColorCommand.java @@ -1,11 +1,13 @@ -package buttondevteam.chat.commands.ucmds; +package buttondevteam.chat.components.towncolors; +import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.OptionallyPlayerCommandClass; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.object.Resident; +import lombok.val; import org.bukkit.entity.Player; @CommandClass // TODO: /u u when annotation not present @@ -14,7 +16,8 @@ public class TownColorCommand extends UCommandBase { @Override public String GetHelpText(String alias)[] { StringBuilder cns = new StringBuilder(" "); - for (int i = 2; i <= ColorCount; i++) + val comp = (TownColorComponent) getComponent(); + for (int i = 2; i <= comp.colorCount().get(); i++) cns.append(" [colorname").append(i).append("]"); return new String[] { // "§6---- Town Color ----", // @@ -26,8 +29,6 @@ public class TownColorCommand extends UCommandBase { }; } - public static byte ColorCount; - @Override public boolean OnCommand(Player player, String alias, String[] args) { Resident res; @@ -36,8 +37,9 @@ public class TownColorCommand extends UCommandBase { player.sendMessage("§cYou need to be the mayor of a town to set it's colors."); return true; } - if (args.length > ColorCount) { - player.sendMessage("You can only use " + ColorCount + " color" + (ColorCount > 1 ? "s" : "") + "."); + val comp = (TownColorComponent) getComponent(); + if (args.length > comp.colorCount().get()) { + player.sendMessage("You can only use " + comp.colorCount().get() + " color" + (comp.colorCount().get() > 1 ? "s" : "") + "."); return true; } String[] a = new String[args.length + 1]; @@ -49,6 +51,6 @@ public class TownColorCommand extends UCommandBase { player.sendMessage("§cCouldn't find your town... Error reported."); return true; } - return buttondevteam.chat.commands.ucmds.admin.TownColorCommand.SetTownColor(player, alias, a); + return buttondevteam.chat.components.towncolors.admin.TownColorCommand.SetTownColor(player, alias, a); } } diff --git a/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java new file mode 100644 index 0000000..a44bdbe --- /dev/null +++ b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java @@ -0,0 +1,201 @@ +package buttondevteam.chat.components.towncolors; + +import buttondevteam.chat.ChatPlayer; +import buttondevteam.chat.PluginMain; +import buttondevteam.chat.components.towncolors.admin.TCCount; +import buttondevteam.chat.components.towny.TownyComponent; +import buttondevteam.core.ComponentManager; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ComponentMetadata; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.chat.Color; +import com.earth2me.essentials.User; +import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import lombok.experimental.var; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.dynmap.towny.DTBridge; +import org.dynmap.towny.DynmapTownyPlugin; + +import java.io.File; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +@ComponentMetadata(depends = TownyComponent.class) +public class TownColorComponent extends Component { + /** + * Names lowercased + */ + public static Map TownColors = new HashMap<>(); + /** + * Names lowercased - nation color gets added to town colors when needed + */ + public static Map NationColor = new HashMap<>(); + + public ConfigData colorCount() { + return getConfig().getData("colorCount", (byte) 1, cc -> (byte) cc, cc -> (int) cc); + } + + public ConfigData useNationColors() { //TODO + return getConfig().getData("useNationColors", true); + } + + @SuppressWarnings("unchecked") + @Override + protected void enable() { + //TODO: Don't register all commands automatically (welp) + Consumer loadTC = cs -> TownColorComponent.TownColors.putAll(cs.getValues(true).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, v -> ((List) v.getValue()).stream() + .map(Color::valueOf).toArray(Color[]::new)))); + Consumer loadNC = ncs -> + TownColorComponent.NationColor.putAll(ncs.getValues(true).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue())))); + var cs = getConfig().getConfig().getConfigurationSection("towncolors"); + if (cs != null) + loadTC.accept(cs); + else + load_old(loadTC, null); //Load old data + var ncs = getConfig().getConfig().getConfigurationSection("nationcolors"); + if (ncs != null) + loadNC.accept(ncs); + else + load_old(null, loadNC); //Why not choose by making different args null + + TownColors.keySet().removeIf(t -> !TownyComponent.TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns + NationColor.keySet().removeIf(n -> !TownyComponent.TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations + + Bukkit.getScheduler().runTask(getPlugin(), () -> { + val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); + if (dtp == null) + return; + for (val entry : TownColors.entrySet()) + setTownColor(dtp, buttondevteam.chat.components.towncolors.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue()); + }); + + registerCommand(new TownColorCommand()); + registerCommand(new NationColorCommand()); + registerCommand(new buttondevteam.chat.components.towncolors.admin.TownColorCommand()); + registerCommand(new buttondevteam.chat.components.towncolors.admin.NationColorCommand()); + registerCommand(new TCCount()); + } + + @Override + protected void disable() { + getConfig().getConfig().createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); + getConfig().getConfig().createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + v -> v.getValue().toString()))); + } + + /** + * Sets a town's color on Dynmap. + * + * @param dtp A reference for the Dynmap-Towny plugin + * @param town The town's name using the correct casing + * @param colors The town's colors + */ + + public static void setTownColor(DynmapTownyPlugin dtp, String town, Color[] colors) { + Function c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue(); + try { + DTBridge.setTownColor(dtp, town, c2i.apply(colors[0]), + c2i.apply(colors.length > 1 ? colors[1] : colors[0])); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e); + } + } + + private static String getPlayerNickname(Player player, User user, ChatPlayer cp) { + String nickname = user.getNick(true); + if (nickname.contains("~")) //StartsWith doesn't work because of color codes + nickname = nickname.replace("~", ""); //It gets stacked otherwise + String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members + val res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase()); + if (res == null || !res.hasTown()) + return name; + try { + Color[] clrs = Optional.ofNullable( + TownColors.get(res.getTown().getName().toLowerCase()) + ).orElse(new Color[]{Color.White}); //Use white as default town color + StringBuilder ret = new StringBuilder(); + AtomicInteger prevlen = new AtomicInteger(); + BiFunction anyColoredNamePart = (c, len) -> "§" //Len==0 if last part + + Integer.toHexString(c.ordinal()) // 'Odds' are the last character is chopped off so we make sure to include all chars at the end + + (len == 0 ? name.substring(prevlen.get()) + : name.substring(prevlen.get(), prevlen.addAndGet(len))); + BiFunction coloredNamePart = (len, i) + -> anyColoredNamePart.apply(clrs[i], i + 1 == clrs.length ? 0 : len); + final int len = name.length() / (clrs.length + 1); //The above param is needed because this isn't always passed + Color nc; + /*if(res.getTown().hasNation() + &&(nc=PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase()))!=null) + len = name.length() / (clrs.length+1); + else + len = name.length() / clrs.length;*/ + val nclar = cp.NameColorLocations().get(); + int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray(); + if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + 1)) //+1: Nation color + ncl = null; // Reset if name length changed + //System.out.println("ncl: "+Arrays.toString(ncl)+" - sum: "+Arrays.stream(ncl).sum()+" - name len: "+name.length()); + if (!res.getTown().hasNation() + || (nc = NationColor.get(res.getTown().getNation().getName().toLowerCase())) == null) + nc = Color.White; + ret.append(anyColoredNamePart.apply(nc, ncl == null ? len : ncl[0])); //Make first color the nation color + for (int i = 0; i < clrs.length; i++) + //ret.append(coloredNamePart.apply(ncl == null ? len : (nc==null?ncl[i]:ncl[i+1]), i)); + ret.append(coloredNamePart.apply(ncl == null ? len : ncl[i + 1], i)); + return ret.toString(); + } catch (NotRegisteredException e) { + return nickname; + } + } + + /** + * Checks if the component is enabled + */ + public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor) + updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class)); + } + + /** + * Checks if the component is enabled + */ + public static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames + if (!ComponentManager.isEnabled(TownColorComponent.class)) + return; + User user = PluginMain.essentials.getUser(player); + user.setNickname(getPlayerNickname(player, user, cp)); + user.setDisplayNick(); //These won't fire the nick change event + cp.FlairUpdate(); //Update in list + } + + private static void load_old(Consumer loadTC, + Consumer loadNC) { + PluginMain.Instance.getLogger().info("Loading files..."); + try { + File file = new File("TBMC/chatsettings.yml"); + if (file.exists()) { + YamlConfiguration yc = new YamlConfiguration(); + yc.load(file); + ConfigurationSection cs; + if (loadTC != null && (cs = yc.getConfigurationSection("towncolors")) != null) + loadTC.accept(cs); + if (loadNC != null && (cs = yc.getConfigurationSection("nationcolors")) != null) + loadNC.accept(cs); + PluginMain.Instance.getLogger().info("Loaded files!"); + } else + PluginMain.Instance.getLogger().info("No files to load, first run probably."); + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while loading chat files!", e); + } + } +} diff --git a/src/main/java/buttondevteam/chat/listener/TownyListener.java b/src/main/java/buttondevteam/chat/components/towncolors/TownyListener.java similarity index 77% rename from src/main/java/buttondevteam/chat/listener/TownyListener.java rename to src/main/java/buttondevteam/chat/components/towncolors/TownyListener.java index a3ecc3f..6a9c28b 100644 --- a/src/main/java/buttondevteam/chat/listener/TownyListener.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/TownyListener.java @@ -1,4 +1,4 @@ -package buttondevteam.chat.listener; +package buttondevteam.chat.components.towncolors; import buttondevteam.chat.PluginMain; import com.earth2me.essentials.User; @@ -16,21 +16,21 @@ import java.util.Objects; public class TownyListener implements Listener { @EventHandler public void onTownRename(RenameTownEvent event) { - val clrs = PluginMain.TownColors.remove(event.getOldName().toLowerCase()); + val clrs = TownColorComponent.TownColors.remove(event.getOldName().toLowerCase()); if (clrs != null) - PluginMain.TownColors.put(event.getTown().getName().toLowerCase(), clrs); + TownColorComponent.TownColors.put(event.getTown().getName().toLowerCase(), clrs); } @EventHandler //Gets called on town load as well public void onTownJoin(TownAddResidentEvent event) { Player p = Bukkit.getPlayer(event.getResident().getName()); if (p != null) - PlayerJoinLeaveListener.updatePlayerColors(p); + TownColorComponent.updatePlayerColors(p); } public static void updateTownMembers(Town town) { town.getResidents().stream().map(r -> Bukkit.getPlayer(r.getName())) - .filter(Objects::nonNull).forEach(PlayerJoinLeaveListener::updatePlayerColors); + .filter(Objects::nonNull).forEach(TownColorComponent::updatePlayerColors); } @EventHandler @@ -47,7 +47,7 @@ public class TownyListener implements Listener { @EventHandler public void onTownDelete(DeleteTownEvent event) { - PluginMain.TownColors.remove(event.getTownName().toLowerCase()); + TownColorComponent.TownColors.remove(event.getTownName().toLowerCase()); } @EventHandler @@ -61,9 +61,9 @@ public class TownyListener implements Listener { @EventHandler public void onNationRename(RenameNationEvent event) { - val clrs = PluginMain.NationColor.remove(event.getOldName().toLowerCase()); + val clrs = TownColorComponent.NationColor.remove(event.getOldName().toLowerCase()); if (clrs != null) - PluginMain.NationColor.put(event.getNation().getName().toLowerCase(), clrs); + TownColorComponent.NationColor.put(event.getNation().getName().toLowerCase(), clrs); } @EventHandler //Gets called on town load as well @@ -78,7 +78,7 @@ public class TownyListener implements Listener { @EventHandler public void onNationDelete(DeleteNationEvent event) { - PluginMain.NationColor.remove(event.getNationName().toLowerCase()); + TownColorComponent.NationColor.remove(event.getNationName().toLowerCase()); } @EventHandler diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java similarity index 82% rename from src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java rename to src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java index 9c9d4b1..3d7c216 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/NationColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/admin/NationColorCommand.java @@ -1,8 +1,10 @@ -package buttondevteam.chat.commands.ucmds.admin; +package buttondevteam.chat.components.towncolors.admin; import buttondevteam.chat.PluginMain; +import buttondevteam.chat.commands.ucmds.admin.AdminCommandBase; +import buttondevteam.chat.components.towncolors.TownColorComponent; +import buttondevteam.chat.components.towncolors.TownyListener; import buttondevteam.chat.components.towny.TownyComponent; -import buttondevteam.chat.listener.TownyListener; import buttondevteam.lib.chat.Color; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Town; @@ -40,14 +42,14 @@ public class NationColorCommand extends AdminCommandBase { val c = TownColorCommand.getColorOrSendError(args[1], sender); if (!c.isPresent()) return true; if (!c.get().getName().equals(Color.White.getName())) { //Default nation color - for (val nc : PluginMain.NationColor.values()) { + for (val nc : TownColorComponent.NationColor.values()) { if (nc.getName().equals(c.get().getName())) { sender.sendMessage("§cAnother nation already uses this color!"); return true; } } } - PluginMain.NationColor.put(args[0].toLowerCase(), c.get()); + TownColorComponent.NationColor.put(args[0].toLowerCase(), c.get()); Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { for (Town t : nation.getTowns()) TownyListener.updateTownMembers(t); diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TCCount.java b/src/main/java/buttondevteam/chat/components/towncolors/admin/TCCount.java similarity index 67% rename from src/main/java/buttondevteam/chat/commands/ucmds/admin/TCCount.java rename to src/main/java/buttondevteam/chat/components/towncolors/admin/TCCount.java index 277dff6..a20b26a 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TCCount.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/admin/TCCount.java @@ -1,5 +1,8 @@ -package buttondevteam.chat.commands.ucmds.admin; +package buttondevteam.chat.components.towncolors.admin; +import buttondevteam.chat.commands.ucmds.admin.AdminCommandBase; +import buttondevteam.chat.components.towncolors.TownColorComponent; +import lombok.val; import org.bukkit.command.CommandSender; public class TCCount extends AdminCommandBase { @@ -20,7 +23,8 @@ public class TCCount extends AdminCommandBase { } catch (NumberFormatException e) { return false; } - buttondevteam.chat.commands.ucmds.TownColorCommand.ColorCount = count; + val comp = (TownColorComponent) getComponent(); + comp.colorCount().set(count); sender.sendMessage("Color count set to " + count); return true; } diff --git a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java b/src/main/java/buttondevteam/chat/components/towncolors/admin/TownColorCommand.java similarity index 85% rename from src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java rename to src/main/java/buttondevteam/chat/components/towncolors/admin/TownColorCommand.java index 21b7659..8905d9d 100644 --- a/src/main/java/buttondevteam/chat/commands/ucmds/admin/TownColorCommand.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/admin/TownColorCommand.java @@ -1,8 +1,10 @@ -package buttondevteam.chat.commands.ucmds.admin; +package buttondevteam.chat.components.towncolors.admin; import buttondevteam.chat.PluginMain; +import buttondevteam.chat.commands.ucmds.admin.AdminCommandBase; +import buttondevteam.chat.components.towncolors.TownColorComponent; +import buttondevteam.chat.components.towncolors.TownyListener; import buttondevteam.chat.components.towny.TownyComponent; -import buttondevteam.chat.listener.TownyListener; import buttondevteam.lib.chat.Color; import com.palmergames.bukkit.towny.object.Town; import lombok.val; @@ -48,16 +50,16 @@ public class TownColorCommand extends AdminCommandBase { return true; clrs[i - 1] = c.get(); } - for (Map.Entry other : PluginMain.TownColors.entrySet()) { + for (Map.Entry other : TownColorComponent.TownColors.entrySet()) { Color nc, tnc; try { - nc = PluginMain.NationColor.get(TownyComponent.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase()); + nc = TownColorComponent.NationColor.get(TownyComponent.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase()); } catch (Exception e) { //Too lazy for lots of null-checks and it may throw exceptions anyways nc = null; } if (nc == null) nc = Color.White; //Default nation color try { - tnc = PluginMain.NationColor.get(targetTown.getNation().getName().toLowerCase()); + tnc = TownColorComponent.NationColor.get(targetTown.getNation().getName().toLowerCase()); } catch (Exception e) { tnc = null; } @@ -75,7 +77,7 @@ public class TownColorCommand extends AdminCommandBase { } } } - PluginMain.TownColors.put(args[0].toLowerCase(), clrs); + TownColorComponent.TownColors.put(args[0].toLowerCase(), clrs); TownyListener.updateTownMembers(targetTown); val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); @@ -84,7 +86,7 @@ public class TownColorCommand extends AdminCommandBase { PluginMain.Instance.getLogger().warning("Dynmap-Towny not found for setting town color!"); return true; } - PluginMain.setTownColor(dtp, targetTown.getName(), clrs); + TownColorComponent.setTownColor(dtp, targetTown.getName(), clrs); sender.sendMessage("§bColor(s) set."); return true; } diff --git a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java index 196a8d0..25158c5 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java @@ -7,28 +7,19 @@ import buttondevteam.chat.commands.UnlolCommand; import buttondevteam.chat.commands.ucmds.HistoryCommand; import buttondevteam.chat.components.flair.FlairComponent; import buttondevteam.chat.components.flair.FlairStates; -import buttondevteam.chat.components.towny.TownyComponent; +import buttondevteam.chat.components.towncolors.TownColorComponent; import buttondevteam.core.ComponentManager; -import buttondevteam.lib.chat.Color; import buttondevteam.lib.player.TBMCPlayerJoinEvent; import buttondevteam.lib.player.TBMCPlayerLoadEvent; import buttondevteam.lib.player.TBMCPlayerSaveEvent; -import com.earth2me.essentials.User; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import lombok.val; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; -import java.util.Arrays; -import java.util.Optional; import java.util.Timer; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiFunction; public class PlayerJoinLeaveListener implements Listener { @@ -70,7 +61,7 @@ public class PlayerJoinLeaveListener implements Listener { nwithoutformatting = p.getName(); PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); - updatePlayerColors(p, cp); //TO!DO: Doesn't have effect - It can help to register the listener + TownColorComponent.updatePlayerColors(p, cp); //TO!DO: Doesn't have effect - It can help to register the listener if (cp.ChatOnly || p.getGameMode().equals(GameMode.SPECTATOR)) { cp.ChatOnly = false; @@ -90,60 +81,4 @@ public class PlayerJoinLeaveListener implements Listener { UnlolCommand.Lastlol.values().removeIf(lld -> lld.getLolowner().equals(event.getPlayer())); } - private static String getPlayerNickname(Player player, User user, ChatPlayer cp) { - String nickname = user.getNick(true); - if (nickname.contains("~")) //StartsWith doesn't work because of color codes - nickname = nickname.replace("~", ""); //It gets stacked otherwise - String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members - val res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase()); - if (res == null || !res.hasTown()) - return name; - try { - Color[] clrs = Optional.ofNullable( - PluginMain.TownColors.get(res.getTown().getName().toLowerCase()) - ).orElse(new Color[]{Color.White}); //Use white as default town color - StringBuilder ret = new StringBuilder(); - AtomicInteger prevlen = new AtomicInteger(); - BiFunction anyColoredNamePart = (c, len) -> "§" //Len==0 if last part - + Integer.toHexString(c.ordinal()) // 'Odds' are the last character is chopped off so we make sure to include all chars at the end - + (len == 0 ? name.substring(prevlen.get()) - : name.substring(prevlen.get(), prevlen.addAndGet(len))); - BiFunction coloredNamePart = (len, i) - -> anyColoredNamePart.apply(clrs[i], i + 1 == clrs.length ? 0 : len); - final int len = name.length() / (clrs.length + 1); //The above param is needed because this isn't always passed - Color nc; - /*if(res.getTown().hasNation() - &&(nc=PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase()))!=null) - len = name.length() / (clrs.length+1); - else - len = name.length() / clrs.length;*/ - val nclar = cp.NameColorLocations().get(); - int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray(); - if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + 1)) //+1: Nation color - ncl = null; // Reset if name length changed - //System.out.println("ncl: "+Arrays.toString(ncl)+" - sum: "+Arrays.stream(ncl).sum()+" - name len: "+name.length()); - if (!res.getTown().hasNation() - || (nc = PluginMain.NationColor.get(res.getTown().getNation().getName().toLowerCase())) == null) - nc = Color.White; - ret.append(anyColoredNamePart.apply(nc, ncl == null ? len : ncl[0])); //Make first color the nation color - for (int i = 0; i < clrs.length; i++) - //ret.append(coloredNamePart.apply(ncl == null ? len : (nc==null?ncl[i]:ncl[i+1]), i)); - ret.append(coloredNamePart.apply(ncl == null ? len : ncl[i + 1], i)); - return ret.toString(); - } catch (NotRegisteredException e) { - return nickname; - } - } - - public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor) - updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class)); - } - - @SuppressWarnings("WeakerAccess") - public static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames - User user = PluginMain.essentials.getUser(player); - user.setNickname(getPlayerNickname(player, user, cp)); - user.setDisplayNick(); //These won't fire the nick change event - cp.FlairUpdate(); //Update in list - } } diff --git a/src/main/java/buttondevteam/chat/listener/PlayerListener.java b/src/main/java/buttondevteam/chat/listener/PlayerListener.java index 42dd4ef..43309f7 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerListener.java @@ -5,6 +5,7 @@ import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.PluginMain; import buttondevteam.chat.commands.ucmds.HistoryCommand; import buttondevteam.chat.components.flair.FlairComponent; +import buttondevteam.chat.components.towncolors.TownColorComponent; import buttondevteam.component.channel.Channel; import buttondevteam.component.channel.ChatChannelRegisterEvent; import buttondevteam.component.channel.ChatRoom; @@ -52,9 +53,6 @@ public class PlayerListener implements Listener { */ public static BiMap nicknames = HashBiMap.create(); - public static String NotificationSound; - public static double NotificationPitch; - public final static String[] LaughStrings = new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}; @EventHandler(priority = EventPriority.HIGHEST) @@ -286,7 +284,7 @@ public class PlayerListener implements Listener { nicknames.inverse().forcePut(e.getAffected().getBase().getUniqueId(), ChatColor.stripColor(nick).toLowerCase()); Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> { - PlayerJoinLeaveListener.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again + TownColorComponent.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again }, 1); } } From 3a29010042c694800c2e0c916c3dfe7bd19aa798 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 19 Jan 2019 20:26:39 +0100 Subject: [PATCH 7/7] Fixed cast error, NPE, masked links Fixed config cast error Fixed mcchat NPE Implemented masked links Added a test for it --- .../buttondevteam/chat/ChatProcessing.java | 24 +- .../towncolors/TownColorComponent.java | 2 +- .../chat/formatting/ChatFormatter.java | 792 +++++++++--------- .../chat/formatting/FormattedSection.java | 70 +- .../listener/PlayerJoinLeaveListener.java | 3 +- src/main/resources/plugin.yml | 2 +- .../java/buttondevteam/chat/ChatFormatIT.java | 13 +- 7 files changed, 459 insertions(+), 447 deletions(-) diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index 0fc251c..053d0b9 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -46,7 +46,7 @@ public class ChatProcessing { 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 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 Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, @@ -63,9 +63,8 @@ public class ChatProcessing { .build(), ChatFormatter.builder().regex(STRIKETHROUGH_PATTERN).strikethrough(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) .build(), - ESCAPE_FORMATTER, ChatFormatter.builder().regex(URL_PATTERN).underlined(true).openlink("$1").type(ChatFormatter.Type.Excluder).build(), - 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) -> { + 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 @@ -78,9 +77,14 @@ public class ChatProcessing { 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) -> { - return match; // TODO! - }).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()) @@ -124,7 +128,7 @@ public class ChatProcessing { 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().color(colormode).onmatch((match, cf) -> { + formatters.add(ChatFormatter.builder().color(colormode).onmatch((match, cf, s) -> { cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); return match; }).build()); @@ -275,7 +279,7 @@ public class ChatProcessing { }; formatters.add(ChatFormatter.builder().regex(Pattern.compile(namesb.toString())).color(Color.Aqua) - .onmatch((match, builder) -> { + .onmatch((match, builder, section) -> { Player p = Bukkit.getPlayer(match); Optional pn = nottest ? Optional.empty() : Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny(); @@ -297,7 +301,7 @@ public class ChatProcessing { if (addNickFormatter) formatters.add(ChatFormatter.builder().regex((Pattern.compile(nicksb.toString()))).color(Color.Aqua) - .onmatch((match, builder) -> { + .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) { diff --git a/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java index a44bdbe..cbbb8e6 100644 --- a/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java +++ b/src/main/java/buttondevteam/chat/components/towncolors/TownColorComponent.java @@ -42,7 +42,7 @@ public class TownColorComponent extends Component { public static Map NationColor = new HashMap<>(); public ConfigData colorCount() { - return getConfig().getData("colorCount", (byte) 1, cc -> (byte) cc, cc -> (int) cc); + return getConfig().getData("colorCount", (byte) 1, cc -> ((Integer) cc).byteValue(), Byte::intValue); } public ConfigData useNationColors() { //TODO diff --git a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java b/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java index aaca06e..e60efbf 100644 --- a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java +++ b/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java @@ -1,394 +1,398 @@ -package buttondevteam.chat.formatting; - -import buttondevteam.chat.ChatProcessing; -import buttondevteam.chat.commands.ucmds.admin.DebugCommand; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.Priority; -import lombok.Builder; -import lombok.Data; -import lombok.val; - -import java.util.*; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.regex.Matcher; -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 - * 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 - * - */ -@Data -@Builder -public final class ChatFormatter { - Pattern regex; - boolean italic; - boolean bold; - boolean underlined; - boolean strikethrough; - boolean obfuscated; - Color color; - BiFunction onmatch; - String openlink; - @Builder.Default - Priority priority = Priority.Normal; - @Builder.Default - short removeCharCount = 0; - @Builder.Default - Type type = Type.Normal; - - 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 - } - - public static void Combine(List formatters, String str, TellrawPart tp) { - /* - * This method assumes that there is always a global formatter - */ - 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); - } - } - - 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)); - - /** - * 0: Start - 1: End index - */ - val remchars = new ArrayList(); - - header("Range section conversion"); - 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++) { - // 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) { - escaped = section.Formatters.contains(ChatProcessing.ESCAPE_FORMATTER) && !escaped; // Enable escaping on first \, disable on second - 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); - } - 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 (section.Start == takenStart || (section.Start > takenStart && section.Start < takenEnd)) { - /* - * if (nextSection.containsKey(section.Formatters.get(0)) ? section.RemCharFromStart <= takenEnd - takenStart : section.RemCharFromStart > takenEnd - takenStart) { - */ - if (section.Formatters.get(0).removeCharCount < takenEnd - takenStart) { - DebugCommand.SendDebugMessage("Lose: " + section); - sendMessageWithPointer(str, section.Start, section.End); - DebugCommand.SendDebugMessage("And win: " + takenFormatter); - continue; // The current section loses - } - nextSection.remove(takenFormatter); // The current section wins - DebugCommand.SendDebugMessage("Win: " + section); - sendMessageWithPointer(str, section.Start, section.End); - DebugCommand.SendDebugMessage("And lose: " + takenFormatter); - } - takenStart = section.Start; - takenEnd = section.Start + section.Formatters.get(0).removeCharCount; - takenFormatter = section.Formatters.get(0); - if (nextSection.containsKey(section.Formatters.get(0))) { - FormattedSection s = nextSection.remove(section.Formatters.get(0)); - // section: the ending marker section - s: the to-be full section - s.End = takenEnd - 1; //Take the remCharCount into account as well - // s.IsRange = false; // IsRange means it's a 1 long section indicating a start or an end - combined.add(s); - DebugCommand.SendDebugMessage("Finished section: " + s); - sendMessageWithPointer(str, s.Start, s.End); - } else { - DebugCommand.SendDebugMessage("Adding next section: " + section); - sendMessageWithPointer(str, section.Start, section.End); - nextSection.put(section.Formatters.get(0), section); - } - DebugCommand - .SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter); - sendMessageWithPointer(str, takenStart, takenEnd); - } else { - DebugCommand.SendDebugMessage("Skipping section: " + section); // This will keep the text (character) - sendMessageWithPointer(str, section.Start, section.End); - escaped = false; // Reset escaping if applied, like if we're at the '*' in '\*' - } - } - //Do not finish unfinished sections, ignore them - sections = combined; - - header("Adding remove chars (RC)"); // Important to add after the range section conversion - 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)); - 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)); - DebugCommand.SendDebugMessage("Added remchars:"); - DebugCommand - .SendDebugMessage(remchars.stream().map(rc -> Arrays.toString(rc)).collect(Collectors.joining("; "))); - - header("Section combining"); - boolean cont = true; - boolean found = false; - for (int i = 1; cont;) { - int nextindex = i + 1; - if (sections.size() < 2) - break; - DebugCommand.SendDebugMessage("i: " + i); - 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); - 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 - 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; - - 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); - return true; - } - return false; - }; - - DebugCommand.SendDebugMessage("To sections"); - if (!removeIfNeeded.test(firstSection)) { - DebugCommand.SendDebugMessage(" 1:" + firstSection + ""); - sendMessageWithPointer(str, firstSection.Start, firstSection.End); - } - if (!removeIfNeeded.test(section)) { - DebugCommand.SendDebugMessage(" 2:" + section + ""); - sendMessageWithPointer(str, section.Start, section.End); - } - if (!removeIfNeeded.test(thirdFormattedSection)) { - DebugCommand.SendDebugMessage(" 3:" + thirdFormattedSection); - sendMessageWithPointer(str, thirdFormattedSection.Start, thirdFormattedSection.End); - } - found = true; - } - for (int j = i - 1; j <= i + 1; j++) { - if (j < sections.size() && sections.get(j).End < sections.get(j).Start) { - DebugCommand.SendDebugMessage("Removing section: " + sections.get(j)); - sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End); - sections.remove(j); - j--; - found = true; - } - } - i = nextindex - 1; - i++; - if (i >= sections.size()) { - 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)); - } else - cont = false; - } - } - - header("Section applying"); - 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); - 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) + ")"); - 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(); - 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(""); - for (ChatFormatter formatter : section.Formatters) { - DebugCommand.SendDebugMessage("Applying formatter: " + formatter); - if (formatter.onmatch != null) - originaltext = formatter.onmatch.apply(originaltext, formatter); - if (formatter.color != null) - newtp.setColor(formatter.color); - if (formatter.bold) - newtp.setBold(formatter.bold); - if (formatter.italic) - newtp.setItalic(formatter.italic); - if (formatter.underlined) - newtp.setUnderlined(formatter.underlined); - if (formatter.strikethrough) - newtp.setStrikethrough(formatter.strikethrough); - if (formatter.obfuscated) - newtp.setObfuscated(formatter.obfuscated); - if (formatter.openlink != null) - openlink = formatter.openlink; - } - 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() - && (openlink == null ? lastlink == null : openlink.equals(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 - } - 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))); - } - tp.addExtra(newtp); - lasttp = newtp; - } - header("ChatFormatter.Combine done"); - } - - private static void sendMessageWithPointer(String str, int... pointer) { - DebugCommand.SendDebugMessage(str); - StringBuilder sb = new StringBuilder(str.length()); - Arrays.sort(pointer); - for (int i = 0; i < pointer.length; i++) { - for (int j = 0; j < pointer[i] - (i > 0 ? pointer[i - 1] + 1 : 0); j++) - sb.append(' '); - if (pointer[i] == (i > 0 ? pointer[i - 1] : -1)) - continue; - sb.append('^'); - } - DebugCommand.SendDebugMessage(sb.toString()); - } - - private static void header(String message) { - DebugCommand.SendDebugMessage("\n--------\n" + message + "\n--------\n"); - } -} +package buttondevteam.chat.formatting; + +import buttondevteam.chat.ChatProcessing; +import buttondevteam.chat.commands.ucmds.admin.DebugCommand; +import buttondevteam.lib.chat.Color; +import buttondevteam.lib.chat.Priority; +import lombok.Builder; +import lombok.Data; +import lombok.val; + +import java.util.*; +import java.util.function.Predicate; +import java.util.regex.Matcher; +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 + * 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 + * + */ +@Data +@Builder +public final class ChatFormatter { + Pattern regex; + boolean italic; + boolean bold; + boolean underlined; + boolean strikethrough; + boolean obfuscated; + Color color; + TriFunc onmatch; + String openlink; + @Builder.Default + Priority priority = Priority.Normal; + @Builder.Default + short removeCharCount = 0; + @Builder.Default + Type type = Type.Normal; + + 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 + } + + @FunctionalInterface + public interface TriFunc { + R apply(T1 x1, T2 x2, T3 x3); + } + + public static void Combine(List formatters, String str, TellrawPart tp) { + /* + * This method assumes that there is always a global formatter + */ + 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); + } + } + + 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)); + + /** + * 0: Start - 1: End index + */ + val remchars = new ArrayList(); + + header("Range section conversion"); + 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++) { + // 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) { + escaped = section.Formatters.contains(ChatProcessing.ESCAPE_FORMATTER) && !escaped; // Enable escaping on first \, disable on second + 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); + } + 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 (section.Start == takenStart || (section.Start > takenStart && section.Start < takenEnd)) { + /* + * if (nextSection.containsKey(section.Formatters.get(0)) ? section.RemCharFromStart <= takenEnd - takenStart : section.RemCharFromStart > takenEnd - takenStart) { + */ + if (section.Formatters.get(0).removeCharCount < takenEnd - takenStart) { + DebugCommand.SendDebugMessage("Lose: " + section); + sendMessageWithPointer(str, section.Start, section.End); + DebugCommand.SendDebugMessage("And win: " + takenFormatter); + continue; // The current section loses + } + nextSection.remove(takenFormatter); // The current section wins + DebugCommand.SendDebugMessage("Win: " + section); + sendMessageWithPointer(str, section.Start, section.End); + DebugCommand.SendDebugMessage("And lose: " + takenFormatter); + } + takenStart = section.Start; + takenEnd = section.Start + section.Formatters.get(0).removeCharCount; + takenFormatter = section.Formatters.get(0); + if (nextSection.containsKey(section.Formatters.get(0))) { + FormattedSection s = nextSection.remove(section.Formatters.get(0)); + // section: the ending marker section - s: the to-be full section + s.End = takenEnd - 1; //Take the remCharCount into account as well + // s.IsRange = false; // IsRange means it's a 1 long section indicating a start or an end + combined.add(s); + DebugCommand.SendDebugMessage("Finished section: " + s); + sendMessageWithPointer(str, s.Start, s.End); + } else { + DebugCommand.SendDebugMessage("Adding next section: " + section); + sendMessageWithPointer(str, section.Start, section.End); + nextSection.put(section.Formatters.get(0), section); + } + DebugCommand + .SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter); + sendMessageWithPointer(str, takenStart, takenEnd); + } else { + DebugCommand.SendDebugMessage("Skipping section: " + section); // This will keep the text (character) + sendMessageWithPointer(str, section.Start, section.End); + escaped = false; // Reset escaping if applied, like if we're at the '*' in '\*' + } + } + //Do not finish unfinished sections, ignore them + sections = combined; + + header("Adding remove chars (RC)"); // Important to add after the range section conversion + 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)); + 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)); + DebugCommand.SendDebugMessage("Added remchars:"); + DebugCommand + .SendDebugMessage(remchars.stream().map(rc -> Arrays.toString(rc)).collect(Collectors.joining("; "))); + + header("Section combining"); + boolean cont = true; + boolean found = false; + for (int i = 1; cont;) { + int nextindex = i + 1; + if (sections.size() < 2) + break; + DebugCommand.SendDebugMessage("i: " + i); + 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); + 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 + 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; + + 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); + return true; + } + return false; + }; + + DebugCommand.SendDebugMessage("To sections"); + if (!removeIfNeeded.test(firstSection)) { + DebugCommand.SendDebugMessage(" 1:" + firstSection + ""); + sendMessageWithPointer(str, firstSection.Start, firstSection.End); + } + if (!removeIfNeeded.test(section)) { + DebugCommand.SendDebugMessage(" 2:" + section + ""); + sendMessageWithPointer(str, section.Start, section.End); + } + if (!removeIfNeeded.test(thirdFormattedSection)) { + DebugCommand.SendDebugMessage(" 3:" + thirdFormattedSection); + sendMessageWithPointer(str, thirdFormattedSection.Start, thirdFormattedSection.End); + } + found = true; + } + for (int j = i - 1; j <= i + 1; j++) { + if (j < sections.size() && sections.get(j).End < sections.get(j).Start) { + DebugCommand.SendDebugMessage("Removing section: " + sections.get(j)); + sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End); + sections.remove(j); + j--; + found = true; + } + } + i = nextindex - 1; + i++; + if (i >= sections.size()) { + 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)); + } else + cont = false; + } + } + + header("Section applying"); + 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); + 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) + ")"); + 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(); + 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(""); + for (ChatFormatter formatter : section.Formatters) { + DebugCommand.SendDebugMessage("Applying formatter: " + formatter); + if (formatter.onmatch != null) + originaltext = formatter.onmatch.apply(originaltext, formatter, section); + if (formatter.color != null) + newtp.setColor(formatter.color); + if (formatter.bold) + newtp.setBold(formatter.bold); + if (formatter.italic) + newtp.setItalic(formatter.italic); + if (formatter.underlined) + newtp.setUnderlined(formatter.underlined); + if (formatter.strikethrough) + newtp.setStrikethrough(formatter.strikethrough); + if (formatter.obfuscated) + newtp.setObfuscated(formatter.obfuscated); + if (formatter.openlink != null) + openlink = formatter.openlink; + } + 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 + } + 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))); + } + tp.addExtra(newtp); + lasttp = newtp; + } + header("ChatFormatter.Combine done"); + } + + private static void sendMessageWithPointer(String str, int... pointer) { + DebugCommand.SendDebugMessage(str); + StringBuilder sb = new StringBuilder(str.length()); + Arrays.sort(pointer); + for (int i = 0; i < pointer.length; i++) { + for (int j = 0; j < pointer[i] - (i > 0 ? pointer[i - 1] + 1 : 0); j++) + sb.append(' '); + if (pointer[i] == (i > 0 ? pointer[i - 1] : -1)) + continue; + sb.append('^'); + } + DebugCommand.SendDebugMessage(sb.toString()); + } + + private static void header(String message) { + DebugCommand.SendDebugMessage("\n--------\n" + message + "\n--------\n"); + } +} diff --git a/src/main/java/buttondevteam/chat/formatting/FormattedSection.java b/src/main/java/buttondevteam/chat/formatting/FormattedSection.java index 4265726..15101c4 100644 --- a/src/main/java/buttondevteam/chat/formatting/FormattedSection.java +++ b/src/main/java/buttondevteam/chat/formatting/FormattedSection.java @@ -1,36 +1,36 @@ -package buttondevteam.chat.formatting; - -import java.util.ArrayList; -import java.util.Collection; - -class FormattedSection { - int Start; - int End; - ArrayList Formatters = new ArrayList(); - ArrayList Matches = new ArrayList(); - ChatFormatter.Type type; - - FormattedSection(ChatFormatter formatter, int start, int end, ArrayList matches, ChatFormatter.Type type) { - Start = start; - End = end; - Formatters.add(formatter); - Matches.addAll(matches); - this.type = type; - } - - FormattedSection(Collection formatters, int start, int end, ArrayList matches, - ChatFormatter.Type type) { - Start = start; - End = end; - Formatters.addAll(formatters); - Matches.addAll(matches); - this.type = type; - } - - @Override - public String toString() { - return "Section(" + Start + ", " + End + ", formatters: " + - Formatters.toString() + ", matches: " + Matches.toString() + ", " + - type + ")"; - } +package buttondevteam.chat.formatting; + +import java.util.ArrayList; +import java.util.Collection; + +public class FormattedSection { + public int Start; + public int End; + public ArrayList Formatters = new ArrayList(); + public ArrayList Matches = new ArrayList(); + public ChatFormatter.Type type; + + FormattedSection(ChatFormatter formatter, int start, int end, ArrayList matches, ChatFormatter.Type type) { + Start = start; + End = end; + Formatters.add(formatter); + Matches.addAll(matches); + this.type = type; + } + + FormattedSection(Collection formatters, int start, int end, ArrayList matches, + ChatFormatter.Type type) { + Start = start; + End = end; + Formatters.addAll(formatters); + Matches.addAll(matches); + this.type = type; + } + + @Override + public String toString() { + return "Section(" + Start + ", " + End + ", formatters: " + + Formatters.toString() + ", matches: " + Matches.toString() + ", " + + type + ")"; + } } \ No newline at end of file diff --git a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java index 25158c5..4dfb371 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerJoinLeaveListener.java @@ -12,7 +12,6 @@ import buttondevteam.core.ComponentManager; import buttondevteam.lib.player.TBMCPlayerJoinEvent; import buttondevteam.lib.player.TBMCPlayerLoadEvent; import buttondevteam.lib.player.TBMCPlayerSaveEvent; -import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -32,7 +31,7 @@ public class PlayerJoinLeaveListener implements Listener { @EventHandler public void onPlayerTBMCJoin(TBMCPlayerJoinEvent e) { ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class); - Player p = Bukkit.getPlayer(cp.getUUID()); + Player p = e.getPlayer(); if (ComponentManager.isEnabled(FlairComponent.class)) { if (!cp.FlairState().get().equals(FlairStates.NoComment)) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d429973..b66a288 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -37,9 +37,9 @@ depend: - Votifier - Vault - ButtonCore -- Dynmap-Towny soft-depend: - Minigames +- Dynmap-Towny permissions: tbmc.admin: description: Gives access to /un- commands and /u admin commands diff --git a/src/test/java/buttondevteam/chat/ChatFormatIT.java b/src/test/java/buttondevteam/chat/ChatFormatIT.java index 55e5a86..73d5c80 100644 --- a/src/test/java/buttondevteam/chat/ChatFormatIT.java +++ b/src/test/java/buttondevteam/chat/ChatFormatIT.java @@ -66,10 +66,15 @@ public class ChatFormatIT { list.add(new ChatFormatIT(sender, "*test _test_ test*", new TellrawPart("test ").setItalic(true).setColor(Color.White), new TellrawPart("test").setItalic(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", new TellrawPart("https://norbipeti.github.io/test?test&test#test") - .setColor(Color.White).setUnderlined(true) - .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, - new TellrawPart("Click to open").setColor(Color.Blue))) - .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test?test&test#test")))); + .setColor(Color.White).setUnderlined(true) + .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, + new TellrawPart("Click to open").setColor(Color.Blue))) + .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test?test&test#test")))); + list.add(new ChatFormatIT(sender, "[hmm](https://norbipeti.github.io/test)", new TellrawPart("hmm") + .setColor(Color.White).setUnderlined(true) + .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, + new TellrawPart("Click to open").setColor(Color.Blue))) + .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test")))); return list; }