diff --git a/src/main/java/buttondevteam/lib/DebugPotato.java b/src/main/java/buttondevteam/lib/DebugPotato.java new file mode 100644 index 0000000..48f195a --- /dev/null +++ b/src/main/java/buttondevteam/lib/DebugPotato.java @@ -0,0 +1,129 @@ +package buttondevteam.lib; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class DebugPotato { + private List message; + private String type; + + /** + * Send the debug potato to a player + * + * @param player + * The player + */ + public void Send(Player player){ + player.getInventory().addItem(this.toItemStack()); + return; + } + + /** + * Get the message (lore of the potato). + * + * @return The message + */ + public List getMessage() { + return message; + } + + /** + * Sets the message (lore of the potato). + * + * @param message + * The message + * @return This potato + */ + public DebugPotato setMessage(List message) { + this.message = message; + return this; + } + + /** + * Sets the message (lore of the potato). It will be word wrapped automatically. + * + * @param message + * The message + * @return This potato + */ + public DebugPotato setMessage(String message) { + this.message = WordWrap(message); + return this; + } + + /** + * Sets the message (lore of the potato). + * + * @param message + * The message + * @return This potato + */ + public DebugPotato setMessage(String[] message) { + this.message = Arrays.asList(message); + return this; + } + + /** + * Gets the type (potato name). + * + * @return The type + */ + public String getType() { + return type; + } + + /** + * Sets the type (potato name). + * + * @param type + * The type + * @return This potato + */ + public DebugPotato setType(String type) { + this.type = type; + return this; + } + + private static List WordWrap(String message) { + String[] splitString = message.split("\\s+"); + List newMessage = new ArrayList(); + String currentLine = ""; + int currentLineLength = 0; + int wordlength; + int maxLineLength = 40; + for (String word : splitString) { + wordlength = word.length(); + if (currentLineLength == 0 || (currentLineLength + wordlength) < maxLineLength) { + currentLine += word + " "; + currentLineLength += wordlength + 1; + } else { + newMessage.add(currentLine); + currentLine = word + " "; + currentLineLength = word.length(); + } + } + return newMessage; + } + public ItemStack toItemStack() { + ItemStack potato = new ItemStack(Material.BAKED_POTATO); + ItemMeta meta = potato.getItemMeta(); + meta.setDisplayName(this.getType() == null ? "Spicy Debug Potato" : this.getType()); + if (this.getMessage() == null){ + List message = new ArrayList(); + message.add("nullMessage"); + meta.setLore(message); + }else{ + meta.setLore(this.getMessage()); + } + potato.setItemMeta(meta); + potato.addUnsafeEnchantment(Enchantment.ARROW_FIRE, 10); + return potato; + } +} diff --git a/src/main/java/buttondevteam/lib/DebugPotatoAPI.java b/src/main/java/buttondevteam/lib/DebugPotatoAPI.java new file mode 100644 index 0000000..5b78edd --- /dev/null +++ b/src/main/java/buttondevteam/lib/DebugPotatoAPI.java @@ -0,0 +1,13 @@ +package buttondevteam.lib; + +import org.bukkit.entity.Player; + +/**@deprecated + * Fully Replaced by DebugPotato Class - Construct a DebugPotato*/ +public class DebugPotatoAPI { + /**@deprecated Replaced by DebugPotato.send*/ + public static void SendDebugPotato(DebugPotato dp, Player player) { + player.getInventory().addItem(dp.toItemStack()); + return; + } +} diff --git a/src/main/java/buttondevteam/lib/Gary.java b/src/main/java/buttondevteam/lib/Gary.java new file mode 100644 index 0000000..beed5ca --- /dev/null +++ b/src/main/java/buttondevteam/lib/Gary.java @@ -0,0 +1,34 @@ +package buttondevteam.lib; + +import java.util.List; + +public class Gary extends DebugPotato { + + public Gary() { + super.setMessage("I'M A POTATO"); + } + + /** + * Gary has a fixed message, therefore this method has no effect. + */ + @Override + public DebugPotato setMessage(List message) { + return this; + } + + /** + * Gary has a fixed message, therefore this method has no effect. + */ + @Override + public DebugPotato setMessage(String message) { + return this; + } + + /** + * Gary has a fixed message, therefore this method has no effect. + */ + @Override + public DebugPotato setMessage(String[] message) { + return this; + } +} diff --git a/src/main/java/buttondevteam/lib/TBMCChatEvent.java b/src/main/java/buttondevteam/lib/TBMCChatEvent.java new file mode 100644 index 0000000..2f00575 --- /dev/null +++ b/src/main/java/buttondevteam/lib/TBMCChatEvent.java @@ -0,0 +1,47 @@ +package buttondevteam.lib; + +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import buttondevteam.lib.chat.Channel; + +public class TBMCChatEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private Channel channel; + private CommandSender sender; + private String message; + + public TBMCChatEvent(CommandSender sender, Channel channel, String message) { + this.sender = sender; + this.channel = channel; + this.message = message; // TODO: Message object with data? + } + + /* + * public TBMCPlayer getPlayer() { return TBMCPlayer.getPlayer(sender); // TODO: Get Chroma user } + */ + + public Channel getChannel() { + return channel; + } + + public CommandSender getSender() { + return sender; + } + + public String getMessage() { + return message; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + +} diff --git a/src/main/java/buttondevteam/lib/TBMCCoreAPI.java b/src/main/java/buttondevteam/lib/TBMCCoreAPI.java index 09b6f9a..56ba8ce 100644 --- a/src/main/java/buttondevteam/lib/TBMCCoreAPI.java +++ b/src/main/java/buttondevteam/lib/TBMCCoreAPI.java @@ -7,17 +7,20 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; -import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; +import java.util.Optional; +import java.util.Random; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; @@ -32,9 +35,11 @@ public final class TBMCCoreAPI { * * @param name * The plugin's repository name. - * @return Error message or empty string + * @param sender + * The command sender (if not console, messages will be printed to console as well). */ - public static String UpdatePlugin(String name) { + public static void UpdatePlugin(String name, CommandSender sender) { + info(sender, "Checking plugin name..."); List plugins = GetPluginNames(); String correctname = null; for (String plugin : plugins) { @@ -44,11 +49,9 @@ public final class TBMCCoreAPI { } } if (correctname == null) { - Bukkit.getLogger().warning("There was an error while updating TBMC plugin: " + name); - return "Can't find plugin: " + name; + error(sender, "Can't find plugin: " + name); } - Bukkit.getLogger().info("Updating TBMC plugin: " + correctname); - String ret = ""; + info(sender, "Updating TBMC plugin: " + correctname); URL url; File result = new File("plugins/" + correctname + ".jar_tmp"); File finalresult = new File("plugins/" + correctname + ".jar"); @@ -59,21 +62,36 @@ public final class TBMCCoreAPI { FileUtils.copyURLToFile(url, result); if (!result.exists() || result.length() < 25) { result.delete(); - ret = "The downloaded JAR is too small (smnaller than 25 bytes). Am I downloading from the right place?"; - } else + error(sender, "The downloaded JAR for " + correctname + + " is too small (smnaller than 25 bytes). Am I downloading from the right place?"); + } else { Files.move(result.toPath(), finalresult.toPath(), StandardCopyOption.REPLACE_EXISTING); + info(sender, "Updating plugin " + correctname + " done!"); + } } catch (FileNotFoundException e) { - ret = "Can't find JAR, the build probably failed. Build log (scroll to bottom):\nhttps://jitpack.io/com/github/TBMCPlugins/" - + correctname - + "/master-SNAPSHOT/build.log\nIf you'd like to rebuild the same commit, go to:\nhttps://jitpack.io/#TBMCPlugins/" - + correctname + "\nAnd delete the newest build."; + error(sender, + "Can't find JAR for " + correctname + ", the build probably failed. Build log (scroll to bottom):" + + "\n" + "https://jitpack.io/com/github/TBMCPlugins/" + correctname + + "/master-SNAPSHOT/build.log\nIf you'd like to rebuild the same commit, go to:\nhttps://jitpack.io/#TBMCPlugins/" + + correctname + "\nAnd delete the newest build."); } catch (IOException e) { - ret = "IO error!\n" + e.getMessage(); + error(sender, "IO error while updating " + correctname + "\n" + e.getMessage()); } catch (Exception e) { - Bukkit.getLogger().warning("Error!\n" + e); - ret = e.toString(); + e.printStackTrace(); + error(sender, "Unknown error while updating " + correctname + ": " + e); } - return ret; + } + + private static void error(CommandSender sender, String message) { + if (!sender.equals(Bukkit.getConsoleSender())) + Bukkit.getLogger().warning(message); + sender.sendMessage("§c" + message); + } + + private static void info(CommandSender sender, String message) { + if (!sender.equals(Bukkit.getConsoleSender())) + Bukkit.getLogger().info(message); + sender.sendMessage("§b" + message); } /** @@ -110,6 +128,13 @@ public final class TBMCCoreAPI { private static HashMap exceptionsToSend = new HashMap<>(); + private static final String[] potatoMessages = new String[] { // + "Well shit", // + "Wait what", // + "Hwat", // + "Wat" // + }; + /** * Send exception to the {@link TBMCExceptionEvent}. * @@ -126,6 +151,17 @@ public final class TBMCCoreAPI { exceptionsToSend.put(sourcemsg, e); Bukkit.getLogger().warning(sourcemsg); e.printStackTrace(); + Optional randomPlayer = Bukkit.getOnlinePlayers().stream().findAny(); + if (randomPlayer.isPresent()){ + DebugPotato potato = new DebugPotato() + .setMessage(new String[] { // + "§b§o" + potatoMessages[new Random().nextInt(potatoMessages.length)], // + "§c§o" + sourcemsg, // + "§a§oFind a dev to fix this issue" }) + .setType(e instanceof IOException ? "Potato on a Stick" + : e instanceof ClassCastException ? "Square Potato" : "Plain Potato"); + potato.Send(randomPlayer.get()); + } } /** @@ -144,6 +180,10 @@ public final class TBMCCoreAPI { * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event */ public static void SendUnsentExceptions() { + if (exceptionsToSend.size() > 20) { + exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded + Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!"); + } for (Entry entry : exceptionsToSend.entrySet()) { TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue()); Bukkit.getPluginManager().callEvent(event); diff --git a/src/main/java/buttondevteam/lib/TBMCPlayer.java b/src/main/java/buttondevteam/lib/TBMCPlayer.java index bdb02c5..203328f 100644 --- a/src/main/java/buttondevteam/lib/TBMCPlayer.java +++ b/src/main/java/buttondevteam/lib/TBMCPlayer.java @@ -157,8 +157,12 @@ public class TBMCPlayer implements AutoCloseable { if (!mname.startsWith("get")) throw new UnsupportedOperationException("Can only use getIntData from a getXYZ method"); Object obj = getLoadedPlayers().get(uuid).data.get(mname.substring("get".length()).toLowerCase()); - if (!(obj instanceof Integer)) - throw new UnsupportedOperationException("The retrieved object isn't a number: " + obj); + if (obj == null) + return null; + if (obj instanceof Short) + return (T) obj; + if (!(Integer.class.isAssignableFrom(obj.getClass()))) + throw new UnsupportedOperationException("The retrieved object isn't an integer: " + obj); Integer int_ = (Integer) obj; if (Short.class.isAssignableFrom(cl)) return (T) (Object) int_.shortValue(); diff --git a/src/main/java/buttondevteam/lib/chat/Channel.java b/src/main/java/buttondevteam/lib/chat/Channel.java new file mode 100644 index 0000000..5a257a4 --- /dev/null +++ b/src/main/java/buttondevteam/lib/chat/Channel.java @@ -0,0 +1,36 @@ +package buttondevteam.lib.chat; + +import java.util.ArrayList; +import java.util.List; + +public class Channel { + public final String DisplayName; + public final Color color; + public final String Command; + + private static List channels = new ArrayList<>(); + + public Channel(String displayname, Color color, String command) { + DisplayName = displayname; + this.color = color; + Command = command; + } + + static { + channels.add(GlobalChat = new Channel("§fg§f", Color.White, "g")); + channels.add(TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc")); + channels.add(NationChat = new Channel("§6NC§f", Color.Gold, "nc")); + channels.add(AdminChat = new Channel("§cADMIN§f", Color.Red, "a")); + channels.add(ModChat = new Channel("§9MOD§f", Color.Blue, "mod")); + } + + public static List getChannels() { + return channels; + } + + public static Channel GlobalChat; + public static Channel TownChat; + public static Channel NationChat; + public static Channel AdminChat; + public static Channel ModChat; +} diff --git a/src/main/java/buttondevteam/lib/chat/Color.java b/src/main/java/buttondevteam/lib/chat/Color.java new file mode 100644 index 0000000..7849f98 --- /dev/null +++ b/src/main/java/buttondevteam/lib/chat/Color.java @@ -0,0 +1,19 @@ +package buttondevteam.lib.chat; + +public enum Color implements TellrawSerializableEnum { + Black("black"), DarkBlue("dark_blue"), DarkGreen("dark_green"), DarkAqua("dark_aqua"), DarkRed( + "dark_red"), DarkPurple("dark_purple"), Gold("gold"), Gray("gray"), DarkGray("dark_gray"), Blue( + "blue"), Green("green"), Aqua("aqua"), Red( + "red"), LightPurple("light_purple"), Yellow("yellow"), White("white"), RPC("rpc"); + + private String name; + + Color(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/src/main/java/buttondevteam/lib/chat/Format.java b/src/main/java/buttondevteam/lib/chat/Format.java new file mode 100644 index 0000000..b13d45b --- /dev/null +++ b/src/main/java/buttondevteam/lib/chat/Format.java @@ -0,0 +1,24 @@ +package buttondevteam.lib.chat; + +public enum Format implements TellrawSerializableEnum { + Bold("bold"), Underlined("underlined"), Italic("italic"), Strikethrough("strikethrough"), Obfuscated( + "obfuscated"); + // TODO: Add format codes to /u c + private String name; + + Format(String name) { + this.name = name; + this.flag = 1 << this.ordinal(); + } + + @Override + public String getName() { + return name; + } + + private final int flag; + + public int getFlag() { + return flag; + } +} \ No newline at end of file diff --git a/src/main/java/buttondevteam/lib/chat/Priority.java b/src/main/java/buttondevteam/lib/chat/Priority.java new file mode 100644 index 0000000..2a2f18f --- /dev/null +++ b/src/main/java/buttondevteam/lib/chat/Priority.java @@ -0,0 +1,14 @@ +package buttondevteam.lib.chat; + +public enum Priority { + Low(0), Normal(1), High(2); + private int val; + + Priority(int v) { + val = v; + } + + public int GetValue() { + return val; + } +} diff --git a/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java b/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java index 6df5ab4..3a62ef6 100644 --- a/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java +++ b/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java @@ -6,12 +6,15 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; +import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCCoreAPI; public class TBMCChatAPI { @@ -30,11 +33,22 @@ public class TBMCChatAPI { * @return The subcommands */ public static String[] GetSubCommands(TBMCCommandBase command) { + return GetSubCommands(command.GetCommandPath()); + } + + /** + * Returns messages formatted for Minecraft chat listing the subcommands of the command. + * + * @param command + * The command which we want the subcommands of + * @return The subcommands + */ + public static String[] GetSubCommands(String command) { ArrayList cmds = new ArrayList(); cmds.add("§6---- Subcommands ----"); for (TBMCCommandBase cmd : TBMCChatAPI.GetCommands().values()) { - if (cmd.GetCommandPath().startsWith(command.GetCommandPath() + " ")) { - int ind = cmd.GetCommandPath().indexOf(' ', command.GetCommandPath().length() + 2); + if (cmd.GetCommandPath().startsWith(command + " ")) { + int ind = cmd.GetCommandPath().indexOf(' ', command.length() + 2); if (ind >= 0) continue; cmds.add("/" + cmd.GetCommandPath()); @@ -103,7 +117,7 @@ public class TBMCChatAPI { * The command's class to create it (because why let you create the command class) */ public static void AddCommand(JavaPlugin plugin, Class thecmdclass, Object... params) { - plugin.getLogger().info("Registering command " + thecmdclass.getSimpleName() + " for " + plugin.getName()); + // plugin.getLogger().info("Registering command " + thecmdclass.getSimpleName() + " for " + plugin.getName()); try { TBMCCommandBase c; if (params.length > 0) @@ -139,7 +153,7 @@ public class TBMCChatAPI { public static void AddCommand(JavaPlugin plugin, TBMCCommandBase cmd) { if (!CheckForNulls(plugin, cmd)) return; - plugin.getLogger().info("Registering command /" + cmd.GetCommandPath() + " for " + plugin.getName()); + // plugin.getLogger().info("Registering command /" + cmd.GetCommandPath() + " for " + plugin.getName()); try { cmd.plugin = plugin; commands.put(cmd.GetCommandPath(), cmd); @@ -160,4 +174,9 @@ public class TBMCChatAPI { } return true; } + + public static void SendChatMessage(Channel channel, CommandSender sender, String message) { + TBMCChatEvent event = new TBMCChatEvent(sender, channel, message); + Bukkit.getPluginManager().callEvent(event); + } } diff --git a/src/main/java/buttondevteam/lib/chat/TBMCCommandBase.java b/src/main/java/buttondevteam/lib/chat/TBMCCommandBase.java index 0379c9f..111e057 100644 --- a/src/main/java/buttondevteam/lib/chat/TBMCCommandBase.java +++ b/src/main/java/buttondevteam/lib/chat/TBMCCommandBase.java @@ -14,21 +14,19 @@ public abstract class TBMCCommandBase { public TBMCCommandBase() { } - + public abstract boolean OnCommand(CommandSender sender, String alias, String[] args); + public abstract String[] GetHelpText(String alias); + /** * The command's path, or name if top-level command.
* For example:
* "u admin updateplugin" or "u" for the top level one
- *
- * Note: If you have a command which has subcommands (like /u admin), you need a separate command class for that as well. + * The path must be lowercase!
* * @return The command path, which is the command class name by default (removing any "command" from it) */ - - public abstract String[] GetHelpText(String alias); - public String GetCommandPath() { return getClass().getSimpleName().toLowerCase().replace("command", ""); } diff --git a/src/main/java/buttondevteam/lib/chat/TellrawSerializableEnum.java b/src/main/java/buttondevteam/lib/chat/TellrawSerializableEnum.java new file mode 100644 index 0000000..1b10963 --- /dev/null +++ b/src/main/java/buttondevteam/lib/chat/TellrawSerializableEnum.java @@ -0,0 +1,5 @@ +package buttondevteam.lib.chat; + +public interface TellrawSerializableEnum { + public String getName(); +}