├── .gitignore ├── License.txt ├── README.md ├── pom.xml └── src ├── main └── java │ └── net │ └── dmulloy2 │ └── swornapi │ ├── SwornAPI.java │ ├── SwornPlugin.java │ ├── commands │ ├── CmdHelp.java │ ├── CmdReload.java │ ├── Command.java │ ├── CommandProps.java │ ├── PaginatedCommand.java │ └── SubCommand.java │ ├── config │ ├── ConfigParser.java │ ├── Key.java │ └── ValueOptions.java │ ├── exception │ ├── BadTimeException.java │ └── CommandException.java │ ├── gui │ ├── AbstractGUI.java │ └── GUIHandler.java │ ├── handlers │ ├── CommandHandler.java │ ├── LogHandler.java │ ├── PermissionHandler.java │ └── ResourceHandler.java │ ├── integration │ ├── DependencyProvider.java │ └── TypelessProvider.java │ ├── io │ ├── Closer.java │ ├── FileResourceLoader.java │ ├── FileSerialization.java │ └── IOUtil.java │ ├── types │ ├── ChatPosition.java │ ├── CommandVisibility.java │ ├── CustomScoreboard.java │ ├── CustomSkullType.java │ ├── EnchantmentType.java │ ├── IPermission.java │ ├── LazyLocation.java │ ├── PotionType.java │ ├── Reloadable.java │ ├── SimpleVector.java │ ├── Sorter.java │ ├── SpecialEntities.java │ ├── StringJoiner.java │ └── Versioning.java │ └── util │ ├── CompatUtil.java │ ├── FormatUtil.java │ ├── InventoryUtil.java │ ├── ItemUtil.java │ ├── ListUtil.java │ ├── MaterialUtil.java │ ├── NumberUtil.java │ ├── ReflectionUtil.java │ ├── TimeUtil.java │ └── Util.java └── test ├── java └── net │ └── dmulloy2 │ └── swornapi │ ├── BukkitTesting.java │ ├── config │ └── ConfigTest.java │ └── types │ └── VersioningTest.java └── resources └── config.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | target/ 4 | logs/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwornAPI 2 | SwornAPI is a collection of useful classes that I use in most of my projects. It contains APIs for configuration, commands, chat, GUIs, reflection, integration, I/O, and more. 3 | 4 | ### Resources 5 | * [Download](https://ci.dmulloy2.net/job/SwornAPI) 6 | * [JavaDocs](https://ci.dmulloy2.net/job/SwornAPI/javadoc) 7 | 8 | ### Building 9 | SwornAPI is built using Maven. It requires Spigot and the Spigot API, which can be obtained [here](https://www.spigotmc.org/wiki/buildtools/). 10 | 11 | ### License 12 | SwornAPI is currently licensed under the GPL v3. 13 | 14 | ### Utilizing SwornAPI 15 | SwornAPI is best utilized as a Maven dependency: 16 | 17 | ````xml 18 | 19 | 20 | jitpack 21 | https://jitpack.io 22 | 23 | 24 | 25 | 26 | 27 | 28 | com.github.dmulloy2 29 | SwornAPI 30 | -SNAPSHOT 31 | 32 | 33 | 34 | ```` 35 | 36 | For the best results, SwornAPI should be shaded into your project: 37 | 38 | ````xml 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-shade-plugin 44 | 2.3 45 | 46 | 47 | package 48 | 49 | shade 50 | 51 | 52 | 53 | 54 | net.dmulloy2:swornapi* 55 | 56 | 57 | 58 | 59 | net.dmulloy2 60 | net.dmulloy2.ultimatearena 61 | 62 | net.dmulloy2.ultimatearena* 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | ```` -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.dmulloy2 5 | swornapi 6 | 2.0.0-SNAPSHOT 7 | SwornAPI 8 | 9 | 2014 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | dmulloy2-repo 18 | https://repo.dmulloy2.net/repository/public/ 19 | 20 | 21 | spigot-repo 22 | https://hub.spigotmc.org/nexus/content/groups/public/ 23 | 24 | 25 | 26 | 27 | 28 | dmulloy2-releases 29 | https://repo.dmulloy2.net/repository/releases/ 30 | 31 | 32 | dmulloy2-snapshots 33 | https://repo.dmulloy2.net/repository/snapshots/ 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-compiler-plugin 42 | 3.10.1 43 | 44 | 17 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-jar-plugin 50 | 3.2.2 51 | 52 | 53 | false 54 | 55 | ${project.name} 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-javadoc-plugin 61 | 3.3.2 62 | 63 | false 64 | ISO-8859-1 65 | SwornAPI JavaDocs 66 | SwornAPI JavaDocs 67 | Copyright © {inceptionYear}–{currentYear} dmulloy2. Licensed under the GNU GPL v3. 68 | 8 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-surefire-plugin 74 | 3.0.0-M6 75 | 76 | 0 77 | 78 | 79 | 80 | 81 | 82 | . 83 | ${basedir} 84 | 85 | License.txt 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.spigotmc 94 | spigot-api 95 | 1.19-R0.1-SNAPSHOT 96 | 97 | 98 | org.spigotmc 99 | spigot 100 | 1.19-R0.1-SNAPSHOT 101 | 102 | 103 | org.projectlombok 104 | lombok 105 | 1.18.22 106 | provided 107 | 108 | 109 | com.comphenix.protocol 110 | ProtocolLib 111 | 5.0.0-SNAPSHOT 112 | 113 | 114 | 115 | 116 | org.junit.jupiter 117 | junit-jupiter-engine 118 | 5.8.2 119 | test 120 | 121 | 122 | org.mockito 123 | mockito-inline 124 | 4.3.1 125 | test 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/SwornAPI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi; 19 | 20 | import net.dmulloy2.swornapi.types.LazyLocation; 21 | import net.dmulloy2.swornapi.types.SimpleVector; 22 | 23 | import org.bukkit.configuration.serialization.ConfigurationSerialization; 24 | 25 | /** 26 | * SwornAPI utility class 27 | * 28 | * @author dmulloy2 29 | */ 30 | 31 | public class SwornAPI 32 | { 33 | private static boolean registered = false; 34 | 35 | public static void checkRegistrations() 36 | { 37 | if (! registered) 38 | { 39 | ConfigurationSerialization.registerClass(LazyLocation.class); 40 | ConfigurationSerialization.registerClass(SimpleVector.class); 41 | registered = true; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/SwornPlugin.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi; 19 | 20 | import java.util.List; 21 | import java.util.logging.Level; 22 | 23 | import net.dmulloy2.swornapi.commands.Command; 24 | import net.dmulloy2.swornapi.commands.CommandProps; 25 | import net.dmulloy2.swornapi.handlers.CommandHandler; 26 | import net.dmulloy2.swornapi.handlers.LogHandler; 27 | import net.dmulloy2.swornapi.handlers.PermissionHandler; 28 | import net.dmulloy2.swornapi.types.Reloadable; 29 | import net.dmulloy2.swornapi.types.Versioning; 30 | import net.dmulloy2.swornapi.types.Versioning.Version; 31 | 32 | import org.bukkit.ChatColor; 33 | import org.bukkit.configuration.file.FileConfiguration; 34 | import org.bukkit.plugin.java.JavaPlugin; 35 | 36 | import lombok.Getter; 37 | 38 | /** 39 | * Main SwornAPI class. Plugins utilizing this API should extend this class. 40 | * 41 | * @author dmulloy2 42 | */ 43 | 44 | public abstract class SwornPlugin extends JavaPlugin implements Reloadable 45 | { 46 | @Getter 47 | protected PermissionHandler permissionHandler; 48 | @Getter 49 | protected CommandHandler commandHandler; 50 | @Getter 51 | protected LogHandler logHandler; 52 | 53 | protected final CommandProps commandProps = new CommandProps(); 54 | 55 | /** 56 | * Allows the modification of basic command properties like the color scheme. 57 | * @return The command properties 58 | */ 59 | public CommandProps props() 60 | { 61 | return commandProps; 62 | } 63 | 64 | /** 65 | * Gets this plugin's prefix. Defaults to {@link ChatColor#YELLOW}. 66 | * @return This plugin's prefix 67 | */ 68 | public String getPrefix() 69 | { 70 | return ChatColor.YELLOW.toString(); 71 | } 72 | 73 | /** 74 | * Gets any extra lines to be displayed in the help menu. By default, this 75 | * method searches for extra help in the configuration. 76 | * 77 | * @return Any extra lines, or null if none 78 | */ 79 | public List getExtraHelp() 80 | { 81 | FileConfiguration config = getConfig(); 82 | if (config.isSet("extraHelp")) 83 | return config.getStringList("extraHelp"); 84 | return null; 85 | } 86 | 87 | /** 88 | * Gets this plugin's help command. Unless this is overriden, it will be 89 | * null before commands are registered. 90 | * @return Custom help command, or the default if unapplicable. 91 | */ 92 | public Command getHelpCommand() 93 | { 94 | return commandHandler.getCommand("help"); 95 | } 96 | 97 | /** 98 | * Gets this plugin's default command if applicable. The default command is 99 | * run if the first argument is not a valid command. This has no effect when 100 | * prefixed commands are not used. 101 | * @return The default command, or null if unapplicable. 102 | */ 103 | public Command getDefaultCommand() 104 | { 105 | return null; 106 | } 107 | 108 | /** 109 | * Exposes this plugin's ClassLoader. 110 | * @see JavaPlugin#getClassLoader() 111 | */ 112 | public ClassLoader classLoader() 113 | { 114 | return super.getClassLoader(); 115 | } 116 | 117 | /** 118 | * Checks if the currently running version of Minecraft is supported by 119 | * SwornAPI. If not, a warning is printed using the logHandler. 120 | */ 121 | public void checkVersion() 122 | { 123 | Version version = Versioning.getVersion(); 124 | if (version.wasDropped()) 125 | logHandler.log(Level.WARNING, "This version of {0} no longer supports {1}. Consider updating Spigot.", getName(), version.getName()); 126 | else if (! version.isSupported()) 127 | logHandler.log(Level.WARNING, "This version of {0} does not support {1}. Check for an update!", getName(), version.getName()); 128 | } 129 | 130 | @Override 131 | public void reload() 132 | { 133 | reloadConfig(); 134 | } 135 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/commands/CmdHelp.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.commands; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.stream.Collectors; 23 | 24 | import net.dmulloy2.swornapi.SwornPlugin; 25 | import net.dmulloy2.swornapi.types.CommandVisibility; 26 | import net.dmulloy2.swornapi.util.FormatUtil; 27 | import net.md_5.bungee.api.chat.BaseComponent; 28 | import net.md_5.bungee.api.chat.TextComponent; 29 | 30 | /** 31 | * Generic help command. This is a modified implementation of 32 | * {@link PaginatedCommand} with support for fancy text formatting. 33 | * 34 | * @author dmulloy2 35 | */ 36 | 37 | public class CmdHelp extends Command 38 | { 39 | private static final int linesPerPage = 6; 40 | private static final int pageArgIndex = 0; 41 | 42 | public CmdHelp(SwornPlugin plugin) 43 | { 44 | super(plugin); 45 | this.name = "help"; 46 | this.addOptionalArg("page"); 47 | this.description = "Shows " + plugin.getName() + " help"; 48 | this.visibility = CommandVisibility.ALL; 49 | this.usesPrefix = true; 50 | } 51 | 52 | @Override 53 | public void perform() 54 | { 55 | int index = 1; 56 | if (args.length > pageArgIndex) 57 | { 58 | try 59 | { 60 | index = Integer.parseInt(args[pageArgIndex]); 61 | if (index < 1 || index > getPageCount()) 62 | { 63 | err("&4There is no page with the index &c{0}&4.", index); 64 | return; 65 | } 66 | } 67 | catch (NumberFormatException ex) 68 | { 69 | err("&c{0} &4is not a number.", args[0]); 70 | return; 71 | } 72 | } 73 | 74 | if (isPlayer()) 75 | { 76 | for (BaseComponent[] components : getPage(index)) 77 | player.spigot().sendMessage(components); 78 | return; 79 | } 80 | 81 | // Fall back to legacy help 82 | for (String line : getLegacyPage(index)) 83 | sendMessage(line); 84 | } 85 | 86 | public String getHeader() 87 | { 88 | return props().getHelpHeader(); 89 | } 90 | 91 | public int getPageCount() 92 | { 93 | return (getListSize() + linesPerPage - 1) / linesPerPage; 94 | } 95 | 96 | public int getListSize() 97 | { 98 | return getHelpMenu().size(); 99 | } 100 | 101 | public List getPage(int index) 102 | { 103 | List lines = new ArrayList<>(); 104 | 105 | lines.addAll(getHeader(index)); 106 | lines.addAll(getLines((index - 1) * linesPerPage, index * linesPerPage)); 107 | 108 | BaseComponent[] footer = getFooter(); 109 | if (footer != null) 110 | lines.add(footer); 111 | 112 | return lines; 113 | } 114 | 115 | public List getLegacyPage(int index) 116 | { 117 | List lines = new ArrayList<>(); 118 | 119 | lines.addAll(getLegacyHeader(index)); 120 | lines.addAll(getLegacyLines((index - 1) * linesPerPage, index * linesPerPage)); 121 | 122 | String footer = props().getHelpFooter(); 123 | if (! footer.isEmpty()) 124 | lines.add(footer); 125 | 126 | return lines; 127 | } 128 | 129 | public List getHeader(int index) 130 | { 131 | return getLegacyHeader(index).stream().map(TextComponent::fromLegacyText).collect(Collectors.toList()); 132 | } 133 | 134 | public List getLegacyHeader(int index) 135 | { 136 | List ret = new ArrayList<>(); 137 | 138 | ret.add(format(getHeader(), plugin.getName(), index, getPageCount())); 139 | 140 | List extraHelp = plugin.getExtraHelp(); 141 | if (extraHelp != null) 142 | { 143 | for (String extra : extraHelp) 144 | ret.add(FormatUtil.format(extra)); 145 | } 146 | 147 | ret.add(format("{b}Key: {h} [optional]")); 148 | return ret; 149 | } 150 | 151 | public List getLines(int startIndex, int endIndex) 152 | { 153 | List helpMenu = getHelpMenu(); 154 | List lines = new ArrayList<>(); 155 | 156 | for (int i = startIndex; i < endIndex && i < getListSize(); i++) 157 | { 158 | lines.add(helpMenu.get(i)); 159 | } 160 | 161 | return lines; 162 | } 163 | 164 | public List getLegacyLines(int startIndex, int endIndex) 165 | { 166 | List helpMenu = getLegacyHelpMenu(); 167 | List lines = new ArrayList<>(); 168 | 169 | for (int i = startIndex; i < endIndex && i < getListSize(); i++) 170 | { 171 | lines.add(helpMenu.get(i)); 172 | } 173 | 174 | return lines; 175 | } 176 | 177 | public BaseComponent[] getFooter() 178 | { 179 | String footer = props().getHelpFooter(); 180 | return TextComponent.fromLegacyText(format(footer)); 181 | } 182 | 183 | private List getHelpMenu() 184 | { 185 | List ret = new ArrayList<>(); 186 | 187 | for (Command cmd : plugin.getCommandHandler().getRegisteredPrefixedCommands()) 188 | { 189 | if (cmd.isVisibleTo(sender)) 190 | { 191 | ret.addAll(cmd.getFancyUsageTemplate(true)); 192 | 193 | if (cmd.hasSubCommands()) 194 | ret.addAll(cmd.getFancySubCommandHelp(true)); 195 | } 196 | } 197 | 198 | for (Command cmd : plugin.getCommandHandler().getRegisteredCommands()) 199 | { 200 | if (cmd.isVisibleTo(sender)) 201 | { 202 | ret.addAll(cmd.getFancyUsageTemplate(true)); 203 | 204 | if (cmd.hasSubCommands()) 205 | ret.addAll(cmd.getFancySubCommandHelp(true)); 206 | } 207 | } 208 | 209 | return ret; 210 | } 211 | 212 | private List getLegacyHelpMenu() 213 | { 214 | List ret = new ArrayList<>(); 215 | 216 | for (Command cmd : plugin.getCommandHandler().getRegisteredPrefixedCommands()) 217 | { 218 | if (cmd.isVisibleTo(sender)) 219 | { 220 | ret.addAll(cmd.getUsageTemplate(true)); 221 | 222 | if (cmd.hasSubCommands()) 223 | ret.addAll(cmd.getSubCommandHelp(true)); 224 | } 225 | } 226 | 227 | for (Command cmd : plugin.getCommandHandler().getRegisteredCommands()) 228 | { 229 | if (cmd.isVisibleTo(sender)) 230 | { 231 | ret.addAll(cmd.getUsageTemplate(true)); 232 | 233 | if (cmd.hasSubCommands()) 234 | ret.addAll(cmd.getSubCommandHelp(true)); 235 | } 236 | } 237 | 238 | return ret; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/commands/CmdReload.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.commands; 19 | 20 | import net.dmulloy2.swornapi.SwornPlugin; 21 | import net.dmulloy2.swornapi.types.IPermission; 22 | 23 | /** 24 | * Generic plugin reload command 25 | * @author dmulloy2 26 | * 27 | * @see SwornPlugin#reload() 28 | * @see CommandProps#setReloadPerm(IPermission) 29 | */ 30 | public class CmdReload extends Command 31 | { 32 | public CmdReload(SwornPlugin plugin) 33 | { 34 | super(plugin); 35 | this.name = "reload"; 36 | this.description = "Reload " + plugin.getName(); 37 | this.permission = props().getReloadPerm(); 38 | this.usesPrefix = true; 39 | } 40 | 41 | @Override 42 | public void perform() 43 | { 44 | long start = System.currentTimeMillis(); 45 | 46 | if (isPlayer()) 47 | plugin.getLogHandler().log("{0} is reloading the plugin", player.getName()); 48 | sendpMessage("Reloading &b{0}&e...", plugin.getName()); 49 | 50 | plugin.reload(); 51 | 52 | if (isPlayer()) 53 | plugin.getLogHandler().log("{0} reloaded the plugin. Took {1} ms", 54 | player.getName(), System.currentTimeMillis() - start); 55 | sendpMessage("Reload complete! Took &b{0} &ems!", System.currentTimeMillis() - start); 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/commands/CommandProps.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.commands; 19 | 20 | import net.dmulloy2.swornapi.types.IPermission; 21 | import net.dmulloy2.swornapi.util.FormatUtil; 22 | 23 | import lombok.Getter; 24 | import lombok.Setter; 25 | import lombok.experimental.Accessors; 26 | 27 | /** 28 | * @author dmulloy2 29 | */ 30 | @Getter 31 | @Setter 32 | @Accessors(chain=true) 33 | public class CommandProps 34 | { 35 | private String errorPrefix = "&cError: &4"; 36 | private String baseColor = "&e"; 37 | private String accentColor = "&b"; 38 | private String headerColor = "&3"; 39 | private String helpHeader = "&3---- &e{0} Commands &3- &e{1}&3/&e{2} &3----"; 40 | private String helpFooter = "{b}Hover to see command information. Click to insert into chat."; 41 | private IPermission reloadPerm = null; 42 | 43 | public CommandProps() { } 44 | 45 | public String format(String string, Object... args) 46 | { 47 | return FormatUtil.format(string 48 | .replace("{b}", baseColor) 49 | .replace("{a}", accentColor) 50 | .replace("{h}", headerColor), 51 | args); 52 | } 53 | 54 | public String formatErr(String string, Object... args) 55 | { 56 | return format(errorPrefix + string, args); 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/commands/PaginatedCommand.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.commands; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import net.dmulloy2.swornapi.SwornPlugin; 24 | 25 | /** 26 | * Represents a command that has pagination. 27 | * 28 | * @author dmulloy2 29 | */ 30 | 31 | public abstract class PaginatedCommand extends Command 32 | { 33 | protected int linesPerPage, pageArgIndex; 34 | 35 | public PaginatedCommand(SwornPlugin plugin) 36 | { 37 | super(plugin); 38 | this.linesPerPage = 10; 39 | } 40 | 41 | @Override 42 | public void perform() 43 | { 44 | int index = 1; 45 | if (args.length > pageArgIndex) 46 | { 47 | try 48 | { 49 | index = Integer.parseInt(args[pageArgIndex]); 50 | if (index < 1 || index > getPageCount()) 51 | { 52 | err("&4There is no page with the index &c{0}&4.", index); 53 | return; 54 | } 55 | } 56 | catch (NumberFormatException ex) 57 | { 58 | err("&c{0} &4is not a number.", args[0]); 59 | return; 60 | } 61 | } 62 | 63 | for (String s : getPage(index)) 64 | sendMessage(s); 65 | } 66 | 67 | /** 68 | * Gets the number of pages in the list associated with this command 69 | * 70 | * @return The number of pages 71 | */ 72 | public int getPageCount() 73 | { 74 | return (getListSize() + linesPerPage - 1) / linesPerPage; 75 | } 76 | 77 | /** 78 | * Gets the size of the list associated with this command 79 | * 80 | * @return The size of the list 81 | */ 82 | public abstract int getListSize(); 83 | 84 | /** 85 | * Gets all of the page lines for the specified page index 86 | * 87 | * @param index The page index 88 | * @return List of page lines 89 | */ 90 | public List getPage(int index) 91 | { 92 | List lines = new ArrayList<>(); 93 | lines.add(getHeader(index)); 94 | lines.addAll(getLines((index - 1) * linesPerPage, index * linesPerPage)); 95 | String footer = getFooter(); 96 | if (! footer.isEmpty()) 97 | lines.add(footer); 98 | return lines; 99 | } 100 | 101 | /** 102 | * Gets the header {@link String} for this command 103 | * 104 | * @param index The page index 105 | * @return String header for this page 106 | */ 107 | public abstract String getHeader(int index); 108 | 109 | /** 110 | * Gets all lines from startIndex up to but not including endIndex 111 | * 112 | * @param startIndex The starting index in the list 113 | * @param endIndex The end index in the list 114 | * @return All lines between start and end indexes 115 | */ 116 | public List getLines(int startIndex, int endIndex) 117 | { 118 | List lines = new ArrayList<>(); 119 | for (int i = startIndex; i < endIndex && i < getListSize(); i++) 120 | { 121 | String line = getLine(i); 122 | if (line != null) 123 | lines.add(getLine(i)); 124 | } 125 | return lines; 126 | } 127 | 128 | /** 129 | * Gets a {@link String} representation of the line at the specified index 130 | * in the list 131 | * 132 | * @param index The index of the entry in the list 133 | * @return A string representation of the line 134 | */ 135 | public abstract String getLine(int index); 136 | 137 | public String getFooter() 138 | { 139 | return ""; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/commands/SubCommand.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.commands; 19 | 20 | /** 21 | * Represents a sub-command 22 | * @author dmulloy2 23 | */ 24 | 25 | public abstract class SubCommand extends Command 26 | { 27 | public SubCommand(Command parent) 28 | { 29 | super(parent.plugin); 30 | this.parent = parent; 31 | } 32 | 33 | protected boolean argMatchesIdentifier(String arg) 34 | { 35 | if (arg.equalsIgnoreCase(name)) 36 | return true; 37 | 38 | for (String alias : aliases) 39 | { 40 | if (arg.equalsIgnoreCase(alias)) 41 | return true; 42 | } 43 | 44 | return false; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/config/ConfigParser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | *

5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | *

10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | *

15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.config; 19 | 20 | import net.dmulloy2.swornapi.SwornPlugin; 21 | import net.dmulloy2.swornapi.util.FormatUtil; 22 | import net.dmulloy2.swornapi.util.ItemUtil; 23 | import net.dmulloy2.swornapi.util.NumberUtil; 24 | import net.dmulloy2.swornapi.util.Util; 25 | 26 | import org.bukkit.Material; 27 | import org.bukkit.configuration.file.FileConfiguration; 28 | 29 | import java.lang.reflect.Field; 30 | import java.lang.reflect.Method; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | import java.util.Locale; 34 | import java.util.concurrent.TimeUnit; 35 | import java.util.logging.Level; 36 | 37 | /** 38 | * Parses a configuration class. 39 | * 40 | * @author dmulloy2 41 | */ 42 | 43 | @SuppressWarnings({ "unchecked", "rawtypes" }) 44 | public final class ConfigParser 45 | { 46 | public static final int TICKS_PER_SECOND = 20; 47 | 48 | private final SwornPlugin plugin; 49 | private final FileConfiguration config; 50 | private final Class clazz; 51 | private final Object object; 52 | 53 | private ConfigParser(SwornPlugin plugin, FileConfiguration config, Class clazz, Object object) 54 | { 55 | this.plugin = plugin; 56 | this.config = config; 57 | this.clazz = clazz; 58 | this.object = object; 59 | } 60 | 61 | /** 62 | * Parses an instance-based configuration. 63 | * 64 | * @param plugin Plugin instance 65 | * @param object Object to parse 66 | */ 67 | public static void parse(SwornPlugin plugin, Object object) 68 | { 69 | new ConfigParser(plugin, plugin.getConfig(), object.getClass(), object).parse(); 70 | } 71 | 72 | /** 73 | * Parses a static-based configuration. 74 | * 75 | * @param plugin Plugin instance 76 | * @param clazz Configuration class 77 | */ 78 | public static void parse(SwornPlugin plugin, Class clazz) 79 | { 80 | new ConfigParser(plugin, plugin.getConfig(), clazz, null).parse(); 81 | } 82 | 83 | public static void parse(SwornPlugin plugin, FileConfiguration config, Object object) 84 | { 85 | new ConfigParser(plugin, config, object.getClass(), object).parse(); 86 | } 87 | 88 | public static void parse(SwornPlugin plugin, FileConfiguration config, Class clazz) 89 | { 90 | new ConfigParser(plugin, config, clazz, null).parse(); 91 | } 92 | 93 | private Object parseValue(Object value, Object def, String path, Field field, ValueOptions options) 94 | { 95 | return switch (options.value()) 96 | { 97 | case FORMAT -> FormatUtil.format(value.toString()); 98 | case LIST_LOWER_CASE -> 99 | { 100 | var original = (List) value; 101 | var lower = new ArrayList<>(original.size()); 102 | for (String s : original) 103 | { 104 | lower.add(s.toLowerCase()); 105 | } 106 | yield lower; 107 | } 108 | case LIST_UPPER_CASE -> 109 | { 110 | var original = (List) value; 111 | var upper = new ArrayList<>(original.size()); 112 | for (String s : original) 113 | { 114 | upper.add(s.toLowerCase()); 115 | } 116 | yield upper; 117 | } 118 | case LOWER_CASE -> value.toString().toLowerCase(Locale.ENGLISH); 119 | case MINUTE_TO_MILLIS -> TimeUnit.MINUTES.toMillis(NumberUtil.toLong(value)); 120 | case MINUTE_TO_TICKS -> TimeUnit.MINUTES.toSeconds(NumberUtil.toLong(value)) * TICKS_PER_SECOND; 121 | case PARSE_ENUM -> Enum.valueOf((Class) field.getType(), value.toString().toUpperCase().replace(" ", "_").replace(".", "_")); 122 | case PARSE_ITEM -> ItemUtil.readItem(value.toString(), plugin); 123 | case PARSE_ITEMS -> ItemUtil.readItems((List) value, plugin); 124 | case PARSE_MATERIAL -> 125 | { 126 | var material = Material.matchMaterial(value.toString()); 127 | if (material == null && !options.allowNull()) 128 | { 129 | plugin.getLogHandler().log(Level.WARNING, "Failed to read material \"{0}\" from {1}. Defaulting to {2}", value, path, def); 130 | yield def; 131 | } else 132 | { 133 | yield material; 134 | } 135 | } 136 | case PARSE_MATERIALS -> 137 | { 138 | List materials = new ArrayList<>(); 139 | for (Object element : (List) value) 140 | { 141 | String string = element.toString(); 142 | Material material = Material.matchMaterial(string); 143 | if (material == null && !options.allowNull()) 144 | { 145 | plugin.getLogHandler().log(Level.WARNING, "Failed to read material \"{0}\" from {1}", string, path); 146 | } else 147 | { 148 | materials.add(material); 149 | } 150 | } 151 | yield materials; 152 | } 153 | case SECOND_TO_MILLIS -> TimeUnit.SECONDS.toMillis(NumberUtil.toLong(value)); 154 | case SECOND_TO_TICKS -> NumberUtil.toLong(value) * TICKS_PER_SECOND; 155 | }; 156 | } 157 | 158 | private void parse() 159 | { 160 | for (Field field : clazz.getDeclaredFields()) 161 | { 162 | if (!field.isAccessible()) field.setAccessible(true); 163 | 164 | Object def = null; 165 | 166 | try 167 | { 168 | def = field.get(object); 169 | } catch (Throwable ex) 170 | { 171 | plugin.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "accessing field {0}", field)); 172 | } 173 | 174 | Key key = field.getAnnotation(Key.class); 175 | if (key == null) 176 | { 177 | continue; 178 | } 179 | 180 | String path = key.value(); 181 | Object value = def; 182 | 183 | try 184 | { 185 | value = config.get(path); 186 | if (value == null) 187 | { 188 | continue; 189 | } 190 | 191 | ValueOptions options = field.getAnnotation(ValueOptions.class); 192 | if (options != null) 193 | { 194 | value = parseValue(value, def, path, field, options); 195 | 196 | for (Class custom : options.custom()) 197 | { 198 | Method convert = custom.getMethod("convert", Object.class); 199 | if (convert.isAccessible()) 200 | { 201 | try 202 | { 203 | value = convert.invoke(null, value); 204 | } catch (Throwable ex) 205 | { 206 | plugin.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "converting {0} using {1}", path, custom.getName())); 207 | } 208 | } 209 | } 210 | } 211 | 212 | try 213 | { 214 | field.set(object, value); 215 | } catch (IllegalArgumentException ex) 216 | { 217 | plugin.getLogHandler().log(Level.WARNING, "\"{0}\" is the wrong type: expected {1}, but got {2}", path, field.getType(), value.getClass().getName()); 218 | plugin.getLogHandler().debug(Level.WARNING, Util.getUsefulStack(ex, "setting {0} to {1}", field, value)); 219 | } 220 | } catch (ClassCastException ex) 221 | { 222 | plugin.getLogHandler().log(Level.WARNING, "\"{0}\" is the wrong type: expected {1}, but got {2}", path, field.getType(), value.getClass().getName()); 223 | plugin.getLogHandler().debug(Level.WARNING, Util.getUsefulStack(ex, "setting {0} to {1}", field, value)); 224 | } catch (Throwable ex) 225 | { 226 | plugin.getLogHandler().log(Level.SEVERE, Util.getUsefulStack(ex, "loading value from {0}", path)); 227 | } 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/config/Key.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.config; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Represents a key in a standard YAML configuration. 27 | * 28 | * @author dmulloy2 29 | */ 30 | 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target(ElementType.FIELD) 33 | public @interface Key 34 | { 35 | /** 36 | * This key's path, in standard YAML format 37 | * 38 | * @return This key's path 39 | */ 40 | String value(); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/config/ValueOptions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.config; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * Represents transformations done to config values. 27 | * 28 | * @author dmulloy2 29 | */ 30 | 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target(ElementType.FIELD) 33 | public @interface ValueOptions 34 | { 35 | /** 36 | * An array of standard value options. 37 | * 38 | * @return Standard value options 39 | */ 40 | ValueOption value(); 41 | 42 | /** 43 | * Whether or not to allow null values. Defaults to false. 44 | * 45 | * @return True or false 46 | */ 47 | boolean allowNull() default false; 48 | 49 | /** 50 | * An array of custom value options. Options provided here must have a 51 | * static method, public static Object convert(Object), but 52 | * this is unenforcable due to how Java handles annotations. 53 | * 54 | * @return Custom value options 55 | */ 56 | Class[] custom() default {}; 57 | 58 | /** 59 | * Represents a standard value option. 60 | * 61 | * @author dmulloy2 62 | */ 63 | enum ValueOption 64 | { 65 | FORMAT, 66 | LIST_LOWER_CASE, 67 | LIST_UPPER_CASE, 68 | LOWER_CASE, 69 | MINUTE_TO_MILLIS, 70 | MINUTE_TO_TICKS, 71 | PARSE_ENUM, 72 | PARSE_ITEM, 73 | PARSE_ITEMS, 74 | PARSE_MATERIAL, 75 | PARSE_MATERIALS, 76 | SECOND_TO_MILLIS, 77 | SECOND_TO_TICKS 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/exception/BadTimeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.exception; 19 | 20 | /** 21 | * An Exception that results from bad time. 22 | * 23 | * @author dmulloy2 24 | */ 25 | 26 | public class BadTimeException extends RuntimeException 27 | { 28 | private static final long serialVersionUID = 5846361750537427952L; 29 | 30 | /** 31 | * Constructs an empty BadTimeException. 32 | */ 33 | public BadTimeException() 34 | { 35 | super(); 36 | } 37 | 38 | /** 39 | * Constructs a BadTimeException with a given message. 40 | * 41 | * @param message Exception message 42 | */ 43 | public BadTimeException(String message) 44 | { 45 | super(message); 46 | } 47 | 48 | /** 49 | * Constructs a BadTimeException with a given message and cause. 50 | * 51 | * @param message Exception message 52 | * @param cause {@link Throwable} cause 53 | */ 54 | public BadTimeException(String message, Throwable cause) 55 | { 56 | super(message, cause); 57 | } 58 | 59 | @Override 60 | public String toString() 61 | { 62 | Throwable cause = getCause(); 63 | return cause != null ? cause.toString() : getMessage(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/exception/CommandException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package net.dmulloy2.swornapi.exception; 5 | 6 | import net.dmulloy2.swornapi.util.FormatUtil; 7 | 8 | import lombok.Getter; 9 | 10 | /** 11 | * @author dmulloy2 12 | */ 13 | public class CommandException extends RuntimeException 14 | { 15 | private static final long serialVersionUID = - 3677819495994061443L; 16 | 17 | private final @Getter Reason reason; 18 | 19 | public CommandException(Reason reason, String message, Object... args) 20 | { 21 | super(FormatUtil.format(message, args)); 22 | this.reason = reason; 23 | } 24 | 25 | public CommandException(Reason reason, Throwable cause, String message, Object... args) 26 | { 27 | super(FormatUtil.format(message, args), cause); 28 | this.reason = reason; 29 | } 30 | 31 | public CommandException(Reason reason) 32 | { 33 | this(reason, ""); 34 | } 35 | 36 | public enum Reason 37 | { 38 | /** 39 | * Breaks out of command execution without a message 40 | */ 41 | BREAK, 42 | /** 43 | * Invalid argument input 44 | */ 45 | INPUT, 46 | /** 47 | * Invalid syntax supplied 48 | */ 49 | SYNTAX, 50 | /** 51 | * Thrown by checkArgument and checkNotNull 52 | */ 53 | VALIDATE 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/gui/AbstractGUI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.gui; 19 | 20 | import net.dmulloy2.swornapi.SwornPlugin; 21 | import net.dmulloy2.swornapi.util.FormatUtil; 22 | import net.dmulloy2.swornapi.util.NumberUtil; 23 | 24 | import org.apache.commons.lang.Validate; 25 | import org.bukkit.ChatColor; 26 | import org.bukkit.entity.Player; 27 | import org.bukkit.event.inventory.InventoryClickEvent; 28 | import org.bukkit.event.inventory.InventoryCloseEvent; 29 | import org.bukkit.inventory.Inventory; 30 | 31 | /** 32 | * A clickable chest GUI 33 | * @author dmulloy2 34 | */ 35 | 36 | public abstract class AbstractGUI 37 | { 38 | protected final Player player; 39 | protected final SwornPlugin plugin; 40 | 41 | public AbstractGUI(SwornPlugin plugin, Player player) 42 | { 43 | Validate.notNull(plugin, "plugin cannot be null"); 44 | Validate.notNull(player, "player cannot be null!"); 45 | this.player = player; 46 | this.plugin = plugin; 47 | } 48 | 49 | /** 50 | * Sets up this inventory, handling the size and title. This method must be 51 | * called for the inventory to actually open. 52 | * 53 | * @throws IllegalArgumentException if {@code size < 0}, {@code size > 54}, 54 | * or the title is null. 55 | */ 56 | protected final void setup() 57 | { 58 | // Size checks 59 | int size = NumberUtil.roundUp(getSize(), 9); 60 | Validate.isTrue(size > 0, "Inventory size must not be negative!"); 61 | Validate.isTrue(size <= 54, "Inventory size is too large! (" + size + " > 54)"); 62 | 63 | // Validate title 64 | String title = getTitle(); 65 | Validate.notNull(title, "Inventory title cannot be null!"); 66 | title = FormatUtil.format(getTitle()); 67 | 68 | Inventory inventory; 69 | 70 | try 71 | { 72 | inventory = plugin.getServer().createInventory(player, size, title); 73 | } 74 | catch (IllegalArgumentException ex) 75 | { 76 | // Truncate the title and add the unicode ... 77 | title = title.substring(0, 31) + "\u2026"; 78 | inventory = plugin.getServer().createInventory(player, size, title); 79 | } 80 | 81 | stock(inventory); 82 | player.openInventory(inventory); 83 | } 84 | 85 | public final Player getPlayer() 86 | { 87 | return player; 88 | } 89 | 90 | // ---- Required Methods 91 | 92 | /** 93 | * Gets the amount of items in this inventory. If this is not a multiple of 94 | * 9, it will be rounded up. This number must be less than or equal to 54. 95 | * 96 | * @return The amount of items 97 | */ 98 | public abstract int getSize(); 99 | 100 | /** 101 | * Gets the title of this inventory. Before 1.8 this had to be less than 32 102 | * characters. 103 | * 104 | * @return The title 105 | */ 106 | public abstract String getTitle(); 107 | 108 | /** 109 | * Stocks this inventory with items. 110 | * 111 | * @param inventory Inventory to stock 112 | */ 113 | public abstract void stock(Inventory inventory); 114 | 115 | // ---- Messaging 116 | 117 | /** 118 | * Sends an error message to the player. 119 | * 120 | * @param message Message to send 121 | * @param args Objects to format in 122 | */ 123 | protected final void err(String message, Object... args) 124 | { 125 | sendMessage("&cError: &4" + FormatUtil.format(message, args)); 126 | } 127 | 128 | /** 129 | * Sends a prefixed message to the player. 130 | * 131 | * @param message Message to send 132 | * @param objects Objects to format in 133 | */ 134 | protected final void sendpMessage(String message, Object... objects) 135 | { 136 | sendMessage(plugin.getPrefix() + message, objects); 137 | } 138 | 139 | /** 140 | * Sends a message to the player. 141 | * 142 | * @param message Message to send 143 | * @param objects Objects to format in 144 | */ 145 | protected final void sendMessage(String message, Object... objects) 146 | { 147 | player.sendMessage(ChatColor.YELLOW + FormatUtil.format(message, objects)); 148 | } 149 | 150 | // ---- Events 151 | 152 | /** 153 | * Called when an InventoryClickEvent is called. 154 | * 155 | * @param event The event 156 | */ 157 | public void onInventoryClick(InventoryClickEvent event) { } 158 | 159 | /** 160 | * Called when an InventoryCloseEvent is called. 161 | * 162 | * @param event The event 163 | */ 164 | public void onInventoryClose(InventoryCloseEvent event) { } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/gui/GUIHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.gui; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import net.dmulloy2.swornapi.SwornPlugin; 24 | 25 | import org.apache.commons.lang.Validate; 26 | import org.bukkit.entity.HumanEntity; 27 | import org.bukkit.entity.Player; 28 | import org.bukkit.event.EventHandler; 29 | import org.bukkit.event.EventPriority; 30 | import org.bukkit.event.Listener; 31 | import org.bukkit.event.inventory.InventoryClickEvent; 32 | import org.bukkit.event.inventory.InventoryCloseEvent; 33 | import org.bukkit.event.player.PlayerQuitEvent; 34 | 35 | /** 36 | * @author dmulloy2 37 | */ 38 | 39 | public class GUIHandler implements Listener 40 | { 41 | private final Map open; 42 | 43 | public GUIHandler(SwornPlugin plugin) 44 | { 45 | this.open = new HashMap<>(); 46 | plugin.getServer().getPluginManager().registerEvents(this, plugin); 47 | } 48 | 49 | /** 50 | * Opens a given GUI for a given {@link Player}. 51 | * 52 | * @param player Player to open GUI for 53 | * @param gui GUI to open 54 | */ 55 | public void open(Player player, AbstractGUI gui) 56 | { 57 | Validate.notNull(player, "player cannot be null!"); 58 | Validate.notNull(gui, "gui cannot be null!"); 59 | open.put(player.getName(), gui); 60 | } 61 | 62 | /** 63 | * Opens a given GUI. 64 | * 65 | * @param gui GUI to open 66 | */ 67 | public void open(AbstractGUI gui) 68 | { 69 | Validate.notNull(gui, "gui cannot be null!"); 70 | open(gui.getPlayer(), gui); 71 | } 72 | 73 | /** 74 | * Closes all the currently open GUIs. 75 | */ 76 | public void closeAll() 77 | { 78 | for (AbstractGUI gui : open.values()) 79 | { 80 | gui.getPlayer().closeInventory(); 81 | } 82 | } 83 | 84 | /** 85 | * Gets a map containing the currently open GUIs. 86 | * 87 | * @return The map 88 | */ 89 | public Map getOpen() 90 | { 91 | return open; 92 | } 93 | 94 | // ---- Listeners 95 | 96 | @EventHandler(priority = EventPriority.HIGHEST) 97 | public void onInventoryClick(InventoryClickEvent event) 98 | { 99 | HumanEntity clicker = event.getWhoClicked(); 100 | if (clicker instanceof Player player) 101 | { 102 | if (open.containsKey(player.getName())) 103 | { 104 | AbstractGUI gui = open.get(player.getName()); 105 | gui.onInventoryClick(event); 106 | } 107 | } 108 | } 109 | 110 | @EventHandler(priority = EventPriority.HIGHEST) 111 | public void onInventoryClose(InventoryCloseEvent event) 112 | { 113 | HumanEntity closer = event.getPlayer(); 114 | if (closer instanceof Player player) 115 | { 116 | if (open.containsKey(player.getName())) 117 | { 118 | AbstractGUI gui = open.get(player.getName()); 119 | gui.onInventoryClose(event); 120 | open.remove(player.getName()); 121 | } 122 | } 123 | } 124 | 125 | @EventHandler(priority = EventPriority.MONITOR) 126 | public void onPlayerQuit(PlayerQuitEvent event) 127 | { 128 | Player player = event.getPlayer(); 129 | if (open.containsKey(player.getName())) 130 | { 131 | player.closeInventory(); 132 | open.remove(player.getName()); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/handlers/CommandHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.handlers; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.List; 23 | import java.util.logging.Level; 24 | 25 | import net.dmulloy2.swornapi.SwornPlugin; 26 | import net.dmulloy2.swornapi.commands.Command; 27 | import net.dmulloy2.swornapi.util.FormatUtil; 28 | 29 | import net.md_5.bungee.api.chat.BaseComponent; 30 | import net.md_5.bungee.api.chat.ComponentBuilder; 31 | 32 | import org.apache.commons.lang.Validate; 33 | import org.bukkit.command.CommandExecutor; 34 | import org.bukkit.command.CommandSender; 35 | import org.bukkit.command.PluginCommand; 36 | import org.bukkit.entity.Player; 37 | 38 | /** 39 | * Handles commands. This supports both prefixed and non-prefixed commands. 40 | * 41 | * @author dmulloy2 42 | */ 43 | 44 | public class CommandHandler implements CommandExecutor 45 | { 46 | private String commandPrefix; 47 | private List registeredPrefixedCommands; 48 | private final List registeredCommands; 49 | 50 | private final SwornPlugin plugin; 51 | public CommandHandler(SwornPlugin plugin) 52 | { 53 | this.plugin = plugin; 54 | this.registeredCommands = new ArrayList<>(); 55 | } 56 | 57 | /** 58 | * Registers a non-prefixed {@link Command}. 59 | * 60 | * @param command Non-prefixed {@link Command} to register. 61 | */ 62 | public void registerCommand(Command command) 63 | { 64 | Validate.notNull(command, "command cannot be null!"); 65 | PluginCommand pluginCommand = plugin.getCommand(command.getName()); 66 | if (pluginCommand != null) 67 | { 68 | pluginCommand.setExecutor(command); 69 | registeredCommands.add(command); 70 | } 71 | else 72 | { 73 | plugin.getLogHandler().log(Level.WARNING, "Entry for command {0} is missing in plugin.yml", command.getName()); 74 | } 75 | } 76 | 77 | /** 78 | * Registers a prefixed {@link Command}. The commandPrefix must be set for 79 | * this method to work. 80 | * 81 | * @param command Prefixed {@link Command} to register. 82 | */ 83 | public void registerPrefixedCommand(Command command) 84 | { 85 | Validate.notNull(command, "command cannot be null!"); 86 | if (commandPrefix != null) 87 | registeredPrefixedCommands.add(command); 88 | } 89 | 90 | /** 91 | * Gets a {@link List} of all registered non-prefixed commands. 92 | * 93 | * @return The list 94 | */ 95 | public List getRegisteredCommands() 96 | { 97 | return registeredCommands; 98 | } 99 | 100 | /** 101 | * Gets a {@link List} of all registered prefixed commands. 102 | * 103 | * @return The list 104 | */ 105 | public List getRegisteredPrefixedCommands() 106 | { 107 | return registeredPrefixedCommands; 108 | } 109 | 110 | /** 111 | * Gets the command prefix. 112 | * 113 | * @return The prefix, or null if not used 114 | */ 115 | public String getCommandPrefix() 116 | { 117 | return commandPrefix; 118 | } 119 | 120 | /** 121 | * Sets the command prefix. This method must be called before any prefixed 122 | * commands are registered. 123 | * 124 | * @param commandPrefix Command prefix 125 | */ 126 | public void setCommandPrefix(String commandPrefix) 127 | { 128 | Validate.notEmpty(commandPrefix, "prefix cannot be null or empty!"); 129 | this.commandPrefix = commandPrefix; 130 | this.registeredPrefixedCommands = new ArrayList<>(); 131 | 132 | plugin.getCommand(commandPrefix).setExecutor(this); 133 | } 134 | 135 | /** 136 | * Whether or not the command prefix is used. 137 | * 138 | * @return True if the command prefix is used, false if not 139 | */ 140 | public boolean usesCommandPrefix() 141 | { 142 | return commandPrefix != null; 143 | } 144 | 145 | /** 146 | * Gets a {@link Command} by name. 147 | * 148 | * @param name Command name 149 | * @return Command, or null if not found 150 | */ 151 | public final Command getCommand(String name) 152 | { 153 | Validate.notNull(name, "name cannot be null!"); 154 | for (Command command : registeredPrefixedCommands) 155 | { 156 | if (name.equalsIgnoreCase(command.getName()) || command.getAliases().contains(name.toLowerCase())) 157 | return command; 158 | } 159 | 160 | for (Command command : registeredCommands) 161 | { 162 | if (name.equalsIgnoreCase(command.getName()) || command.getAliases().contains(name.toLowerCase())) 163 | return command; 164 | } 165 | 166 | return null; 167 | } 168 | 169 | @Override 170 | public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) 171 | { 172 | if (args.length > 0) 173 | { 174 | String name = args[0]; 175 | String[] originalArgs = args; 176 | args = Arrays.copyOfRange(args, 1, args.length); 177 | 178 | Command command = getCommand(name); 179 | if (command != null) 180 | { 181 | command.execute(sender, args); 182 | return true; 183 | } 184 | 185 | Command def = plugin.getDefaultCommand(); 186 | if (def != null) 187 | { 188 | def.execute(sender, originalArgs); 189 | return true; 190 | } 191 | 192 | if (sender instanceof Player player) 193 | { 194 | List templates = getHelpCommand().getFancyUsageTemplate(); 195 | String error = FormatUtil.format("&cError: &4Unknown command \"&c{0}&4\". Try ", name); 196 | BaseComponent[] components = new ComponentBuilder(error).append(templates.get(0)).create(); 197 | player.spigot().sendMessage(components); 198 | } 199 | else 200 | { 201 | List templates = getHelpCommand().getUsageTemplate(false); 202 | sender.sendMessage(FormatUtil.format("&cError: &4Unknown command \"&c{0}&4\". Try {1}", name, templates.get(0))); 203 | } 204 | } 205 | else 206 | { 207 | getHelpCommand().execute(sender, args); 208 | } 209 | 210 | return true; 211 | } 212 | 213 | public final Command getHelpCommand() 214 | { 215 | if (plugin.getHelpCommand() != null) 216 | return plugin.getHelpCommand(); 217 | 218 | return getCommand("help"); 219 | } 220 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/handlers/LogHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.handlers; 19 | 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | import net.dmulloy2.swornapi.SwornPlugin; 24 | import net.dmulloy2.swornapi.util.FormatUtil; 25 | 26 | /** 27 | * Handles logging and formatting through the plugin's logger. 28 | * 29 | * @author dmulloy2 30 | */ 31 | public class LogHandler 32 | { 33 | private final SwornPlugin plugin; 34 | private final Logger logger; 35 | 36 | public LogHandler(SwornPlugin plugin, Logger logger) 37 | { 38 | this.plugin = plugin; 39 | this.logger = logger; 40 | } 41 | 42 | public LogHandler(SwornPlugin plugin) 43 | { 44 | this(plugin, plugin.getLogger()); 45 | } 46 | 47 | /** 48 | * Logs a formatted message to console with a given level. 49 | * 50 | * @param level Logging {@link Level}. 51 | * @param msg Message to log. 52 | * @param objects Objects to format in. 53 | */ 54 | public final void log(Level level, String msg, Object... objects) 55 | { 56 | logger.log(level, FormatUtil.format(msg, objects)); 57 | } 58 | 59 | /** 60 | * Logs a formatted message to console with INFO level. 61 | * 62 | * @param msg Message to log. 63 | * @param objects Objects to format in. 64 | */ 65 | public final void log(String msg, Object... objects) 66 | { 67 | log(Level.INFO, msg, objects); 68 | } 69 | 70 | /** 71 | * Logs a debug message to console with a given level if debug 72 | * is set to true in the config.yml. 73 | * 74 | * @param level Logging {@link Level}. 75 | * @param msg Message to log. 76 | * @param objects Objects to format in. 77 | */ 78 | public final void debug(Level level, String msg, Object... objects) 79 | { 80 | if (isGlobalDebugEnabled() || plugin.getConfig().getBoolean("debug", false)) 81 | log(level, "[Debug] " + msg, objects); 82 | } 83 | 84 | /** 85 | * Logs a debug message to console with the INFO level if debug 86 | * is set to true in the config.yml. 87 | * 88 | * @param msg Message to log. 89 | * @param objects Objects to format in. 90 | */ 91 | public final void debug(String msg, Object... objects) 92 | { 93 | debug(Level.INFO, msg, objects); 94 | } 95 | 96 | /** 97 | * Logs a debug message to the console if the system property 98 | * swornapi.debug is true. 99 | * 100 | * @param msg Message to log. 101 | * @param objects Objects to format in. 102 | */ 103 | public static void globalDebug(String msg, Object... objects) 104 | { 105 | if (isGlobalDebugEnabled()) 106 | System.out.println("[Debug] " + FormatUtil.format(msg, objects)); 107 | } 108 | 109 | /** 110 | * @return true if the system property swornapi.debug is true 111 | */ 112 | public static boolean isGlobalDebugEnabled() 113 | { 114 | return Boolean.getBoolean("swornapi.debug"); 115 | } 116 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/handlers/PermissionHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.handlers; 19 | 20 | import net.dmulloy2.swornapi.SwornPlugin; 21 | import net.dmulloy2.swornapi.types.IPermission; 22 | 23 | import org.bukkit.command.CommandSender; 24 | import org.bukkit.entity.Player; 25 | 26 | /** 27 | * Handles permissions. 28 | * 29 | * @author dmulloy2 30 | */ 31 | 32 | public class PermissionHandler 33 | { 34 | private final String prefix; 35 | public PermissionHandler(String prefix) 36 | { 37 | this.prefix = prefix.toLowerCase() + "."; 38 | } 39 | 40 | public PermissionHandler(SwornPlugin plugin) 41 | { 42 | this(plugin.getName()); 43 | } 44 | 45 | /** 46 | * Whether or not a {@link CommandSender} has a permission. 47 | * 48 | * @param sender Sender to check. 49 | * @param permission Permission. 50 | * @return True if they have the permission, false if not 51 | */ 52 | public final boolean hasPermission(CommandSender sender, IPermission permission) 53 | { 54 | return permission == null || hasPermission(sender, getPermissionString(permission)); 55 | } 56 | 57 | /** 58 | * Whether or not a {@link CommandSender} has a permission. 59 | * 60 | * @param sender Sender to check. 61 | * @param permission Permission. 62 | * @return True if they have the permission, false if not 63 | */ 64 | public final boolean hasPermission(CommandSender sender, String permission) 65 | { 66 | if (sender instanceof Player player) 67 | { 68 | return player.hasPermission(permission) || player.isOp(); 69 | } 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * Gets the complete permission string for a given {@link IPermission}. 76 | * 77 | * @param permission - Permission to get the node for. 78 | * @return The complete permission string 79 | */ 80 | public final String getPermissionString(IPermission permission) 81 | { 82 | return prefix + permission.getNode().toLowerCase(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/handlers/ResourceHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.handlers; 19 | 20 | import java.util.Locale; 21 | import java.util.MissingResourceException; 22 | import java.util.ResourceBundle; 23 | import java.util.logging.Level; 24 | 25 | import net.dmulloy2.swornapi.SwornPlugin; 26 | import net.dmulloy2.swornapi.io.FileResourceLoader; 27 | 28 | /** 29 | * @author dmulloy2 30 | */ 31 | 32 | public class ResourceHandler 33 | { 34 | private Locale locale; 35 | private ResourceBundle messages; 36 | 37 | private final SwornPlugin plugin; 38 | public ResourceHandler(SwornPlugin plugin) 39 | { 40 | this(plugin, plugin.classLoader()); 41 | } 42 | 43 | public ResourceHandler(SwornPlugin plugin, ClassLoader classLoader) 44 | { 45 | this.plugin = plugin; 46 | 47 | try 48 | { 49 | if (plugin.getConfig().isSet("locale")) 50 | locale = Locale.forLanguageTag(plugin.getConfig().getString("locale")); 51 | if (locale == null) 52 | locale = Locale.getDefault(); 53 | 54 | messages = ResourceBundle.getBundle("messages", locale, new FileResourceLoader(classLoader, plugin)); 55 | } 56 | catch (MissingResourceException ex) 57 | { 58 | plugin.getLogHandler().log(Level.SEVERE, "Could not find resource bundle: {0}", ex.getKey()); 59 | } 60 | } 61 | 62 | private boolean bundleWarning; 63 | 64 | /** 65 | * Gets a message from the message file with a given key. 66 | * 67 | * @param key Message key 68 | * @return The message 69 | */ 70 | public final String getMessage(String key) 71 | { 72 | if (messages == null) 73 | { 74 | if (! bundleWarning) 75 | { 76 | plugin.getLogHandler().log(Level.WARNING, "Messages bundle is missing!"); 77 | bundleWarning = true; 78 | } 79 | 80 | return ""; 81 | } 82 | 83 | try 84 | { 85 | return messages.getString(key); 86 | } 87 | catch (Throwable ex) 88 | { 89 | plugin.getLogHandler().log(Level.WARNING, "Message for key \"{0}\" is missing!", key); 90 | return ""; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/integration/DependencyProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.integration; 19 | 20 | import java.util.logging.Level; 21 | 22 | import net.dmulloy2.swornapi.SwornPlugin; 23 | import net.dmulloy2.swornapi.util.Util; 24 | 25 | import org.bukkit.event.EventHandler; 26 | import org.bukkit.event.Listener; 27 | import org.bukkit.event.server.PluginDisableEvent; 28 | import org.bukkit.event.server.PluginEnableEvent; 29 | import org.bukkit.plugin.Plugin; 30 | 31 | import static com.google.common.base.Preconditions.checkNotNull; 32 | 33 | /** 34 | * A dependency provider for optional {@link Plugin} dependencies. 35 | *

36 | * In order to avoid a hard dependency, the following precautions should be taken:
37 | *

    38 | *
  • Initialization of Objects of this Class should be wrapped in a try-catch block.
  • 39 | *
  • Methods in this class should return Objects that will definitely exist at runtime.
  • 40 | *
      41 | *
    • Like Bukkit objects, Strings, and Java primitives.
    • 42 | *
    43 | *
  • Before calling methods from this class, {@link #isEnabled()} should be called.
  • 44 | *
45 | * 46 | * @author dmulloy2 47 | */ 48 | 49 | public class DependencyProvider 50 | { 51 | 52 | protected T dependency; 53 | protected boolean enabled; 54 | 55 | private final int minVersion; 56 | protected final String name; 57 | protected final SwornPlugin handler; 58 | 59 | public DependencyProvider(final SwornPlugin handler, final String name) 60 | { 61 | this(handler, name, new int[0]); 62 | } 63 | 64 | public DependencyProvider(final SwornPlugin handler, final String name, int... minVersion) 65 | { 66 | this.handler = checkNotNull(handler, "handler cannot be null!"); 67 | this.name = checkNotNull(name, "name cannot be null!"); 68 | this.minVersion = condense(minVersion); 69 | 70 | handler.getServer().getPluginManager().registerEvents(new Listener() 71 | { 72 | @EventHandler 73 | public void onPluginEnable(PluginEnableEvent event) 74 | { 75 | if (dependency == null && event.getPlugin().getName().equals(name)) 76 | { 77 | enable(); 78 | } 79 | } 80 | 81 | @EventHandler 82 | public void onPluginDisable(PluginDisableEvent event) 83 | { 84 | if (dependency != null && event.getPlugin().getName().equals(name)) 85 | { 86 | disable(); 87 | handler.getLogHandler().log("{0} integration disabled.", name); 88 | } 89 | } 90 | }, handler); 91 | 92 | enable(); 93 | } 94 | 95 | @SuppressWarnings("unchecked") 96 | protected void enable() 97 | { 98 | if (dependency != null) 99 | { 100 | return; 101 | } 102 | 103 | try 104 | { 105 | dependency = (T) handler.getServer().getPluginManager().getPlugin(name); 106 | if (dependency != null && versionCheck()) 107 | { 108 | enabled = true; 109 | onEnable(); 110 | handler.getLogHandler().log("{0} integration successful.", name); 111 | } 112 | } 113 | catch (Throwable ex) 114 | { 115 | handler.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "hooking into " + name)); 116 | } 117 | } 118 | 119 | protected void disable() 120 | { 121 | onDisable(); 122 | enabled = false; 123 | dependency = null; 124 | } 125 | 126 | /** 127 | * Called when the dependency is found or enabled. 128 | */ 129 | public void onEnable() { } 130 | 131 | /** 132 | * Called when the dependency is disabled. 133 | */ 134 | public void onDisable() { } 135 | 136 | /** 137 | * Gets the dependency. 138 | * 139 | * @return The dependency 140 | * @throws NullPointerException if the dependency does not exist. 141 | */ 142 | public T getDependency() 143 | { 144 | return checkNotNull(dependency, name + " dependency does not exist."); 145 | } 146 | 147 | /** 148 | * Gets this dependency's name. 149 | * 150 | * @return The dependency's name 151 | */ 152 | public String getName() 153 | { 154 | return name; 155 | } 156 | 157 | /** 158 | * Whether or not this dependency is enabled. 159 | * 160 | * @return True if enabled, false if not 161 | */ 162 | public boolean isEnabled() 163 | { 164 | return enabled && dependency != null; 165 | } 166 | 167 | // ---- Version Checking 168 | 169 | private boolean versionCheck() 170 | { 171 | if (dependency != null) 172 | { 173 | String version = dependency.getDescription().getVersion(); 174 | if (version.contains("-")) 175 | { 176 | version = version.split("-")[0]; 177 | } 178 | 179 | int condensed = condense(version); 180 | return condensed >= minVersion; 181 | } 182 | 183 | return false; 184 | } 185 | 186 | private int condense(String version) 187 | { 188 | // assume that they will all (at least roughly) follow semver 189 | int major, minor = 0, patch = 0; 190 | 191 | String[] split = version.split("\\."); 192 | major = Integer.parseInt(split[0]); 193 | 194 | if (split.length > 1) 195 | { 196 | minor = Integer.parseInt(split[1]); 197 | } 198 | 199 | if (split.length > 2) 200 | { 201 | patch = Integer.parseInt(split[2]); 202 | } 203 | 204 | return condense(major, minor, patch); 205 | } 206 | 207 | private int condense(int... numbers) 208 | { 209 | int major = numbers.length > 0 ? numbers[0] : 0; 210 | int minor = numbers.length > 1 ? numbers[1] : 0; 211 | int patch = numbers.length > 2 ? numbers[2] : 0; 212 | 213 | return (10000 * major) + (100 * minor) + patch; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/integration/TypelessProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.integration; 19 | 20 | import static com.google.common.base.Preconditions.checkNotNull; 21 | 22 | import java.util.logging.Level; 23 | 24 | import org.bukkit.event.EventHandler; 25 | import org.bukkit.event.Listener; 26 | import org.bukkit.event.server.PluginDisableEvent; 27 | import org.bukkit.event.server.PluginEnableEvent; 28 | import org.bukkit.plugin.Plugin; 29 | 30 | import net.dmulloy2.swornapi.SwornPlugin; 31 | import net.dmulloy2.swornapi.util.Util; 32 | 33 | /** 34 | * A dependency provider for optional {@link Plugin} dependencies that only checks for the existence of a plugin. 35 | * This provider doesn't provide the Plugin object. 36 | *

37 | * In order to avoid a hard dependency, the following precautions should be taken:
38 | *

    39 | *
  • Initialization of Objects of this Class should be wrapped in a try-catch block.
  • 40 | *
  • Methods in this class should return Objects that will definitely exist at runtime.
  • 41 | *
      42 | *
    • Like Bukkit objects, Strings, and Java primitives.
    • 43 | *
    44 | *
  • Before calling methods from this class, {@link #isEnabled()} should be called.
  • 45 | *
46 | * 47 | * @author dmulloy2 48 | */ 49 | 50 | public class TypelessProvider 51 | { 52 | protected String name; 53 | protected boolean enabled; 54 | 55 | protected final SwornPlugin handler; 56 | 57 | public TypelessProvider(final SwornPlugin handler, final String name) 58 | { 59 | this.handler = checkNotNull(handler, "handler cannot be null!"); 60 | this.name = checkNotNull(name, "name cannot be null!"); 61 | 62 | if (handler.getServer().getPluginManager().isPluginEnabled(name)) 63 | { 64 | enabled = true; 65 | onEnable(); 66 | handler.getLogHandler().log("{0} integration successful.", name); 67 | } 68 | 69 | handler.getServer().getPluginManager().registerEvents(new Listener() 70 | { 71 | @EventHandler 72 | public void onPluginEnable(PluginEnableEvent event) 73 | { 74 | if (! enabled && event.getPlugin().getName().equals(name)) 75 | { 76 | try 77 | { 78 | enabled = true; 79 | onEnable(); 80 | handler.getLogHandler().log("{0} integration enabled.", name); 81 | } 82 | catch (Throwable ex) 83 | { 84 | handler.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "hooking into " + name)); 85 | } 86 | } 87 | } 88 | 89 | @EventHandler 90 | public void onPluginDisable(PluginDisableEvent event) 91 | { 92 | if (enabled && event.getPlugin().getName().equals(name)) 93 | { 94 | onDisable(); 95 | enabled = false; 96 | handler.getLogHandler().log("{0} integration disabled.", name); 97 | } 98 | } 99 | 100 | }, handler); 101 | } 102 | 103 | /** 104 | * Called when the dependency is found or enabled. 105 | */ 106 | public void onEnable() { } 107 | 108 | /** 109 | * Called when the dependency is disabled. 110 | */ 111 | public void onDisable() { } 112 | 113 | /** 114 | * Gets this dependency's name. 115 | * 116 | * @return The dependency's name 117 | */ 118 | public String getName() 119 | { 120 | return name; 121 | } 122 | 123 | /** 124 | * Whether or not this dependency is enabled. 125 | * 126 | * @return True if enabled, false if not 127 | */ 128 | public boolean isEnabled() 129 | { 130 | return enabled; 131 | } 132 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/io/Closer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.io; 19 | 20 | import java.io.Closeable; 21 | import java.util.ArrayList; 22 | import java.util.Iterator; 23 | import java.util.List; 24 | 25 | import org.apache.commons.lang.Validate; 26 | 27 | /** 28 | * Automatically closes a collection of closeable objects. 29 | * 30 | * @author dmulloy2 31 | */ 32 | 33 | public class Closer implements Closeable 34 | { 35 | private final List list = new ArrayList<>(); 36 | 37 | /** 38 | * Registers a closeable object. 39 | * 40 | * @param closeable Object to register 41 | * @return The object 42 | */ 43 | public final C register(C closeable) 44 | { 45 | Validate.notNull(closeable, "closeable cannot be null!"); 46 | 47 | list.add(closeable); 48 | return closeable; 49 | } 50 | 51 | @Override 52 | public final void close() 53 | { 54 | if (list.isEmpty()) 55 | return; 56 | 57 | Iterator iter = list.iterator(); 58 | while (iter.hasNext()) 59 | { 60 | closeQuietly(iter.next()); 61 | iter.remove(); 62 | } 63 | } 64 | 65 | /** 66 | * Quietly closes a closeable object, ignoring all exceptions. 67 | * 68 | * @param closeable Object to close 69 | */ 70 | public static void closeQuietly(AutoCloseable closeable) 71 | { 72 | try 73 | { 74 | if (closeable != null) 75 | closeable.close(); 76 | } catch (Throwable ignored) { } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/io/FileResourceLoader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.io; 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.InputStream; 23 | import java.net.URL; 24 | 25 | import org.bukkit.plugin.java.JavaPlugin; 26 | 27 | /** 28 | * @author dmulloy2 29 | */ 30 | 31 | public class FileResourceLoader extends ClassLoader 32 | { 33 | private transient final File dataFolder; 34 | public FileResourceLoader(ClassLoader classLoader, JavaPlugin plugin) 35 | { 36 | super(classLoader); 37 | this.dataFolder = plugin.getDataFolder(); 38 | } 39 | 40 | @Override 41 | public URL getResource(String string) 42 | { 43 | File file = new File(dataFolder, string); 44 | if (file.exists()) 45 | { 46 | try 47 | { 48 | return file.toURI().toURL(); 49 | } catch (Throwable ignored) { } 50 | } 51 | 52 | return super.getResource(string); 53 | } 54 | 55 | @Override 56 | public InputStream getResourceAsStream(String string) 57 | { 58 | File file = new File(dataFolder, string); 59 | if (file.exists()) 60 | { 61 | try 62 | { 63 | return new FileInputStream(file); 64 | } catch (Throwable ignored) { } 65 | } 66 | 67 | return super.getResourceAsStream(string); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/io/FileSerialization.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.io; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.lang.invoke.MethodHandle; 23 | import java.lang.invoke.MethodHandles; 24 | import java.lang.invoke.MethodType; 25 | import java.lang.reflect.Field; 26 | import java.lang.reflect.Modifier; 27 | import java.util.*; 28 | import java.util.Map.Entry; 29 | import java.util.concurrent.ConcurrentHashMap; 30 | import java.util.concurrent.ConcurrentMap; 31 | 32 | import net.dmulloy2.swornapi.handlers.LogHandler; 33 | import net.dmulloy2.swornapi.util.Util; 34 | import org.apache.commons.lang.Validate; 35 | import org.bukkit.configuration.InvalidConfigurationException; 36 | import org.bukkit.configuration.file.YamlConfiguration; 37 | import org.bukkit.configuration.serialization.ConfigurationSerializable; 38 | import org.bukkit.configuration.serialization.ConfigurationSerialization; 39 | 40 | /** 41 | * Utility methods for serializing and deserializing Objects with YAML. 42 | * @author dmulloy2 43 | */ 44 | 45 | public class FileSerialization 46 | { 47 | /** 48 | * Loads a previously serialized object from a given file using YAML. 49 | * 50 | * @param file File to load from 51 | * @param clazz Class the object should be of 52 | * @param exists Whether or not the file exists and the expensive 53 | * {@link File#exists()} operation can be skipped 54 | * @return The deserialized object, or null if the file does not exist 55 | * @throws IllegalArgumentException If the file or class is null 56 | * @throws IOException If the file cannot be read 57 | * @throws InvalidConfigurationException If the given file is not a valid 58 | * YAML configuration 59 | * @see #save(ConfigurationSerializable, File) 60 | */ 61 | @SuppressWarnings("unchecked") 62 | public static T load(File file, Class clazz, boolean exists) throws IOException, InvalidConfigurationException 63 | { 64 | Validate.notNull(file, "file cannot be null!"); 65 | Validate.notNull(clazz, "clazz cannot be null!"); 66 | 67 | if (! exists && ! file.exists()) 68 | return null; 69 | 70 | YamlConfiguration config = new YamlConfiguration(); 71 | config.load(file); 72 | 73 | Map map = config.getValues(true); 74 | return (T) ConfigurationSerialization.deserializeObject(map, clazz); 75 | } 76 | 77 | /** 78 | * Loads a previously serialized object from a given file using YAML. Alias 79 | * for {@link #load(File, Class, boolean)}, exists defaults to false. 80 | * 81 | * @see #save(ConfigurationSerializable, File) 82 | */ 83 | public static T load(File file, Class clazz) throws IOException, InvalidConfigurationException 84 | { 85 | return load(file, clazz, false); 86 | } 87 | 88 | /** 89 | * Saves a serializable object to a given file. 90 | * 91 | * @param instance Object to seriaize 92 | * @param file File to save to 93 | * @throws IllegalArgumentException If the instance or file is null 94 | * @throws IOException If the file cannot be written to 95 | * @see #load(File, Class, boolean) 96 | */ 97 | public static void save(ConfigurationSerializable instance, File file) throws IOException 98 | { 99 | Validate.notNull(instance, "instance cannot be null!"); 100 | Validate.notNull(file, "file cannot be null!"); 101 | 102 | file.delete(); 103 | file.createNewFile(); 104 | 105 | YamlConfiguration config = new YamlConfiguration(); 106 | 107 | for (Entry entry : instance.serialize().entrySet()) 108 | { 109 | config.set(entry.getKey(), entry.getValue()); 110 | } 111 | 112 | config.save(file); 113 | } 114 | 115 | private static final ConcurrentMap> SERIALIZE_CACHE = new ConcurrentHashMap<>(); 116 | 117 | /** 118 | * Serializes all of an object's fields into a Map. This method ignores 119 | * transient, null, zero, and empty fields. 120 | * 121 | * @param object Object to serialize 122 | * @return The map 123 | */ 124 | public static Map serialize(Object object) 125 | { 126 | Map data = new LinkedHashMap<>(); 127 | 128 | for (Field field : object.getClass().getDeclaredFields()) 129 | { 130 | try 131 | { 132 | if (Modifier.isTransient(field.getModifiers())) 133 | continue; 134 | 135 | field.setAccessible(true); 136 | 137 | if (field.getType().equals(Integer.TYPE)) 138 | { 139 | if (field.getInt(object) != 0) 140 | data.put(field.getName(), field.getInt(object)); 141 | } 142 | else if (field.getType().equals(Long.TYPE)) 143 | { 144 | if (field.getLong(object) != 0) 145 | data.put(field.getName(), field.getLong(object)); 146 | } 147 | else if (field.getType().equals(Boolean.TYPE)) 148 | { 149 | if (field.getBoolean(object)) 150 | data.put(field.getName(), field.getBoolean(object)); 151 | } 152 | else if (field.getType().isAssignableFrom(Collection.class)) 153 | { 154 | if (! ((Collection) field.get(object)).isEmpty()) 155 | data.put(field.getName(), field.get(object)); 156 | } 157 | else if (field.getType().isAssignableFrom(String.class)) 158 | { 159 | if (field.get(object) != null) 160 | data.put(field.getName(), field.get(object)); 161 | } 162 | else if (field.getType().isAssignableFrom(Map.class)) 163 | { 164 | if (! ((Map) field.get(object)).isEmpty()) 165 | data.put(field.getName(), field.get(object)); 166 | } 167 | else if (field.getType().isEnum()) 168 | { 169 | data.put(field.getName(), ((Enum) field.get(object)).name().toLowerCase()); 170 | } 171 | else if (field.get(object) != null) 172 | { 173 | String className = field.getType().getName(); 174 | if (!SERIALIZE_CACHE.containsKey(className)) 175 | { 176 | try 177 | { 178 | MethodType methodType = MethodType.methodType(Object.class); 179 | MethodHandle serialHandle = MethodHandles.publicLookup().findVirtual(field.getType(), "serialize", methodType); 180 | SERIALIZE_CACHE.put(className, Optional.of(serialHandle)); 181 | } 182 | catch (NoSuchMethodException ex) 183 | { 184 | SERIALIZE_CACHE.put(className, Optional.empty()); 185 | } 186 | } 187 | 188 | Optional serialHandle = SERIALIZE_CACHE.get(className); 189 | if (serialHandle.isPresent()) 190 | { 191 | data.put(field.getName(), serialHandle.get().invoke(field.get(object))); 192 | } 193 | else 194 | { 195 | data.put(field.getName(), field.get(object)); 196 | } 197 | } 198 | } 199 | catch (Throwable ex) 200 | { 201 | if (LogHandler.isGlobalDebugEnabled()) 202 | LogHandler.globalDebug(Util.getUsefulStack(ex, "serializing field {0} of {1}", 203 | field.getName(), object)); 204 | } 205 | } 206 | 207 | return data; 208 | } 209 | 210 | private static final ConcurrentMap> DESERIALIZE_CACHE = new ConcurrentHashMap<>(); 211 | 212 | @SuppressWarnings("unchecked") 213 | public static void deserialize(Object object, Map data) 214 | { 215 | for (Entry entry : data.entrySet()) 216 | { 217 | String fieldName = entry.getKey(); 218 | Object fieldData = entry.getValue(); 219 | 220 | try 221 | { 222 | Field field = object.getClass().getDeclaredField(fieldName); 223 | if (Modifier.isTransient(field.getModifiers())) 224 | continue; 225 | 226 | field.setAccessible(true); 227 | 228 | Class fieldType = field.getType(); 229 | if (fieldType.isPrimitive()) 230 | { 231 | field.set(object, fieldData); 232 | } 233 | else if (fieldType.isEnum()) 234 | { 235 | Class> enumType = (Class>) fieldType; 236 | String name = fieldData.toString(); 237 | Object enumValue = Arrays.stream(enumType.getEnumConstants()) 238 | .filter(e -> e.name().equalsIgnoreCase(name)).findFirst().orElseThrow(); 239 | field.set(object, enumValue); 240 | } 241 | else 242 | { 243 | String className = fieldType.getName(); 244 | if (!DESERIALIZE_CACHE.containsKey(className)) 245 | { 246 | try 247 | { 248 | MethodType methodType = MethodType.methodType(fieldType, Object.class); 249 | MethodHandle serialHandle = MethodHandles.publicLookup().findStatic(field.getType(), "deserialize", methodType); 250 | DESERIALIZE_CACHE.put(className, Optional.of(serialHandle)); 251 | } 252 | catch (NoSuchMethodException ex) 253 | { 254 | DESERIALIZE_CACHE.put(className, Optional.empty()); 255 | } 256 | } 257 | 258 | Optional deserialize = DESERIALIZE_CACHE.get(className); 259 | if (deserialize.isPresent()) 260 | { 261 | field.set(object, deserialize.get().invoke(fieldData)); 262 | } 263 | else 264 | { 265 | field.set(object, fieldData); 266 | } 267 | } 268 | } 269 | catch (NoSuchFieldException ignored) { } 270 | catch (Throwable ex) 271 | { 272 | if (LogHandler.isGlobalDebugEnabled()) 273 | LogHandler.globalDebug(Util.getUsefulStack(ex, "deserializing field {0} of {1}", 274 | fieldName, object)); 275 | } 276 | } 277 | } 278 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/io/IOUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.io; 19 | 20 | import java.io.BufferedReader; 21 | import java.io.DataInputStream; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.FileWriter; 25 | import java.io.IOException; 26 | import java.io.InputStreamReader; 27 | import java.io.PrintWriter; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | import org.apache.commons.lang.Validate; 32 | 33 | /** 34 | * Util for dealing with IO stuff 35 | * 36 | * @author dmulloy2 37 | */ 38 | 39 | public class IOUtil 40 | { 41 | private IOUtil() { } 42 | 43 | /** 44 | * Parses the lines of a given file in the proper order. 45 | * 46 | * @param file File to parse 47 | * @return The lines 48 | * @throws IOException If parsing fails 49 | */ 50 | public static List readLines(File file) throws IOException 51 | { 52 | Validate.notNull(file, "file cannot be null!"); 53 | 54 | try (Closer closer = new Closer()) 55 | { 56 | FileInputStream fis = closer.register(new FileInputStream(file)); 57 | DataInputStream dis = closer.register(new DataInputStream(fis)); 58 | InputStreamReader isr = closer.register(new InputStreamReader(dis)); 59 | BufferedReader br = closer.register(new BufferedReader(isr)); 60 | 61 | List lines = new ArrayList<>(); 62 | 63 | String line; 64 | while ((line = br.readLine()) != null) 65 | lines.add(line); 66 | 67 | return lines; 68 | } 69 | } 70 | 71 | /** 72 | * Writes given lines to a given file in the proper order. 73 | * 74 | * @param file File to write to 75 | * @param lines Lines to write 76 | * @throws IOException If writing fails 77 | */ 78 | public static void writeLines(File file, List lines) throws IOException 79 | { 80 | Validate.notNull(file, "file cannot be null!"); 81 | Validate.notNull(lines, "lines cannot be null!"); 82 | 83 | try (Closer closer = new Closer()) 84 | { 85 | FileWriter fw = closer.register(new FileWriter(file)); 86 | PrintWriter pw = closer.register(new PrintWriter(fw)); 87 | 88 | for (String line : lines) 89 | pw.println(line); 90 | } 91 | } 92 | 93 | /** 94 | * Returns the given {@link File}'s name with the extension omitted. 95 | * 96 | * @param file {@link File} 97 | * @param extension File extension 98 | * @return The file's name with the extension omitted 99 | */ 100 | public static String trimFileExtension(File file, String extension) 101 | { 102 | Validate.notNull(file, "file cannot be null!"); 103 | Validate.notNull(extension, "extension cannot be null!"); 104 | 105 | int index = file.getName().lastIndexOf(extension); 106 | return index > 0 ? file.getName().substring(0, index) : file.getName(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/ChatPosition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import lombok.Getter; 21 | 22 | /** 23 | * Represents the currently supported chat positions. 24 | * @author dmulloy2 25 | */ 26 | 27 | @Getter 28 | public enum ChatPosition 29 | { 30 | /** 31 | * Player chat (in chat box) 32 | */ 33 | CHAT(0), 34 | 35 | /** 36 | * System messages (in chat box) 37 | */ 38 | SYSTEM(1), 39 | 40 | /** 41 | * Action bar (above hotbar) 42 | */ 43 | ACTION_BAR(2), 44 | ; 45 | 46 | private final byte value; 47 | 48 | ChatPosition(int value) 49 | { 50 | this.value = (byte) value; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/CommandVisibility.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | /** 21 | * Represents various visibilities for commands 22 | * 23 | * @author dmulloy2 24 | */ 25 | 26 | public enum CommandVisibility 27 | { 28 | /** 29 | * Visible to everyone 30 | */ 31 | ALL, 32 | 33 | /** 34 | * Visible to players with a permission 35 | */ 36 | PERMISSION, 37 | 38 | /** 39 | * Visible to operators 40 | */ 41 | OPS, 42 | 43 | /** 44 | * Invisible 45 | */ 46 | NONE 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/CustomSkullType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * This file incorporates work covered by the following copyright and 19 | * permission notice: 20 | * 21 | * This Source Code Form is subject to the terms of the Mozilla Public 22 | * License, v. 2.0. If a copy of the MPL was not distributed with this 23 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 24 | * 25 | * Copyright (c) 2015, MPL meiskam 26 | */ 27 | package net.dmulloy2.swornapi.types; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | import lombok.Getter; 33 | 34 | /** 35 | * Represents a skull type not included in Spigot/Minecraft. 36 | * @author meiskam 37 | */ 38 | 39 | @Getter 40 | public enum CustomSkullType 41 | { 42 | SPIDER("MHF_Spider", "Kelevra_V"), // Thanks Marc Watson 43 | ENDERMAN("MHF_Enderman", "Violit"), // Thanks Marc Watson 44 | BLAZE("MHF_Blaze", "Blaze_Head"), // Thanks Marc Watson 45 | HORSE("gavertoso"), // Thanks Glompalici0us 46 | SQUID("MHF_Squid", "squidette8"), // Thanks Marc Watson 47 | SILVERFISH("Xzomag", "AlexVMiner"), // Thanks XlexerX 48 | ENDER_DRAGON("KingEndermen", "KingEnderman"), // Thanks SethBling 49 | SLIME("HappyHappyMan", "Ex_PS3Zocker"), // Thanks SethBling 50 | IRON_GOLEM("MHF_Golem", "zippie007"), // Thanks Marc Watson 51 | MUSHROOM_COW("MHF_MushroomCow", "Mooshroom_Stew"), // Thanks Marc Watson 52 | BAT("bozzobrain", "coolwhip101"), // Thanks incraftion.com 53 | PIG_ZOMBIE("MHF_PigZombie", "ManBearPigZombie", "scraftbrothers5"), // Thanks Marc Watson 54 | SNOWMAN("Koebasti", "scraftbrothers2"), // Thanks MrLeikermoser 55 | GHAST("MHF_Ghast", "_QuBra_", "blaiden"), // Thanks Marc Watson 56 | PIG("MHF_Pig", "XlexerX", "scrafbrothers7"), // Thanks Marc Watson 57 | VILLAGER("MHF_Villager", "Kuvase", "Villager", "scraftbrothers9"), // Thanks Marc Watson 58 | SHEEP("MHF_Sheep", "SGT_KICYORASS", "Eagle_Peak"), // Thanks Marc Watson 59 | COW("MHF_Cow", "VerifiedBernard", "CarlosTheCow"), // Thanks Marc Watson 60 | CHICKEN("MHF_Chicken", "scraftbrothers1"), // Thanks Marc Watson 61 | OCELOT("MHF_Ocelot", "scraftbrothers3"), // Thanks Marc Watson 62 | WITCH("scrafbrothers4"), // Thanks SuperCraftBrothers.com 63 | MAGMA_CUBE("MHF_LavaSlime"), // Thanks Marc Watson 64 | WOLF("Pablo_Penguin", "Budwolf"), // I still need an official wolf head if anyone wants to provide one 65 | CAVE_SPIDER("MHF_CaveSpider"), // Thanks Marc Watson 66 | RABBIT("rabbit2077"), // Thanks IrParadox 67 | GUARDIAN("Guardian", "creepypig7", "Creepypig7"); // Thanks lee3kfc 68 | 69 | private final String owner; 70 | private final String[] toConvert; 71 | 72 | CustomSkullType(String owner, String... toConvert) 73 | { 74 | this.owner = owner; 75 | this.toConvert = toConvert; 76 | } 77 | 78 | private static final Map MAP; 79 | 80 | static 81 | { 82 | MAP = new HashMap<>(); 83 | 84 | for (CustomSkullType type : values()) 85 | { 86 | MAP.put(type.name().toLowerCase(), type); 87 | MAP.put(type.getOwner().toLowerCase(), type); 88 | for (String owner : type.getToConvert()) 89 | { 90 | MAP.put(owner.toLowerCase(), type); 91 | } 92 | } 93 | } 94 | 95 | /** 96 | * Get the CustomSkullType associated with a given key. 97 | * @param key Mob type, owner, etc. 98 | * @return The CustomSkullType, or null if not found 99 | */ 100 | public static CustomSkullType get(String key) 101 | { 102 | return MAP.get(key.toLowerCase()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/EnchantmentType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import java.util.Map; 21 | import java.util.Map.Entry; 22 | 23 | import net.dmulloy2.swornapi.util.FormatUtil; 24 | 25 | import lombok.Getter; 26 | 27 | import org.bukkit.enchantments.Enchantment; 28 | 29 | /** 30 | * Represents various enchantments with friendlier configuration and display names. 31 | * @author dmulloy2 32 | */ 33 | @Getter 34 | public enum EnchantmentType 35 | { 36 | ARROW_DAMAGE("Power", "arrowdmg"), 37 | ARROW_FIRE("Flame", "fire"), 38 | ARROW_INFINITE("Infinity", "inf"), 39 | ARROW_KNOCKBACK("Punch", "arrowkb"), 40 | BINDING_CURSE("Curse of Bind", "bind", "binding"), 41 | DAMAGE_ALL("Sharpness", "sharp"), 42 | DAMAGE_ARTHROPODS("Bane of Arthropods", "bane"), 43 | DAMAGE_UNDEAD("Smite"), 44 | DEPTH_STRIDER("Depth Strider", "depthstrider", "depth"), 45 | DIG_SPEED("Efficiency", "eff"), 46 | DURABILITY("Durability", "dura"), 47 | FIRE_ASPECT("Fire Aspect", "fireaspect"), 48 | FROST_WALKER("Frost Walker", "frostwalker"), 49 | KNOCKBACK("Knockback"), 50 | LOOT_BONUS_BLOCKS("Fortune"), 51 | LOOT_BONUS_MOBS("Looting"), 52 | LUCK("Luck"), 53 | LOOT("Loot"), 54 | LURE("Lure"), 55 | MENDING("Mending", "mend"), 56 | OXYGEN("Respiration", "breathing"), 57 | PROTECTION_ENVIRONMENTAL("Protection", "prot"), 58 | PROTECTION_EXPLOSIONS("Blast Protection", "blast"), 59 | PROTECTION_FALL("Feather Falling", "feather"), 60 | PROTECTION_FIRE("Fire Protection", "fireprot"), 61 | PROTECTION_PROJECTILE("Projectile Protection", "proj"), 62 | SILK_TOUCH("Silk Touch", "silk"), 63 | SWEEPING_EDGE("Sweeping Edge", "sweep"), 64 | THORNS("Thorns"), 65 | VANISHING_CURSE("Vanishing Curse", "vanish"), 66 | WATER_WORKER("Aqua Affinity", "aqua", "affinity"); 67 | 68 | private final String name; 69 | private final String[] aliases; 70 | 71 | EnchantmentType(String name, String... aliases) 72 | { 73 | this.name = name; 74 | this.aliases = aliases; 75 | } 76 | 77 | /** 78 | * Returns a friendlier name of a given {@link Enchantment}. 79 | * 80 | * @param enchant {@link Enchantment} 81 | * @return Friendlier name. 82 | */ 83 | public static String toName(Enchantment enchant) 84 | { 85 | EnchantmentType type = getByName(enchant.getName()); 86 | if (type != null) 87 | return type.getName(); 88 | 89 | return FormatUtil.getFriendlyName(enchant); 90 | } 91 | 92 | /** 93 | * Attempts to get an {@link Enchantment} from a given string. 94 | * 95 | * @param enchant Enchantment name 96 | * @return The enchantment, or null if none exists. 97 | */ 98 | public static Enchantment toEnchantment(String enchant) 99 | { 100 | enchant = enchant.replaceAll(" ", "_"); 101 | enchant = enchant.toUpperCase(); 102 | 103 | EnchantmentType type = getByName(enchant); 104 | if (type != null) 105 | return Enchantment.getByName(type.name()); 106 | 107 | return Enchantment.getByName(enchant); 108 | } 109 | 110 | /** 111 | * Returns a String representation of a {@link Map} of 112 | * enchantments. 113 | * 114 | * @param enchantments Enchantment map 115 | */ 116 | public static String toString(Map enchantments) 117 | { 118 | StringJoiner joiner = new StringJoiner(", "); 119 | for (Entry entry : enchantments.entrySet()) 120 | { 121 | joiner.append(EnchantmentType.toName(entry.getKey()) + ":" + entry.getValue()); 122 | } 123 | 124 | return joiner.toString(); 125 | } 126 | 127 | // ---- Utility Methods 128 | 129 | private static EnchantmentType getByName(String name) 130 | { 131 | for (EnchantmentType type : values()) 132 | { 133 | if (type.getName().equalsIgnoreCase(name) 134 | || type.name().equalsIgnoreCase(name) 135 | || containsIgnoreCase(name, type.getAliases())) 136 | return type; 137 | } 138 | 139 | return null; 140 | } 141 | 142 | private static boolean containsIgnoreCase(String lookup, String[] array) 143 | { 144 | for (String string : array) 145 | { 146 | if (string.equalsIgnoreCase(lookup)) 147 | return true; 148 | } 149 | 150 | return false; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/IPermission.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | /** 21 | * Represents a permission that is compatible with the PermissionHandler. 22 | * 23 | * @author dmulloy2 24 | */ 25 | 26 | public interface IPermission 27 | { 28 | /** 29 | * @return This permission's node 30 | */ 31 | String getNode(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/LazyLocation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import java.util.LinkedHashMap; 21 | import java.util.Map; 22 | import java.util.Objects; 23 | 24 | import lombok.Getter; 25 | import lombok.Setter; 26 | 27 | import org.apache.commons.lang.Validate; 28 | import org.bukkit.Bukkit; 29 | import org.bukkit.Location; 30 | import org.bukkit.World; 31 | import org.bukkit.configuration.serialization.ConfigurationSerializable; 32 | import org.bukkit.configuration.serialization.SerializableAs; 33 | import org.bukkit.entity.Player; 34 | 35 | /** 36 | * This class provides a lazy-load Location, so that World doesn't need to be 37 | * initialized yet when an object of this class is created, only when the 38 | * {@link Location} is first accessed. This class is also serializable and 39 | * can easily be converted into a {@link Location} or {@link SimpleVector} 40 | * 41 | * @author dmulloy2 42 | */ 43 | 44 | @Getter @Setter 45 | @SerializableAs("net.dmulloy2.LazyLocation") 46 | public final class LazyLocation implements ConfigurationSerializable, Cloneable 47 | { 48 | private final int x, y, z; 49 | private final String worldName; 50 | 51 | private transient World world; 52 | private transient Location location; 53 | private transient SimpleVector simpleVector; 54 | 55 | public LazyLocation(String worldName, int x, int y, int z) 56 | { 57 | Validate.notNull(worldName, "worldName cannot be null!"); 58 | this.worldName = worldName; 59 | this.x = x; 60 | this.y = y; 61 | this.z = z; 62 | } 63 | 64 | public LazyLocation(String worldName, int x, int z) 65 | { 66 | this(worldName, x, 0, z); 67 | } 68 | 69 | public LazyLocation(World world, int x, int y, int z) 70 | { 71 | this(world.getName(), x, y, z); 72 | } 73 | 74 | public LazyLocation(String worldName, SimpleVector vector) 75 | { 76 | this(worldName, vector.getX(), vector.getY(), vector.getZ()); 77 | this.simpleVector = vector; 78 | } 79 | 80 | public LazyLocation(Location location) 81 | { 82 | this(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); 83 | this.location = location; 84 | } 85 | 86 | public LazyLocation(Player player) 87 | { 88 | this(player.getLocation()); 89 | } 90 | 91 | public LazyLocation(Map args) 92 | { 93 | Validate.notNull(args, "args cannot be null!"); 94 | this.worldName = (String) args.get("worldName"); 95 | this.x = (int) args.get("x"); 96 | this.y = (int) args.get("y"); 97 | this.z = (int) args.get("z"); 98 | } 99 | 100 | /** 101 | * Returns the {@link World} associated with this 102 | */ 103 | public World getWorld() 104 | { 105 | if (world == null) 106 | world = Bukkit.getWorld(worldName); 107 | 108 | return world; 109 | } 110 | 111 | /** 112 | * Initializes the Location 113 | */ 114 | private void initLocation() 115 | { 116 | // if location is already initialized, simply return 117 | if (location != null) 118 | return; 119 | 120 | // get World; hopefully it's initialized at this point 121 | World world = getWorld(); 122 | if (world == null) 123 | return; 124 | 125 | // store the Location for future calls, and pass it on 126 | location = new Location(world, x, y, z); 127 | } 128 | 129 | /** 130 | * Initializes the SimpleVector 131 | */ 132 | private void initSimpleVector() 133 | { 134 | if (simpleVector != null) 135 | return; 136 | 137 | Location location = getLocation(); 138 | if (location == null) 139 | return; 140 | 141 | simpleVector = new SimpleVector(location); 142 | } 143 | 144 | /** 145 | * Returns the actual {@link Location} 146 | */ 147 | public Location getLocation() 148 | { 149 | initLocation(); 150 | return location; 151 | } 152 | 153 | /** 154 | * Returns a new {@link SimpleVector} based around this 155 | */ 156 | public SimpleVector getSimpleVector() 157 | { 158 | initSimpleVector(); 159 | return simpleVector; 160 | } 161 | 162 | public static LazyLocation getMaximum(LazyLocation l1, LazyLocation l2) 163 | { 164 | return new LazyLocation(l1.worldName, Math.max(l1.x, l2.x), Math.max(l1.y, l2.y), Math.max(l1.z, l2.z)); 165 | } 166 | 167 | public static LazyLocation getMinimum(LazyLocation l1, LazyLocation l2) 168 | { 169 | return new LazyLocation(l1.worldName, Math.min(l1.x, l2.x), Math.min(l1.y, l2.y), Math.min(l1.z, l2.z)); 170 | } 171 | 172 | @Override 173 | public Map serialize() 174 | { 175 | Map result = new LinkedHashMap<>(); 176 | result.put("worldName", worldName); 177 | result.put("x", x); 178 | result.put("y", y); 179 | result.put("z", z); 180 | return result; 181 | } 182 | 183 | @Override 184 | public boolean equals(Object obj) 185 | { 186 | if (obj instanceof LazyLocation that) 187 | { 188 | return x == that.x && y == that.y && z == that.z && worldName.equals(that.worldName); 189 | } 190 | 191 | return false; 192 | } 193 | 194 | @Override 195 | public int hashCode() 196 | { 197 | return Objects.hash(x, y, z, worldName); 198 | } 199 | 200 | @Override 201 | public String toString() 202 | { 203 | return "LastLocation[worldName=" + worldName + ", x=" + x + ", y=" + y + ", z=" + z + "]"; 204 | } 205 | 206 | @Override 207 | public LazyLocation clone() 208 | { 209 | return new LazyLocation(worldName, x, y, z); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/PotionType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import java.util.Collection; 21 | 22 | import net.dmulloy2.swornapi.util.FormatUtil; 23 | 24 | import org.apache.commons.lang.Validate; 25 | import org.bukkit.potion.PotionEffect; 26 | import org.bukkit.potion.PotionEffectType; 27 | 28 | import lombok.Getter; 29 | 30 | /** 31 | * Represents various potion types with friendlier configuration and display names. 32 | * @author dmulloy2 33 | */ 34 | @Getter 35 | public enum PotionType 36 | { 37 | AWKWARD("Awkward"), 38 | FIRE_RESISTANCE("Fire Resistance", "fireres"), 39 | INSTANT_DAMAGE("Harming", "damage"), 40 | INSTANT_HEAL("Healing", "heal"), 41 | INVISIBILITY("Invisibility", "invis"), 42 | JUMP("Leaping", "jump"), 43 | LUCK("Luck", "luck"), 44 | MUNDANE("Mundane"), 45 | NIGHT_VISION("Night Vision", "nvg"), 46 | POISON("Poison"), 47 | REGEN("Regeneration", "regen"), 48 | SLOWNESS("Slowness", "slow"), 49 | SPEED("Swiftness", "swift", "speed"), 50 | STRENGTH("Strength"), 51 | THICK("Thick"), 52 | WATER("Water"), 53 | WATER_BREATHING("Water Breathing", "waterbreath"), 54 | WEAKNESS("Weakness", "weak"); 55 | 56 | private final String name; 57 | private final String[] aliases; 58 | 59 | PotionType(String name, String... aliases) 60 | { 61 | this.name = name; 62 | this.aliases = aliases; 63 | } 64 | 65 | /** 66 | * Gets the Minecraft Potion display name of this type. 67 | * @return The display name 68 | */ 69 | public String getPotionDisplay() 70 | { 71 | return switch (this) { 72 | case AWKWARD, MUNDANE -> name + " Potion"; 73 | case WATER -> name; 74 | default -> "Potion of " + name; 75 | }; 76 | } 77 | 78 | /** 79 | * Gets the Minecraft Effect display name of this type. 80 | * @return The display name 81 | */ 82 | public String getEffectDisplay() 83 | { 84 | return name; 85 | } 86 | 87 | /** 88 | * Gets the Bukkit PotionType equivalent of this PotionType 89 | * @return The Bukkit equivalent 90 | */ 91 | public org.bukkit.potion.PotionType getBukkit() 92 | { 93 | return org.bukkit.potion.PotionType.valueOf(name()); 94 | } 95 | 96 | /** 97 | * Gets the Bukkit PotionEffectType equivalent of this PotionType. 98 | * An equivalent does not exist for every PotionType. 99 | * @return The Bukkit equivalent, or null if it does not exist 100 | */ 101 | public PotionEffectType getEffectType() 102 | { 103 | return getBukkit().getEffectType(); 104 | } 105 | 106 | // ---- Finders 107 | 108 | /** 109 | * Finds the Bukkit PotionType from a given string, falling back to enum names 110 | * if no PotionType exists. 111 | * @param string String to parse 112 | * @return The PotionType, or null if none could be found 113 | */ 114 | public static org.bukkit.potion.PotionType findPotion(String string) 115 | { 116 | PotionType type = find(string); 117 | if (type != null) 118 | return type.getBukkit(); 119 | 120 | try 121 | { 122 | return org.bukkit.potion.PotionType.valueOf( 123 | string.toUpperCase().replace(" ", "_")); 124 | } catch (IllegalArgumentException ignored) { } 125 | return null; 126 | } 127 | 128 | /** 129 | * Finds the Bukkit PotionEffectType from a given string, falling back to 130 | * {@link PotionEffectType#getByName(String)} if no PotionType exists. 131 | * @param string String to parse 132 | * @return The PotionEffectType, or null if none could be found 133 | */ 134 | public static PotionEffectType findEffect(String string) 135 | { 136 | PotionType type = find(string); 137 | if (type != null) 138 | { 139 | PotionEffectType effect = type.getEffectType(); 140 | if (effect != null) 141 | return effect; 142 | } 143 | 144 | return PotionEffectType.getByName(string.replace(" ", "_")); 145 | } 146 | 147 | /** 148 | * Finds a PotionType from a given string matcher 149 | * @param matcher String matcher 150 | * @return The PotionType, or null if none exists 151 | */ 152 | public static PotionType find(String matcher) 153 | { 154 | Validate.notNull(matcher, "matcher cannot be null!"); 155 | matcher = matcher.toLowerCase(); 156 | 157 | for (PotionType type : values()) 158 | { 159 | if (type.getName().equals(matcher) 160 | || type.name().toLowerCase().equals(matcher) 161 | || containsIgnoreCase(matcher, type.getAliases())) 162 | return type; 163 | } 164 | 165 | return null; 166 | } 167 | 168 | private static boolean containsIgnoreCase(String lookup, String[] array) 169 | { 170 | for (String string : array) 171 | { 172 | if (string.equalsIgnoreCase(lookup)) 173 | return true; 174 | } 175 | 176 | return false; 177 | } 178 | 179 | /** 180 | * Returns a String representation of a {@link Collection} of 181 | * PotionEffects 182 | * 183 | * @param effects Collection of potion effects. 184 | */ 185 | // TODO Figure out a good way to use our strings 186 | public static String toString(Collection effects) 187 | { 188 | Validate.notNull(effects, "effects cannot be null!"); 189 | 190 | StringJoiner joiner = new StringJoiner(", "); 191 | for (PotionEffect effect : effects) 192 | { 193 | joiner.append(FormatUtil.getFriendlyName(effect.getType())); 194 | } 195 | 196 | return joiner.toString(); 197 | } 198 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/Reloadable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | /** 21 | * Represents a reloadable class. 22 | * 23 | * @author dmulloy2 24 | */ 25 | 26 | public interface Reloadable 27 | { 28 | /** 29 | * Reloads settings in this class. 30 | */ 31 | void reload(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/SimpleVector.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import java.util.LinkedHashMap; 21 | import java.util.Map; 22 | import java.util.Objects; 23 | 24 | import lombok.Getter; 25 | import net.dmulloy2.swornapi.util.NumberUtil; 26 | 27 | import org.apache.commons.lang.Validate; 28 | import org.bukkit.Location; 29 | import org.bukkit.World; 30 | import org.bukkit.configuration.serialization.ConfigurationSerializable; 31 | import org.bukkit.configuration.serialization.SerializableAs; 32 | import org.bukkit.util.Vector; 33 | 34 | /** 35 | * Represents a serializable vector. 36 | * 37 | * @author dmulloy2 38 | */ 39 | 40 | @Getter 41 | @SerializableAs("net.dmulloy2.SimpleVector") 42 | public final class SimpleVector implements ConfigurationSerializable, Cloneable 43 | { 44 | private int x, y, z; 45 | 46 | public SimpleVector() 47 | { 48 | this.x = 0; 49 | this.y = 0; 50 | this.z = 0; 51 | } 52 | 53 | public SimpleVector(int x, int y, int z) 54 | { 55 | this.x = x; 56 | this.y = y; 57 | this.z = z; 58 | } 59 | 60 | public SimpleVector(Vector vec) 61 | { 62 | this(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); 63 | } 64 | 65 | public SimpleVector(Location loc) 66 | { 67 | this(loc.toVector()); 68 | } 69 | 70 | public SimpleVector(String s) 71 | { 72 | Validate.notEmpty(s, "s cannot be null or empty!"); 73 | 74 | String[] ss = s.split(","); 75 | this.x = NumberUtil.toInt(ss[0]); 76 | this.y = NumberUtil.toInt(ss[1]); 77 | this.z = NumberUtil.toInt(ss[2]); 78 | } 79 | 80 | public SimpleVector(Map args) 81 | { 82 | this((String) args.get("c")); 83 | } 84 | 85 | // ---- Conversion 86 | 87 | /** 88 | * Converts this SimpleVector into a Bukkit {@link Vector} 89 | */ 90 | public Vector toVector() 91 | { 92 | return new Vector(x, y, z); 93 | } 94 | 95 | /** 96 | * Converts this SimpleVector into a Bukkit {@link Location} 97 | * 98 | * @param world World 99 | */ 100 | public Location toLocation(World world) 101 | { 102 | return toVector().toLocation(world); 103 | } 104 | 105 | // ---- Serialization 106 | 107 | @Override 108 | public Map serialize() 109 | { 110 | Map result = new LinkedHashMap<>(); 111 | result.put("c", toString()); 112 | return result; 113 | } 114 | 115 | // ---- Generic Methods 116 | 117 | @Override 118 | public String toString() 119 | { 120 | return x + "," + y + "," + z; 121 | } 122 | 123 | @Override 124 | public boolean equals(Object obj) 125 | { 126 | if (obj instanceof SimpleVector that) 127 | { 128 | return this.x == that.x && this.y == that.y && this.z == that.z; 129 | } 130 | 131 | return false; 132 | } 133 | 134 | @Override 135 | public int hashCode() 136 | { 137 | return Objects.hash(x, y, z); 138 | } 139 | 140 | @Override 141 | public SimpleVector clone() 142 | { 143 | return new SimpleVector(x, y, z); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/Sorter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import java.util.Arrays; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Map.Entry; 25 | import java.util.stream.Collectors; 26 | 27 | import lombok.AllArgsConstructor; 28 | import lombok.Getter; 29 | import lombok.Setter; 30 | 31 | /** 32 | * Utility class for sorting lists and arrays based on given criteria. 33 | * @author dmulloy2 34 | */ 35 | @Getter @Setter 36 | public class Sorter> 37 | { 38 | /** 39 | * Obtains criteria used for sorting 40 | * @author dmulloy2 41 | */ 42 | @FunctionalInterface 43 | public interface SortCriteria 44 | { 45 | /** 46 | * Obtains the criteria used for sorting from the given object 47 | * @param key Object in the list 48 | * @return Criteria for sorting 49 | */ 50 | V getValue(K key); 51 | } 52 | 53 | /** 54 | * Sorting mode, either ascending or descending 55 | * @author dmulloy2 56 | */ 57 | @Getter 58 | @AllArgsConstructor 59 | public enum SortMode 60 | { 61 | /** 62 | * Sorts values in ascending order, with the lowest values first 63 | */ 64 | ASCENDING(1), 65 | /** 66 | * Sorts values in descending order, with the highest values first 67 | */ 68 | DESCENDING(-1); 69 | 70 | private final int sign; 71 | } 72 | 73 | /** 74 | * Filters out values from sorting 75 | * @author dmulloy2 76 | */ 77 | @FunctionalInterface 78 | public interface Filter 79 | { 80 | /** 81 | * Whether or not to include this value in the sorting process 82 | * @param value Value to check 83 | * @return True if acceptable, false if not 84 | */ 85 | boolean accept(V value); 86 | } 87 | 88 | private SortCriteria criteria; 89 | private SortMode mode; 90 | 91 | /** 92 | * Creates a new sorter with no filtering. 93 | * @param criteria Criteria to sort by 94 | * @param mode Sorting mode 95 | */ 96 | public Sorter(SortCriteria criteria, SortMode mode) 97 | { 98 | this.criteria = criteria; 99 | this.mode = mode; 100 | } 101 | 102 | /** 103 | * Creates a new sorter, defaulting to descending order. 104 | * @param criteria Criteria to sort by 105 | */ 106 | public Sorter(SortCriteria criteria) 107 | { 108 | this(criteria, SortMode.DESCENDING); 109 | } 110 | 111 | /** 112 | * Sorts the given array based on this Sorter's criteria and mode. 113 | * @param array Array to sort 114 | * @return The sorted array as a list 115 | */ 116 | public List sort(K[] array) 117 | { 118 | return sort(Arrays.stream(array) 119 | .collect(Collectors.toMap(k -> k, criteria::getValue))); 120 | } 121 | 122 | /** 123 | * Sorts the given collection based on this Sorter's criteria and mode. 124 | * @param collection Collection to sort 125 | * @return The sorted collection as a list 126 | */ 127 | public List sort(Collection collection) { 128 | return sort(collection.stream() 129 | .collect(Collectors.toMap(k -> k, criteria::getValue))); 130 | } 131 | 132 | // Where the actual sorting takes place 133 | private List sort(Map map) { 134 | return map.entrySet() 135 | .stream() 136 | .sorted((e1, e2) -> mode.getSign() * e1.getValue().compareTo(e2.getValue())) 137 | .map(Entry::getKey) 138 | .collect(Collectors.toList()); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/SpecialEntities.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import net.dmulloy2.swornapi.util.Util; 21 | 22 | import org.bukkit.Location; 23 | import org.bukkit.entity.ChestedHorse; 24 | import org.bukkit.entity.ElderGuardian; 25 | import org.bukkit.entity.Entity; 26 | import org.bukkit.entity.EntityType; 27 | import org.bukkit.entity.Guardian; 28 | import org.bukkit.entity.Horse; 29 | import org.bukkit.entity.Horse.Color; 30 | import org.bukkit.entity.Horse.Style; 31 | import org.bukkit.entity.Horse.Variant; 32 | import org.bukkit.entity.LivingEntity; 33 | import org.bukkit.entity.Skeleton; 34 | import org.bukkit.entity.Skeleton.SkeletonType; 35 | import org.bukkit.entity.Villager.Profession; 36 | import org.bukkit.entity.Zombie; 37 | import org.bukkit.entity.ZombieVillager; 38 | 39 | import lombok.AllArgsConstructor; 40 | import lombok.Getter; 41 | 42 | import java.util.Objects; 43 | 44 | /** 45 | * Handles special entities such as Wither Skeletons, Zombie Villagers, and Horses. 46 | * Necessary because Mojang changed Entities how are structured in 1.11. 47 | * 48 | * @author dmulloy2 49 | */ 50 | @SuppressWarnings("deprecation") 51 | public class SpecialEntities 52 | { 53 | private static Provider provider; 54 | 55 | static 56 | { 57 | try 58 | { 59 | ElderGuardian.class.getName(); 60 | provider = new SeparateProvider(); 61 | } 62 | catch (Throwable ex) 63 | { 64 | provider = new CombinedProvider(); 65 | } 66 | } 67 | 68 | private SpecialEntities() { } 69 | 70 | private interface Provider 71 | { 72 | LivingEntity spawnWitherSkeleton(Location loc); 73 | LivingEntity spawnZombieVillager(Location loc, Profession profession); 74 | LivingEntity spawnHorse(Location loc, HorseType type, Horse.Color color, 75 | Horse.Style style, boolean tame, boolean chest); 76 | boolean isElderGuardian(Entity entity); 77 | } 78 | 79 | private static class SeparateProvider implements Provider 80 | { 81 | @Override 82 | public LivingEntity spawnWitherSkeleton(Location loc) 83 | { 84 | Objects.requireNonNull(loc, "loc cannot be null"); 85 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 86 | 87 | return (LivingEntity) loc.getWorld().spawnEntity(loc, EntityType.WITHER_SKELETON); 88 | } 89 | 90 | @Override 91 | public LivingEntity spawnZombieVillager(Location loc, Profession profession) 92 | { 93 | Objects.requireNonNull(loc, "loc cannot be null"); 94 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 95 | 96 | ZombieVillager entity = (ZombieVillager) loc.getWorld().spawnEntity(loc, EntityType.ZOMBIE_VILLAGER); 97 | entity.setVillagerProfession(profession); 98 | return entity; 99 | } 100 | 101 | @Override 102 | public LivingEntity spawnHorse(Location loc, HorseType type, Color color, Style style, boolean tame, boolean chest) 103 | { 104 | Objects.requireNonNull(loc, "loc cannot be null"); 105 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 106 | 107 | Horse horse = (Horse) loc.getWorld().spawnEntity(loc, type.getEntity()); 108 | horse.setColor(color); 109 | horse.setStyle(style); 110 | horse.setTamed(tame); 111 | 112 | if (chest && horse instanceof ChestedHorse) 113 | ((ChestedHorse) horse).setCarryingChest(true); 114 | 115 | return horse; 116 | } 117 | 118 | @Override 119 | public boolean isElderGuardian(Entity entity) 120 | { 121 | return entity instanceof ElderGuardian; 122 | } 123 | 124 | } 125 | 126 | @Getter 127 | @AllArgsConstructor 128 | public enum HorseType 129 | { 130 | DONKEY(EntityType.DONKEY, Variant.DONKEY), 131 | NORMAL(EntityType.HORSE, Variant.HORSE), 132 | LLAMA(EntityType.LLAMA, Variant.LLAMA), 133 | MULE(EntityType.MULE, Variant.MULE), 134 | SKELETON(EntityType.SKELETON_HORSE, Variant.SKELETON_HORSE), 135 | ZOMBIE(EntityType.ZOMBIE_HORSE, Variant.UNDEAD_HORSE) 136 | ; 137 | 138 | private final EntityType entity; 139 | private final Variant variant; 140 | } 141 | 142 | private static class CombinedProvider implements Provider 143 | { 144 | @Override 145 | public LivingEntity spawnWitherSkeleton(Location loc) 146 | { 147 | Objects.requireNonNull(loc, "loc cannot be null"); 148 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 149 | 150 | Skeleton entity = (Skeleton) loc.getWorld().spawnEntity(loc, EntityType.SKELETON); 151 | entity.setSkeletonType(SkeletonType.WITHER); 152 | return entity; 153 | } 154 | 155 | @Override 156 | public LivingEntity spawnZombieVillager(Location loc, Profession profession) 157 | { 158 | Objects.requireNonNull(loc, "loc cannot be null"); 159 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 160 | 161 | Zombie zombie = (Zombie) loc.getWorld().spawnEntity(loc, EntityType.ZOMBIE); 162 | zombie.setVillagerProfession(profession); 163 | return zombie; 164 | } 165 | 166 | @Override 167 | public LivingEntity spawnHorse(Location loc, HorseType type, Color color, Style style, boolean tame, boolean chest) 168 | { 169 | Objects.requireNonNull(loc, "loc cannot be null"); 170 | Objects.requireNonNull(loc.getWorld(), "loc world cannot be null"); 171 | 172 | Horse horse = (Horse) loc.getWorld().spawnEntity(loc, EntityType.HORSE); 173 | horse.setVariant(type.getVariant()); 174 | horse.setColor(color); 175 | horse.setStyle(style); 176 | horse.setTamed(tame); 177 | horse.setCarryingChest(chest); 178 | return horse; 179 | } 180 | 181 | @Override 182 | public boolean isElderGuardian(Entity entity) 183 | { 184 | return entity instanceof Guardian && ((Guardian) entity).isElder(); 185 | } 186 | } 187 | 188 | /** 189 | * Spawns a Wither Skeleton at a given location. 190 | * @param loc Location to spawn at 191 | * @return The Wither Skeleton 192 | */ 193 | public static LivingEntity spawnWitherSkeleton(Location loc) 194 | { 195 | return provider.spawnWitherSkeleton(loc); 196 | } 197 | 198 | /** 199 | * Spawns a Zombie Villager at a given location with a given profession. 200 | * @param loc Location to spawn at 201 | * @param profession Villager profession, random if null 202 | * @return The Zombie Villager 203 | */ 204 | public static LivingEntity spawnZombieVillager(Location loc, Profession profession) 205 | { 206 | if (profession == null) profession = randomElement(Profession.values()); 207 | 208 | return provider.spawnZombieVillager(loc, profession); 209 | } 210 | 211 | /** 212 | * Whether or not a given Entity is an Elder Guardian. 213 | * @param entity Entity to check 214 | * @return True if an elder, false if not 215 | */ 216 | public static boolean isElderGuardian(Entity entity) 217 | { 218 | return provider.isElderGuardian(entity); 219 | } 220 | 221 | /** 222 | * Spawns a Horse at a given location with the given properties. 223 | * @param loc Location to spawn at 224 | * @param type Horse Type, null if random 225 | * @param color Horse Color, null if random 226 | * @param style Horse Style, null if random 227 | * @param tame Whether or not the Horse is tamed 228 | * @param chest Whether or not the Horse is carrying a chest 229 | * @return The Horse 230 | */ 231 | public static LivingEntity spawnHorse(Location loc, HorseType type, 232 | Horse.Color color, Horse.Style style, boolean tame, boolean chest) 233 | { 234 | if (type == null) type = randomElement(HorseType.values()); 235 | if (color == null) color = randomElement(Horse.Color.values()); 236 | if (style == null) style = randomElement(Horse.Style.values()); 237 | 238 | return provider.spawnHorse(loc, type, color, style, tame, chest); 239 | } 240 | 241 | private static E randomElement(E[] elements) 242 | { 243 | return elements[Util.random(elements.length)]; 244 | } 245 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/StringJoiner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import org.apache.commons.lang.Validate; 21 | 22 | /** 23 | * StringJoiner is used to construct a sequence of characters separated by a 24 | * delimiter. 25 | * 26 | * @author dmulloy2 27 | */ 28 | 29 | public class StringJoiner 30 | { 31 | private static final String DEFAULT_DELIMITER = " "; 32 | public static final StringJoiner SPACE = new StringJoiner(); 33 | 34 | private String delimiter; 35 | private StringBuilder builder; 36 | 37 | /** 38 | * Constructs a new StringJoiner with the default delimiter. 39 | */ 40 | public StringJoiner() 41 | { 42 | this.delimiter = DEFAULT_DELIMITER; 43 | this.builder = new StringBuilder(); 44 | } 45 | 46 | /** 47 | * Constructs a new StringJoiner with a given delimiter. 48 | * 49 | * @param delimiter Delimiter 50 | */ 51 | public StringJoiner(String delimiter) 52 | { 53 | Validate.notNull(delimiter, "delimiter cannot be null!"); 54 | 55 | this.delimiter = delimiter; 56 | this.builder = new StringBuilder(); 57 | } 58 | 59 | /** 60 | * Appends a given {@link String} to this StringJoiner. 61 | * 62 | * @param string String to append 63 | * @return This, for chaining 64 | */ 65 | public final StringJoiner append(final String string) 66 | { 67 | Validate.notNull(string, "string cannot be null!"); 68 | 69 | if (! string.isEmpty()) 70 | builder.append(string).append(delimiter); 71 | return this; 72 | } 73 | 74 | /** 75 | * Appends an {@link Iterable} set of {@link String}s. 76 | * 77 | * @param strings Strings to append 78 | * @return This, for chaining 79 | */ 80 | public final StringJoiner appendAll(final Iterable strings) 81 | { 82 | Validate.notNull(strings, "strings cannot be null!"); 83 | 84 | for (String string : strings) 85 | { 86 | append(string); 87 | } 88 | 89 | return this; 90 | } 91 | 92 | /** 93 | * Appends a given array of {@link String}s to this StringJoiner. 94 | * 95 | * @param strings Strings to append 96 | * @return This, for chaining 97 | */ 98 | public final StringJoiner appendAll(final String... strings) 99 | { 100 | Validate.noNullElements(strings, "strings cannot have null elements!"); 101 | 102 | for (String string : strings) 103 | { 104 | append(string); 105 | } 106 | 107 | return this; 108 | } 109 | 110 | /** 111 | * Resets this {@link StringJoiner}'s string value. 112 | * 113 | * @return This, for chaining 114 | */ 115 | public final StringJoiner newString() 116 | { 117 | this.builder = new StringBuilder(); 118 | return this; 119 | } 120 | 121 | /** 122 | * Sets a new delimiter for this {@link StringJoiner} while keeping the 123 | * string value. 124 | * 125 | * @param delimiter New delimiter 126 | * @return This, for chaining 127 | */ 128 | public final StringJoiner setDelimiter(final String delimiter) 129 | { 130 | Validate.notNull(delimiter, "delimiter cannot be null!"); 131 | 132 | this.delimiter = delimiter; 133 | return this; 134 | } 135 | 136 | /** 137 | * {@inheritDoc} 138 | */ 139 | @Override 140 | public final String toString() 141 | { 142 | if (builder.lastIndexOf(delimiter) >= 0) 143 | builder.delete(builder.lastIndexOf(delimiter), builder.length()); 144 | 145 | return builder.toString(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/types/Versioning.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.types; 19 | 20 | import org.bukkit.Bukkit; 21 | 22 | import lombok.Getter; 23 | 24 | /** 25 | * @author dmulloy2 26 | */ 27 | 28 | public class Versioning 29 | { 30 | private Versioning() { } 31 | 32 | /** 33 | * Represents a supported Minecraft version 34 | */ 35 | @Getter 36 | public enum Version 37 | { 38 | /** 39 | * Minecraft 1.19, the wild update 40 | */ 41 | MC_119("Minecraft 1.19.x", "1.19"), 42 | /** 43 | * Minecraft 1.18, caves & cliffs II 44 | */ 45 | MC_118("Minecraft 1.18.x", "1.18"), 46 | /** 47 | * Minecraft 1.17, caves & cliffs I 48 | */ 49 | MC_117("Minecraft 1.17.x", "1.17"), 50 | /** 51 | * Minecraft 1.16, the nether update 52 | */ 53 | MC_116("Minecraft 1.16.x", "1.16"), 54 | /** 55 | * Minecraft 1.15, the bee update 56 | */ 57 | MC_115("Minecraft 1.15.x", "1.15"), 58 | /** 59 | * Minecraft 1.14, the village and pillage update 60 | */ 61 | MC_114("Minecraft 1.14.x", "1.14"), 62 | /** 63 | * Minecraft 1.13, update aquatic / the flattening 64 | */ 65 | MC_113("Minecraft 1.13.x", "1.13"), 66 | /** 67 | * Minecraft 1.12, the world of color update 68 | */ 69 | MC_112("Minecraft 1.12.x", "1.12"), 70 | /** 71 | * Minecraft 1.11, the exploration update 72 | */ 73 | MC_111("Minecraft 1.11.x", "1.11"), 74 | /** 75 | * Minecraft 1.10, the frostburn update 76 | */ 77 | MC_110("Minecraft 1.10.x", "1.10"), 78 | /** 79 | * Minecraft 1.9, the combat update 80 | */ 81 | MC_19("Minecraft 1.9.x", "1.9"), 82 | /** 83 | * Minecraft 1.8, the bountiful update 84 | */ 85 | MC_18("Minecraft 1.8.x", "1.8"), 86 | /** 87 | * Minecraft 1.7, the update that changed the world. No longer supported. 88 | */ 89 | MC_17("Minecraft 1.7.x", "1.7", false), 90 | /** 91 | * Minecraft 1.6, the horse update. No longer supported. 92 | */ 93 | MC_16("Minecraft 1.6.x", "1.6", false), 94 | /** 95 | * Generic unknown version. Obviously not supported. 96 | */ 97 | UNKNOWN("Minecraft 1.x.x", "N/A", false); 98 | 99 | private String name; 100 | private final String matcher; 101 | 102 | private final boolean isKnown; 103 | private final boolean isSupported; 104 | 105 | Version(String name, String matcher) 106 | { 107 | this(name, matcher, true); 108 | } 109 | 110 | Version(String name, String matcher, boolean isSupported) 111 | { 112 | this.name = name; 113 | this.matcher = matcher; 114 | this.isKnown = true; 115 | this.isSupported = isSupported; 116 | } 117 | 118 | /** 119 | * Whether or not SwornAPI explicitly supports this version. 120 | * @return True if it does, false if not 121 | */ 122 | public boolean isSupported() 123 | { 124 | return isKnown && isSupported; 125 | } 126 | 127 | /** 128 | * Whether or not SwornAPI has dropped support for this version. 129 | * @return True if it has, false if it hasn't 130 | */ 131 | public boolean wasDropped() 132 | { 133 | return isKnown && !isSupported; 134 | } 135 | 136 | @Override 137 | public String toString() 138 | { 139 | return name + (matcher != null ? "[matcher=" + matcher + "]" : ""); 140 | } 141 | } 142 | 143 | private static Version version; 144 | 145 | // Adapted from ProtocolLib 146 | 147 | private static Version fromCurrent() 148 | { 149 | String version = extractVersion(Bukkit.getBukkitVersion()); 150 | Version.UNKNOWN.name = "Minecraft " + version; 151 | return Version.UNKNOWN; 152 | } 153 | 154 | private static String extractVersion(String text) 155 | { 156 | return text.split("-")[0]; 157 | } 158 | 159 | /** 160 | * Gets the {@link Version} that this server is currently running. 161 | * 162 | * @return The version 163 | */ 164 | public static Version getVersion() 165 | { 166 | if (version == null) 167 | { 168 | String serverVersion = Bukkit.getBukkitVersion(); 169 | for (Version ver : Version.values()) 170 | { 171 | if (serverVersion.contains(ver.getMatcher())) 172 | return version = ver; 173 | } 174 | 175 | return version = fromCurrent(); 176 | } 177 | 178 | return version; 179 | } 180 | 181 | /** 182 | * For testing use only 183 | * 184 | * @param version The new version 185 | */ 186 | protected static void setVersion(Version version) 187 | { 188 | Versioning.version = version; 189 | } 190 | 191 | /** 192 | * Gets the version string that this server is currently running. 193 | * 194 | * @return The version string 195 | */ 196 | public static String getVersionString() 197 | { 198 | return getVersion().getName(); 199 | } 200 | 201 | /** 202 | * Whether or not the currently running version is supported. 203 | * 204 | * @return True if it is supported, false if not 205 | */ 206 | public static boolean isSupported() 207 | { 208 | return getVersion().isSupported(); 209 | } 210 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/CompatUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import org.bukkit.Material; 21 | import org.bukkit.entity.Player; 22 | import org.bukkit.inventory.ItemStack; 23 | import org.bukkit.inventory.meta.PotionMeta; 24 | import org.bukkit.plugin.Plugin; 25 | import org.bukkit.potion.PotionData; 26 | import org.bukkit.potion.PotionType; 27 | 28 | /** 29 | * Utility for dealing with backwards compatibility 30 | * @author dmulloy2 31 | * @deprecated Target newer versions of Minecraft 32 | */ 33 | @Deprecated 34 | public class CompatUtil 35 | { 36 | /** 37 | * Creates a potion with the given attributes. Potions were changed in 1.9, 38 | * necessitating this method. 39 | * 40 | * @param type Potion type 41 | * @param amount ItemStack amount 42 | * @param level Potion level 43 | * @param splash Whether or not it's a splash potion 44 | * @param extended Extended potion 45 | * @return The potion item 46 | */ 47 | public static ItemStack createPotion(PotionType type, int amount, int level, boolean splash, boolean extended) 48 | { 49 | Material material = splash ? Material.SPLASH_POTION : Material.POTION; 50 | PotionData data = new PotionData(type, extended, level > 1); 51 | ItemStack potion = new ItemStack(material, amount); 52 | PotionMeta meta = (PotionMeta) potion.getItemMeta(); 53 | meta.setBasePotionData(data); 54 | potion.setItemMeta(meta); 55 | return potion; 56 | } 57 | 58 | /** 59 | * Gets the item in a player's main hand. The ability to use the other hand 60 | * was added in 1.9, necessitating this method. 61 | * 62 | * @param player Player to get item from 63 | * @return The item 64 | */ 65 | public static ItemStack getItemInMainHand(Player player) 66 | { 67 | try 68 | { 69 | return player.getInventory().getItemInMainHand(); 70 | } 71 | catch (LinkageError e) 72 | { 73 | return player.getItemInHand(); 74 | } 75 | } 76 | 77 | /** 78 | * Sets the item in a player's main hand to a given item stack. The ability 79 | * to use the other hand was added in 1.9, necessitating this method. 80 | * 81 | * @param player Player to set item in hand 82 | * @param item Item to set 83 | */ 84 | public static void setItemInMainHand(Player player, ItemStack item) 85 | { 86 | try 87 | { 88 | player.getInventory().setItemInMainHand(item); 89 | } 90 | catch (LinkageError e) 91 | { 92 | player.setItemInHand(item); 93 | } 94 | } 95 | 96 | /** 97 | * Gets a player's max health. Implementations targeting newer versions of 98 | * Minecraft should use Attributes. 99 | * 100 | * @param player Player to get max health of 101 | * @return The max health 102 | */ 103 | public static double getMaxHealth(Player player) 104 | { 105 | try 106 | { 107 | return player.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); 108 | } 109 | catch (LinkageError e) 110 | { 111 | return player.getMaxHealth(); 112 | } 113 | } 114 | 115 | /** 116 | * Sets a player's max health. Implementations targeting newer versions of 117 | * Minecraft should use Attributes. 118 | * 119 | * @param player Player to set max health of 120 | * @param value New max health 121 | */ 122 | public static void setMaxHealth(Player player, double value) 123 | { 124 | try 125 | { 126 | player.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).setBaseValue(value); 127 | } 128 | catch (LinkageError e) 129 | { 130 | player.setMaxHealth(value); 131 | } 132 | } 133 | 134 | public static void hidePlayer(Player player1, Plugin plugin, Player player2) 135 | { 136 | try 137 | { 138 | player1.hidePlayer(plugin, player2); 139 | } 140 | catch (LinkageError e) 141 | { 142 | player1.showPlayer(player2); 143 | } 144 | } 145 | 146 | public static void showPlayer(Player player1, Plugin plugin, Player player2) 147 | { 148 | try 149 | { 150 | player1.showPlayer(plugin, player2); 151 | } 152 | catch (LinkageError e) 153 | { 154 | player1.showPlayer(player2); 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/FormatUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.lang.reflect.Method; 21 | import java.text.MessageFormat; 22 | 23 | import org.apache.commons.lang.Validate; 24 | import org.apache.commons.lang.WordUtils; 25 | import org.bukkit.ChatColor; 26 | import org.bukkit.Material; 27 | 28 | import net.dmulloy2.swornapi.types.StringJoiner; 29 | 30 | /** 31 | * Util used for general formatting. 32 | * 33 | * @author dmulloy2 34 | */ 35 | 36 | public class FormatUtil 37 | { 38 | private FormatUtil() { } 39 | 40 | /** 41 | * Formats a given string with its objects. 42 | * 43 | * @param format Base string 44 | * @param objects Objects to format in 45 | * @return Formatted string 46 | * @see MessageFormat#format(String, Object...) 47 | */ 48 | public static String format(String format, Object... objects) 49 | { 50 | Validate.notNull(format, "format cannot be null!"); 51 | 52 | try 53 | { 54 | format = MessageFormat.format(format, objects); 55 | } catch (Throwable ignored) { } 56 | 57 | return replaceColors(format); 58 | } 59 | 60 | private static final String[] rainbowColors = new String[] 61 | { 62 | "c", "6", "e", "a", "b", "d", "5" 63 | }; 64 | 65 | /** 66 | * Replaces color codes in a given string. Includes rainbow. 67 | * 68 | * @param message Message to replace color codes in 69 | * @return Formatted chat message 70 | */ 71 | public static String replaceColors(String message) 72 | { 73 | Validate.notNull(message, "message cannot be null!"); 74 | message = message.replaceAll("(&([zZ]))", "&z"); 75 | if (message.contains("&z")) 76 | { 77 | StringBuilder ret = new StringBuilder(); 78 | String[] ss = message.split("&z"); 79 | ret.append(ss[0]); 80 | ss[0] = null; 81 | 82 | for (String s : ss) 83 | { 84 | if (s != null) 85 | { 86 | int index = 0; 87 | while (index < s.length() && s.charAt(index) != '&') 88 | { 89 | ret.append("&").append(rainbowColors[index % rainbowColors.length]); 90 | ret.append(s.charAt(index)); 91 | index++; 92 | } 93 | 94 | if (index < s.length()) 95 | { 96 | ret.append(s.substring(index)); 97 | } 98 | } 99 | } 100 | 101 | message = ret.toString(); 102 | } 103 | 104 | // Format the colors 105 | return ChatColor.translateAlternateColorCodes('&', message); 106 | } 107 | 108 | /** 109 | * Returns a user-friendly representation of a given Object. This is mostly 110 | * used for {@link Enum} constants. 111 | *

112 | * If the object or any of its superclasses (minus Object) do not implement 113 | * a toString() method, the object's simple name will be returned. 114 | * 115 | * @param obj Object to get the user-friendly representation of 116 | * @return A user-friendly representation of the given Object. 117 | */ 118 | public static String getFriendlyName(Object obj) 119 | { 120 | Validate.notNull(obj, "obj cannot be null!"); 121 | 122 | try 123 | { 124 | // Clever little method to check if the method isn't declared by a class other than Object. 125 | Method method = obj.getClass().getMethod("toString"); 126 | if (method.getDeclaringClass().getSuperclass() == null) 127 | return obj.getClass().getSimpleName(); 128 | } catch (Throwable ignored) { } 129 | return getFriendlyName(obj.toString()); 130 | } 131 | 132 | /** 133 | * Returns a user-friendly version of a given String. 134 | * 135 | * @param string String to get the user-friendly version of 136 | * @return A user-friendly version of the given String. 137 | */ 138 | public static String getFriendlyName(String string) 139 | { 140 | Validate.notNull(string, "string cannot be null!"); 141 | 142 | return WordUtils.capitalize(string.toLowerCase().replaceAll("_", " ")); 143 | } 144 | 145 | /** 146 | * Returns a user-friendly version of a given Material. 147 | * 148 | * @param material Material to get the user-friendly version of 149 | * @return The string 150 | * @see MaterialUtil#getName(Material) 151 | */ 152 | public static String getFriendlyName(Material material) 153 | { 154 | return getFriendlyName(material.name()); 155 | } 156 | 157 | private static final String VOWELS = "aeiou"; 158 | 159 | /** 160 | * Returns the proper article of a given string 161 | * 162 | * @param string String to get the article for 163 | * @return The proper article of a given string 164 | */ 165 | public static String getArticle(String string) 166 | { 167 | Validate.notEmpty(string, "string cannot be null or empty!"); 168 | 169 | return VOWELS.indexOf(Character.toLowerCase(string.charAt(0))) != -1 ? "an" : "a"; 170 | } 171 | 172 | /** 173 | * Returns the proper plural of a given string 174 | * 175 | * @param string String to get the plural for 176 | * @return The proper plural of a given string 177 | */ 178 | public static String getPlural(String string, int amount) 179 | { 180 | Validate.notEmpty(string, "string cannot be null or empty!"); 181 | 182 | amount = Math.abs(amount); 183 | if (amount != 1) 184 | { 185 | char end = string.charAt(string.length() - 1); 186 | if (end != 's') 187 | return Character.isUpperCase(end) ? string + "S" : string + "s"; 188 | } 189 | 190 | return string; 191 | } 192 | 193 | /** 194 | * Capitalizes the first letter of a given string. 195 | * 196 | * @param string String to capitalize 197 | * @return The resulting String 198 | */ 199 | public static String capitalizeFirst(String string) 200 | { 201 | Validate.notEmpty(string, "string cannot be null or empty!"); 202 | return Character.toUpperCase(string.charAt(0)) + string.substring(1); 203 | } 204 | 205 | /** 206 | * Joins together multiple given strings with the given glue using the 207 | * {@link StringJoiner} class. 208 | * 209 | * @param delimiter String to join the args together with 210 | * @param args Strings to join together 211 | * @return Multiple strings joined together with the given glue. 212 | * @see StringJoiner 213 | */ 214 | public static String join(String delimiter, String... args) 215 | { 216 | Validate.notNull(delimiter, "glue cannot be null"); 217 | Validate.noNullElements(args, "args cannot have null elements!"); 218 | 219 | return new StringJoiner(delimiter).appendAll(args).toString(); 220 | } 221 | 222 | /** 223 | * Joins together multiple given strings with a single space using the 224 | * {@link StringJoiner} class. 225 | * 226 | * @param args Strings to join together 227 | * @return Multiple strings joined together with a space 228 | * @see StringJoiner 229 | */ 230 | public static String join(String... args) 231 | { 232 | Validate.noNullElements(args, "args cannot have null elements!"); 233 | 234 | return StringJoiner.SPACE.newString().appendAll(args).toString(); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/InventoryUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import org.apache.commons.lang.Validate; 24 | import org.bukkit.Material; 25 | import org.bukkit.entity.Player; 26 | import org.bukkit.inventory.Inventory; 27 | import org.bukkit.inventory.ItemStack; 28 | import org.bukkit.inventory.PlayerInventory; 29 | 30 | /** 31 | * Util dealing with Inventories. 32 | * 33 | * @author dmulloy2 34 | */ 35 | 36 | public class InventoryUtil 37 | { 38 | private InventoryUtil() { } 39 | 40 | /** 41 | * Whether or not a given {@link Inventory} is empty. 42 | * 43 | * @param inventory Inventory to check 44 | * @return True if the inventory is empty, false if not 45 | */ 46 | public static boolean isEmpty(Inventory inventory) 47 | { 48 | Validate.notNull(inventory, "inventory cannot be null!"); 49 | 50 | for (ItemStack stack : inventory.getContents()) 51 | { 52 | if (stack != null && stack.getType() != Material.AIR) 53 | return false; 54 | } 55 | 56 | if (inventory instanceof PlayerInventory) 57 | { 58 | for (ItemStack armor : ((PlayerInventory) inventory).getArmorContents()) 59 | { 60 | if (armor != null && armor.getType() != Material.AIR) 61 | return false; 62 | } 63 | } 64 | 65 | return true; 66 | } 67 | 68 | /** 69 | * Completely clears an inventory, including armor, if applicable. 70 | * 71 | * @param inventory Inventory to clear 72 | */ 73 | public static void clear(Inventory inventory) 74 | { 75 | Validate.notNull(inventory, "inventory cannot be null!"); 76 | 77 | inventory.clear(); 78 | 79 | if (inventory instanceof PlayerInventory pInventory) 80 | { 81 | pInventory.setHelmet(null); 82 | pInventory.setChestplate(null); 83 | pInventory.setLeggings(null); 84 | pInventory.setBoots(null); 85 | } 86 | } 87 | 88 | /** 89 | * Gives a {@link Player} an item. 90 | * 91 | * @param player {@link Player} to give them item to 92 | * @param item {@link ItemStack} to give the player 93 | * @return Leftovers, if any 94 | */ 95 | public static Map giveItem(Player player, ItemStack item) 96 | { 97 | Validate.notNull(player, "player cannot be null!"); 98 | return addItems(player.getInventory(), item); 99 | } 100 | 101 | /** 102 | * Gives a {@link Player} items. 103 | * 104 | * @param player {@link Player} to give them item to 105 | * @param items {@link ItemStack}s to give the player 106 | * @return Leftovers, if any 107 | */ 108 | public static Map giveItems(Player player, ItemStack... items) 109 | { 110 | Validate.notNull(player, "player cannot be null!"); 111 | Validate.noNullElements(items, "items cannot contain null elements!"); 112 | 113 | return addItems(player.getInventory(), items); 114 | } 115 | 116 | /** 117 | * Gets the amount of {@link ItemStack}s in an inventory with a given type 118 | * and data. 119 | * 120 | * @param inventory Inventory containing the items 121 | * @param type Material of the item 122 | * @param dat Item data 123 | * @return The amount of items 124 | */ 125 | public static int amount(Inventory inventory, Material type, short dat) 126 | { 127 | Validate.notNull(inventory, "inventory cannot be null!"); 128 | Validate.notNull(type, "type cannot be null!"); 129 | 130 | int ret = 0; 131 | ItemStack[] items = inventory.getContents(); 132 | for (ItemStack item : items) 133 | { 134 | if (item != null && item.getType() != Material.AIR) 135 | { 136 | Material mat = item.getType(); 137 | short duration = item.getDurability(); 138 | int amt = item.getAmount(); 139 | if (mat == type) 140 | { 141 | if (dat == -1 || dat == duration) 142 | { 143 | ret += amt; 144 | } 145 | } 146 | } 147 | } 148 | 149 | return ret; 150 | } 151 | 152 | /** 153 | * Removes items from an inventory. 154 | * 155 | * @param inventory Inventory to remove items from 156 | * @param type Type of the items 157 | * @param dat Data of the items 158 | * @param amt Amount to remove 159 | * @throws IllegalArgumentException if {@code amt} is less than 0 160 | */ 161 | public static void remove(Inventory inventory, Material type, short dat, int amt) 162 | { 163 | Validate.notNull(inventory, "inventory cannot be null!"); 164 | Validate.notNull(type, "type cannot be null!"); 165 | Validate.isTrue(amt > 0, "amt cannot be less than 0!"); 166 | 167 | int start = amt; 168 | ItemStack[] items = inventory.getContents(); 169 | for (int slot = 0; slot < items.length; slot++) 170 | { 171 | if (items[slot] != null) 172 | { 173 | Material mat = items[slot].getType(); 174 | short duration = items[slot].getDurability(); 175 | int itmAmt = items[slot].getAmount(); 176 | if ((mat == type) && ((dat == duration) || (dat == -1))) 177 | { 178 | if (itmAmt >= amt) 179 | { 180 | itmAmt -= amt; 181 | amt = 0; 182 | } 183 | else 184 | { 185 | amt = start - itmAmt; 186 | itmAmt = 0; 187 | } 188 | if (itmAmt > 0) 189 | { 190 | inventory.getItem(slot).setAmount(itmAmt); 191 | } 192 | else 193 | { 194 | inventory.setItem(slot, null); 195 | } 196 | 197 | if (amt <= 0) 198 | { 199 | return; 200 | } 201 | } 202 | } 203 | } 204 | } 205 | 206 | // ---- Internal Methods 207 | 208 | private static Map addItems(Inventory inventory, ItemStack... items) 209 | { 210 | return addOversizedItems(inventory, 0, items); 211 | } 212 | 213 | private static Map addOversizedItems(Inventory inventory, int oversizedStacks, ItemStack... items) 214 | { 215 | Map leftover = new HashMap<>(); 216 | 217 | ItemStack[] combined = new ItemStack[items.length]; 218 | for (ItemStack item1 : items) 219 | { 220 | if (item1 == null || item1.getAmount() < 1) 221 | continue; 222 | 223 | for (int j = 0; j < combined.length; j++) 224 | { 225 | if (combined[j] == null) 226 | { 227 | combined[j] = item1.clone(); 228 | combined[j].setData(item1.getData()); 229 | break; 230 | } 231 | 232 | if (combined[j].isSimilar(item1)) 233 | { 234 | combined[j].setAmount(combined[j].getAmount() + item1.getAmount()); 235 | break; 236 | } 237 | } 238 | } 239 | 240 | for (int i = 0; i < combined.length; i++) 241 | { 242 | ItemStack item = combined[i]; 243 | if (item == null) 244 | continue; 245 | 246 | while (true) 247 | { 248 | // Do we already have a stack of it? 249 | int maxAmount = Math.max(oversizedStacks, item.getType().getMaxStackSize()); 250 | int firstPartial = firstPartial(inventory, item, maxAmount); 251 | 252 | // Drat! no partial stack 253 | if (firstPartial == - 1) 254 | { 255 | // Find a free spot! 256 | int firstFree = inventory.firstEmpty(); 257 | 258 | if (firstFree == - 1) 259 | { 260 | // No space at all! 261 | leftover.put(i, item); 262 | break; 263 | } 264 | else 265 | { 266 | // More than a single stack! 267 | if (item.getAmount() > maxAmount) 268 | { 269 | ItemStack stack = item.clone(); 270 | stack.setData(item.getData()); 271 | stack.setAmount(maxAmount); 272 | inventory.setItem(firstFree, stack); 273 | item.setAmount(item.getAmount() - maxAmount); 274 | } 275 | else 276 | { 277 | // Just store it 278 | inventory.setItem(firstFree, item); 279 | break; 280 | } 281 | } 282 | } 283 | else 284 | { 285 | // So, apparently it might only partially fit, well lets do 286 | // just that 287 | ItemStack partialItem = inventory.getItem(firstPartial); 288 | 289 | int amount = item.getAmount(); 290 | int partialAmount = partialItem.getAmount(); 291 | 292 | // Check if it fully fits 293 | if (amount + partialAmount <= maxAmount) 294 | { 295 | partialItem.setAmount(amount + partialAmount); 296 | break; 297 | } 298 | 299 | // It fits partially 300 | partialItem.setAmount(maxAmount); 301 | item.setAmount(amount + partialAmount - maxAmount); 302 | } 303 | } 304 | } 305 | 306 | return leftover; 307 | } 308 | 309 | private static int firstPartial(Inventory inventory, ItemStack item, int maxAmount) 310 | { 311 | if (item == null) 312 | return -1; 313 | 314 | ItemStack[] stacks = inventory.getContents(); 315 | for (int i = 0; i < stacks.length; i++) 316 | { 317 | ItemStack cItem = stacks[i]; 318 | if (cItem != null && cItem.getAmount() < maxAmount && cItem.isSimilar(item)) 319 | return i; 320 | } 321 | 322 | return -1; 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/ItemUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.util.*; 21 | import java.util.Map.Entry; 22 | import java.util.logging.Level; 23 | import java.util.regex.Pattern; 24 | 25 | import net.dmulloy2.swornapi.SwornPlugin; 26 | import net.dmulloy2.swornapi.types.CustomSkullType; 27 | import net.dmulloy2.swornapi.types.EnchantmentType; 28 | import net.dmulloy2.swornapi.types.StringJoiner; 29 | 30 | import org.bukkit.ChatColor; 31 | import org.bukkit.DyeColor; 32 | import org.bukkit.Material; 33 | import org.bukkit.enchantments.Enchantment; 34 | import org.bukkit.inventory.ItemStack; 35 | import org.bukkit.inventory.meta.ItemMeta; 36 | import org.bukkit.inventory.meta.LeatherArmorMeta; 37 | import org.bukkit.inventory.meta.SkullMeta; 38 | import org.bukkit.potion.PotionType; 39 | 40 | /** 41 | * Utility for dealing with items and potions 42 | * @author dmulloy2 43 | */ 44 | 45 | public class ItemUtil 46 | { 47 | private ItemUtil() { } 48 | 49 | /** 50 | * Parses an ItemStack from configuration. This provides limited meta 51 | * support. This should be surrounded in a try-catch block to deal with 52 | * unparsable items. 53 | *

54 | * The basic format is "[Type]:[Data], [Amount], 55 | * [Enchantment:Level...], [Meta]" 56 | * 57 | * @param string String to parse 58 | * @return ItemStack from given string, unless parsing fails 59 | * @throws NullPointerException if the material is null 60 | * @throws IllegalArgumentException if the amount is less than 1 61 | * @throws IndexOutOfBoundsException if the string is in an improper format 62 | */ 63 | public static ItemStack readItem(String string) 64 | { 65 | if (string.startsWith("potion:")) 66 | return readPotion(string); 67 | 68 | String materialStr = string, amountStr = ""; 69 | Map enchants = new HashMap<>(); 70 | 71 | string = string.replaceAll("\\s", ""); 72 | if (string.contains(",")) 73 | { 74 | String[] split = string.split(","); 75 | 76 | materialStr = split[0]; 77 | amountStr = split[1]; 78 | 79 | for (int i = 2; i < split.length; i++) 80 | { 81 | String[] enchSplit = split[i].split(":"); 82 | 83 | Enchantment enchant = EnchantmentType.toEnchantment(enchSplit[0]); 84 | int level = NumberUtil.toInt(enchSplit[1]); 85 | 86 | if (enchant != null && level > 0) 87 | { 88 | enchants.put(enchant, level); 89 | } 90 | } 91 | } 92 | 93 | short data = 0; 94 | if (materialStr.contains(":")) 95 | { 96 | String[] split = materialStr.split(":"); 97 | materialStr = split[0]; 98 | 99 | data = NumberUtil.toShort(split[1]); 100 | if (data < 0) 101 | { 102 | throw new IllegalArgumentException("Invalid data: " + split[1]); 103 | } 104 | } 105 | 106 | Material material = Material.matchMaterial(materialStr); 107 | if (material == null) 108 | { 109 | throw new NullPointerException("Invalid material: " + materialStr); 110 | } 111 | 112 | int amount = 1; 113 | if (!amountStr.isEmpty()) 114 | { 115 | amount = NumberUtil.toInt(amountStr); 116 | if (amount <= 0) 117 | { 118 | throw new IllegalArgumentException("Illegal amount: " + amountStr); 119 | } 120 | } 121 | 122 | ItemStack item = new ItemStack(material, amount, data); 123 | item.addUnsafeEnchantments(enchants); 124 | 125 | // Parse meta 126 | parseItemMeta(item, string); 127 | return item; 128 | } 129 | 130 | /** 131 | * Safely reads an item, logging any exceptions. 132 | * 133 | * @param string String to parse 134 | * @param plugin Plugin instance 135 | * @return ItemStack, or null if parsing failed 136 | * @see #readItem(String) 137 | */ 138 | public static ItemStack readItem(String string, SwornPlugin plugin) 139 | { 140 | try 141 | { 142 | return ItemUtil.readItem(string); 143 | } 144 | catch (Throwable ex) 145 | { 146 | plugin.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "parsing item \"" + string + "\"")); 147 | return null; 148 | } 149 | } 150 | 151 | /** 152 | * Safely reads a list of items, logging any exceptions. 153 | * 154 | * @param strings Strings to parse 155 | * @param plugin Plugin instance 156 | * @return List of ItemStacks 157 | * @see #readItem(String) 158 | */ 159 | public static List readItems(List strings, SwornPlugin plugin) 160 | { 161 | List ret = new ArrayList<>(); 162 | for (String string : strings) 163 | { 164 | ItemStack item = readItem(string, plugin); 165 | if (item != null) 166 | ret.add(item); 167 | } 168 | 169 | return ret; 170 | } 171 | 172 | /** 173 | * Parses a potion from configuration. 174 | *

175 | * The basic format is potion: <type>,<amount>,<level>,[splash] 176 | * 177 | * @param string String to read 178 | * @return ItemStack from string, or null if parsing fails 179 | */ 180 | public static ItemStack readPotion(final String string) 181 | { 182 | // Normalize string 183 | String normalized = string.replaceAll("\\s", ""); 184 | normalized = normalized.substring(string.indexOf(":") + 1); 185 | 186 | String[] split = normalized.split(","); 187 | 188 | PotionType type = net.dmulloy2.swornapi.types.PotionType.findPotion(split[0]); 189 | if (type == null) 190 | throw new NullPointerException("Null potion type \"" + split[0] + "\""); 191 | 192 | int amount = NumberUtil.toInt(split[1]); 193 | if (amount < 0) 194 | throw new IllegalArgumentException("Invalid amount " + amount); 195 | 196 | int level = NumberUtil.toInt(split[2]); 197 | if (level < 0) 198 | throw new IllegalArgumentException("Invalid level " + level); 199 | 200 | boolean splash = split.length > 3 && Util.toBoolean(split[3]); 201 | boolean extended = split.length > 4 && Util.toBoolean(split[4]); 202 | 203 | ItemStack potion = CompatUtil.createPotion(type, amount, level, splash, extended); 204 | 205 | // Parse meta 206 | parseItemMeta(potion, normalized); 207 | return potion; 208 | } 209 | 210 | private static final Pattern LORE_MATCHER = Pattern.compile("name:|lore:|color:|owner:|type:"); 211 | 212 | /** 213 | * Parses ItemMeta from a given string, then applies it to a given item. 214 | * @param item Item to apply meta to 215 | * @param string String to parse meta from 216 | */ 217 | public static void parseItemMeta(ItemStack item, String string) 218 | { 219 | if (! LORE_MATCHER.matcher(string).find()) 220 | { 221 | return; 222 | } 223 | 224 | ItemMeta meta = item.getItemMeta(); 225 | if (meta == null) 226 | { 227 | return; 228 | } 229 | 230 | try 231 | { 232 | // Name 233 | String nameKey = "name:"; 234 | if (string.contains(nameKey)) 235 | { 236 | String name = string.substring(string.indexOf(nameKey) + nameKey.length()); 237 | int commaIndex = name.indexOf(","); 238 | if (commaIndex != -1) 239 | name = name.substring(0, commaIndex); 240 | 241 | meta.setDisplayName(FormatUtil.format(name.replace('_', ' '))); 242 | } 243 | 244 | // Lore 245 | String loreKey = "lore:"; 246 | if (string.contains(loreKey)) 247 | { 248 | String str = string.substring(string.indexOf(loreKey) + loreKey.length()); 249 | int commaIndex = str.indexOf(","); 250 | if (commaIndex != -1) 251 | str = str.substring(0, commaIndex); 252 | str = str.replace('_', ' '); 253 | 254 | List lore = new ArrayList<>(); 255 | for (String split : str.split("\\|")) 256 | lore.add(FormatUtil.format(split)); 257 | meta.setLore(lore); 258 | } 259 | 260 | // Leather armor 261 | if (meta instanceof LeatherArmorMeta) 262 | { 263 | String colorKey = "color:"; 264 | if (string.contains(colorKey)) 265 | { 266 | String str = string.substring(string.indexOf(colorKey) + colorKey.length()); 267 | int commaIndex = str.indexOf(","); 268 | if (commaIndex != -1) 269 | str = str.substring(0, commaIndex); 270 | 271 | DyeColor dyeColor = DyeColor.valueOf(str.toUpperCase()); 272 | ((LeatherArmorMeta) meta).setColor(dyeColor.getColor()); 273 | } 274 | } 275 | 276 | // Skulls 277 | if (meta instanceof SkullMeta) 278 | { 279 | String ownerKey = "owner:"; 280 | String typeKey = "type:"; 281 | 282 | if (string.contains(ownerKey)) 283 | { 284 | String owner = string.substring(string.indexOf(ownerKey) + ownerKey.length()); 285 | 286 | // Attempt to use CustomSkullType 287 | CustomSkullType type = CustomSkullType.get(owner); 288 | if (type != null) 289 | ((SkullMeta) meta).setOwner(type.getOwner()); 290 | else 291 | ((SkullMeta) meta).setOwner(owner); 292 | } 293 | else if (string.contains(typeKey)) 294 | { 295 | String type = string.substring(string.indexOf(typeKey) + typeKey.length()); 296 | 297 | // Attempt to use CustomSkullType 298 | CustomSkullType customType = CustomSkullType.get(type); 299 | ((SkullMeta) meta).setOwner(customType.getOwner()); 300 | } 301 | } 302 | 303 | // TODO: Firework and Book support 304 | item.setItemMeta(meta); 305 | } catch (Throwable ignored) { } 306 | } 307 | 308 | /** 309 | * Serializes a given ItemStack in the same format as 310 | * {@link ItemUtil#readItem(String)}. 311 | * 312 | * @param stack Stack to serialize 313 | * @return Serialized string 314 | */ 315 | public static String serialize(ItemStack stack) 316 | { 317 | StringBuilder ret = new StringBuilder(); 318 | ret.append(stack.getType()); 319 | if (stack.getDurability() > 0) 320 | ret.append(":").append(stack.getDurability()); 321 | ret.append(", ").append(stack.getAmount()); 322 | 323 | if (! stack.getEnchantments().isEmpty()) 324 | { 325 | StringJoiner joiner = new StringJoiner(", "); 326 | for (Entry ench : stack.getEnchantments().entrySet()) 327 | joiner.append(EnchantmentType.toName(ench.getKey()) + ":" + ench.getValue()); 328 | ret.append(", ").append(joiner); 329 | } 330 | 331 | ItemMeta meta = stack.getItemMeta(); 332 | if (meta == null) 333 | { 334 | return ret.toString(); 335 | } 336 | 337 | if (meta.hasDisplayName()) 338 | { 339 | ret.append(", name:").append(meta.getDisplayName() 340 | .replace(ChatColor.COLOR_CHAR, '&') 341 | .replace(' ', '_')); 342 | } 343 | 344 | if (meta.hasLore()) 345 | { 346 | StringJoiner lore = new StringJoiner("|"); 347 | for (String line : meta.getLore()) 348 | { 349 | lore.append(line 350 | .replace(ChatColor.COLOR_CHAR, '&') 351 | .replace(' ', '_')); 352 | } 353 | 354 | ret.append(", lore:").append(lore.toString()); 355 | } 356 | 357 | // TODO: More meta support 358 | 359 | return ret.toString(); 360 | } 361 | 362 | /** 363 | * Returns an ItemStack's enchantments in string form. 364 | * 365 | * @param stack ItemStack to get enchantments 366 | * @return The item's enchantments in string form 367 | */ 368 | public static String getEnchantments(ItemStack stack) 369 | { 370 | StringBuilder ret = new StringBuilder(); 371 | if (! stack.getEnchantments().isEmpty()) 372 | { 373 | ret.append("("); 374 | for (Entry enchantment : stack.getEnchantments().entrySet()) 375 | ret.append(EnchantmentType.toName(enchantment.getKey())).append(": ").append(enchantment.getValue()) 376 | .append(", "); 377 | ret.delete(ret.lastIndexOf(","), ret.lastIndexOf(" ")); 378 | ret.append(")"); 379 | } 380 | 381 | return ret.toString(); 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/ListUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.util.*; 21 | 22 | import org.apache.commons.lang.Validate; 23 | 24 | /** 25 | * Util dealing with Lists. 26 | * 27 | * @author dmulloy2 28 | */ 29 | 30 | public class ListUtil 31 | { 32 | private ListUtil() { } 33 | 34 | private static final Object EMPTY = new Object(); 35 | 36 | /** 37 | * Removes duplicate entries from a {@link List}. Retains order. 38 | * 39 | * @param list List to remove duplicate entries from 40 | * @return The list, without duplicate entries 41 | */ 42 | public static List removeDuplicates(List list) 43 | { 44 | Validate.notNull(list, "list cannot be null!"); 45 | 46 | Map map = new LinkedHashMap<>(); 47 | for (T element : list) 48 | map.put(element, EMPTY); 49 | 50 | return new ArrayList<>(map.keySet()); 51 | } 52 | 53 | /** 54 | * Constructs a new {@link List} paramaterized with T. 55 | * 56 | * @param elements Array of T to create the list with 57 | * @return a new {@link List} from the given objects 58 | */ 59 | @SafeVarargs 60 | public static List toList(T... elements) 61 | { 62 | Validate.notNull(elements, "elements cannot be null!"); 63 | 64 | List list = new ArrayList<>(elements.length); 65 | list.addAll(Arrays.asList(elements)); 66 | 67 | return list; 68 | } 69 | 70 | /** 71 | * Whether or not a list contains a String, ignoring case. 72 | * @param list List to check 73 | * @param string String to check for 74 | * @return Whether or not the list contains the given String 75 | */ 76 | public static boolean containsIgnoreCase(List list, String string) 77 | { 78 | Validate.notNull(list, "list cannot be null!"); 79 | Validate.notNull(string, "string cannot be null!"); 80 | 81 | for (String element : list) 82 | { 83 | if (string.equalsIgnoreCase(element)) 84 | return true; 85 | } 86 | 87 | return false; 88 | } 89 | 90 | /** 91 | * Removes a given String element from a list, ignoring case. 92 | * @param list List to remove from 93 | * @param string String to remove 94 | */ 95 | public static void removeIgnoreCase(List list, String string) 96 | { 97 | Validate.notNull(list, "list cannot be null!"); 98 | Validate.notNull(string, "string cannot be null!"); 99 | 100 | list.removeIf(string::equalsIgnoreCase); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/MaterialUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | import org.bukkit.Bukkit; 26 | import org.bukkit.Material; 27 | import org.bukkit.inventory.ItemStack; 28 | import org.bukkit.material.MaterialData; 29 | 30 | /** 31 | * Utility class for dealing with Materials. 32 | * 33 | * @author dmulloy2 34 | */ 35 | 36 | public class MaterialUtil 37 | { 38 | private MaterialUtil() { } 39 | 40 | /** 41 | * Gets the friendly name of a Material. 42 | * 43 | * @param material Material to get the name of 44 | * @return The name 45 | */ 46 | public static String getName(Material material) 47 | { 48 | if (material == null) 49 | return "null"; 50 | 51 | return FormatUtil.getFriendlyName(material); 52 | } 53 | 54 | /** 55 | * Gets the friendly name of an ItemStack. 56 | * 57 | * @param stack Stack to get the name of 58 | * @return The name 59 | */ 60 | public static String getName(ItemStack stack) 61 | { 62 | if (stack == null) 63 | return "null"; 64 | 65 | return getName(stack.getType()); 66 | } 67 | 68 | /** 69 | * Gets the friendly name of an Item or Material. 70 | * @param string String to parse 71 | * @return The name, or {@code -string} if parsing fails 72 | */ 73 | public static String getName(String string) 74 | { 75 | try 76 | { 77 | ItemStack stack = ItemUtil.readItem(string); 78 | return getName(stack); 79 | } catch (Throwable ignored) { } 80 | 81 | return "-" + string; 82 | } 83 | 84 | /** 85 | * Converts a list of strings into a list of Materials. 86 | * 87 | * @param strings List to convert 88 | * @return Converted list 89 | */ 90 | public static List fromStrings(List strings) 91 | { 92 | List ret = new ArrayList<>(); 93 | List invalid = new ArrayList<>(); 94 | 95 | for (String string : strings) 96 | { 97 | Material material = Material.matchMaterial(string); 98 | if (material == null) 99 | invalid.add(string); 100 | else 101 | ret.add(material); 102 | } 103 | 104 | if (!invalid.isEmpty()) 105 | throw new IllegalArgumentException("Invalid materials: " + invalid); 106 | 107 | return ret; 108 | } 109 | 110 | private static Map LEGACY_BY_ID = null; 111 | 112 | /** 113 | * @deprecated It's way past time to migrate from IDs 114 | */ 115 | @Deprecated 116 | private static Material materialFromId(int id) 117 | { 118 | if (LEGACY_BY_ID == null) 119 | { 120 | LEGACY_BY_ID = new HashMap<>(); 121 | 122 | for (Material material : Material.values()) 123 | { 124 | if (material.isLegacy()) 125 | { 126 | LEGACY_BY_ID.put(material.getId(), material); 127 | } 128 | } 129 | } 130 | 131 | return LEGACY_BY_ID.get(id); 132 | } 133 | 134 | /** 135 | * @deprecated Should only be called on the first run when migrating pre 1.13 data/configs 136 | */ 137 | @Deprecated 138 | public static Material convertFromLegacy(String legacyString) 139 | { 140 | String materialName = legacyString; 141 | byte magicData = 0; 142 | 143 | if (legacyString.contains(":")) 144 | { 145 | String[] split = legacyString.split(":"); 146 | materialName = split[0]; 147 | magicData = Byte.parseByte(split[1]); 148 | } 149 | 150 | Material material; 151 | 152 | try 153 | { 154 | int materialId = Integer.parseInt(materialName); 155 | material = materialFromId(materialId); 156 | } 157 | catch (NumberFormatException ex) 158 | { 159 | material = Material.getMaterial(materialName, true); 160 | } 161 | 162 | MaterialData data = new MaterialData(material, magicData); 163 | return Bukkit.getUnsafe().fromLegacy(data); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/NumberUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.text.DecimalFormat; 21 | 22 | /** 23 | * Util for managing Numbers. 24 | * 25 | * @author dmulloy2 26 | */ 27 | 28 | public class NumberUtil 29 | { 30 | private NumberUtil() { } 31 | 32 | /** 33 | * Parses an {@code int} from an Object. 34 | * 35 | * @param object Object to parse 36 | * @return Parsed integer, or -1 if parsing failed 37 | */ 38 | public static int toInt(Object object) 39 | { 40 | if (object instanceof Number) 41 | { 42 | return ((Number) object).intValue(); 43 | } 44 | 45 | try 46 | { 47 | return Integer.parseInt(object.toString()); 48 | } catch (Throwable ignored) { } 49 | return -1; 50 | } 51 | 52 | /** 53 | * Returns whether or not an Object can be parsed as an Integer. 54 | * 55 | * @param object Object to parse 56 | * @return True if it can be parsed, false if not 57 | */ 58 | public static boolean isInt(Object object) 59 | { 60 | try 61 | { 62 | Integer.valueOf(object.toString()); 63 | return true; 64 | } 65 | catch (NumberFormatException ex) 66 | { 67 | return false; 68 | } 69 | } 70 | 71 | /** 72 | * Parses an {@code int} from an Object. 73 | * 74 | * @param object Object to parse 75 | * @return Parsed float, or -1 if parsing failed 76 | */ 77 | public static float toFloat(Object object) 78 | { 79 | if (object instanceof Number) 80 | { 81 | return ((Number) object).floatValue(); 82 | } 83 | 84 | try 85 | { 86 | return Float.parseFloat(object.toString()); 87 | } catch (Throwable ignored) { } 88 | return -1; 89 | } 90 | 91 | /** 92 | * Returns whether or not an Object can be parsed as a Float. 93 | * 94 | * @param object Object to parse 95 | * @return True if it can be parsed, false if not 96 | */ 97 | public static boolean isFloat(Object object) 98 | { 99 | try 100 | { 101 | Float.valueOf(object.toString()); 102 | return true; 103 | } 104 | catch (NumberFormatException ex) 105 | { 106 | return false; 107 | } 108 | } 109 | 110 | /** 111 | * Parses a {@code double} from an Object. 112 | * 113 | * @param object Object to parse 114 | * @return Parsed double, or -1 if parsing failed 115 | */ 116 | public static double toDouble(Object object) 117 | { 118 | if (object instanceof Number) 119 | { 120 | return ((Number) object).doubleValue(); 121 | } 122 | 123 | try 124 | { 125 | return Double.parseDouble(object.toString()); 126 | } catch (Throwable ignored) { } 127 | return -1; 128 | } 129 | 130 | /** 131 | * Returns whether or not an Object can be parsed as a Double 132 | * 133 | * @param object Object to parse 134 | * @return True if it can be parsed, false if not 135 | */ 136 | public static boolean isDouble(Object object) 137 | { 138 | try 139 | { 140 | Double.valueOf(object.toString()); 141 | return true; 142 | } 143 | catch (NumberFormatException ex) 144 | { 145 | return false; 146 | } 147 | } 148 | 149 | /** 150 | * Parses a {@code long} from an Object. 151 | * 152 | * @param object Object to parse 153 | * @return Parsed long, or -1 if parsing failed 154 | */ 155 | public static long toLong(Object object) 156 | { 157 | if (object instanceof Number) 158 | { 159 | return ((Number) object).longValue(); 160 | } 161 | 162 | try 163 | { 164 | return Long.parseLong(object.toString()); 165 | } catch (Throwable ignored) { } 166 | return -1; 167 | } 168 | 169 | /** 170 | * Returns whether or not an Object can be parsed as a Long. 171 | * 172 | * @param object Object to parse 173 | * @return True if it can be parsed, false if not 174 | */ 175 | public static boolean isLong(Object object) 176 | { 177 | try 178 | { 179 | Long.valueOf(object.toString()); 180 | return true; 181 | } 182 | catch (NumberFormatException ex) 183 | { 184 | return false; 185 | } 186 | } 187 | 188 | /** 189 | * Parses a {@code short} from an Object. 190 | * 191 | * @param object Object to parse 192 | * @return Parsed short, or -1 if parsing failed 193 | */ 194 | public static short toShort(Object object) 195 | { 196 | if (object instanceof Number) 197 | { 198 | return ((Number) object).shortValue(); 199 | } 200 | 201 | try 202 | { 203 | return Short.parseShort(object.toString()); 204 | } catch (Throwable ignored) { } 205 | return -1; 206 | } 207 | 208 | /** 209 | * Returns whether or not an Object can be parsed as a Short. 210 | * 211 | * @param object Object to parse 212 | * @return True if it can be parsed, false if not 213 | */ 214 | public static boolean isShort(Object object) 215 | { 216 | try 217 | { 218 | Short.valueOf(object.toString()); 219 | return true; 220 | } 221 | catch (NumberFormatException ex) 222 | { 223 | return false; 224 | } 225 | } 226 | 227 | /** 228 | * Parses an {@code int} from an Object. 229 | * 230 | * @param object Object to parse 231 | * @return Parsed byte, or -1 if parsing failed 232 | */ 233 | public static byte toByte(Object object) 234 | { 235 | if (object instanceof Number) 236 | { 237 | return ((Number) object).byteValue(); 238 | } 239 | 240 | try 241 | { 242 | return Byte.parseByte(object.toString()); 243 | } catch (Throwable ignored) { } 244 | return -1; 245 | } 246 | 247 | /** 248 | * Returns whether or not an Object can be parsed as a Byte. 249 | * 250 | * @param object Object to parse 251 | * @return True if it can be parsed, false if not 252 | */ 253 | public static boolean isByte(Object object) 254 | { 255 | try 256 | { 257 | Byte.valueOf(object.toString()); 258 | return true; 259 | } 260 | catch (NumberFormatException ex) 261 | { 262 | return false; 263 | } 264 | } 265 | 266 | /** 267 | * Returns the given double, rounded to a given number of places. 268 | * 269 | * @param d Double to round 270 | * @param num Places to round to 271 | * @return The given double, rounded to a given number of places 272 | */ 273 | public static double roundNumDecimals(double d, int num) 274 | { 275 | DecimalFormat f = new DecimalFormat("#." + "#".repeat(Math.max(0, num))); 276 | return toDouble(f.format(d)); 277 | } 278 | 279 | /** 280 | * Rounds a given number up to the nearest multiple of another number. 281 | * 282 | * @param number Number to round up 283 | * @param multipleOf Rounds to a multiple of this number 284 | * @return The nearest multiple 285 | */ 286 | public static int roundUp(double number, int multipleOf) 287 | { 288 | return (int) Math.ceil(number / multipleOf) * multipleOf; 289 | } 290 | 291 | /** 292 | * Gets the Roman numeral from a given integer 1 - 10. For other numbers, 293 | * the String representation of the number is returned. 294 | * @param number The number 295 | * @return The numeral 296 | */ 297 | public static String getNumeral(int number) 298 | { 299 | return switch (number) { 300 | case 1 -> "I"; 301 | case 2 -> "II"; 302 | case 3 -> "III"; 303 | case 4 -> "IV"; 304 | case 5 -> "V"; 305 | case 6 -> "VI"; 306 | case 7 -> "VII"; 307 | case 8 -> "VIII"; 308 | case 9 -> "IX"; 309 | case 10 -> "X"; 310 | default -> String.valueOf(number); 311 | }; 312 | } 313 | 314 | /** 315 | * Gets the integer from a given Roman numeral I-X. For other numbers, 316 | * {@link Integer#parseInt(String)} is used. 317 | * @param numeral The Roman numeral 318 | * @return The number 319 | */ 320 | public static int toNumber(String numeral) 321 | { 322 | return switch (numeral) { 323 | case "I" -> 1; 324 | case "II" -> 2; 325 | case "III" -> 3; 326 | case "IV" -> 4; 327 | case "V" -> 5; 328 | case "VI" -> 6; 329 | case "VII" -> 7; 330 | case "VIII" -> 8; 331 | case "IX" -> 9; 332 | case "X" -> 10; 333 | default -> Integer.parseInt(numeral); 334 | }; 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | package net.dmulloy2.swornapi.util; 2 | 3 | import net.dmulloy2.swornapi.handlers.LogHandler; 4 | 5 | import org.bukkit.Bukkit; 6 | 7 | public class ReflectionUtil 8 | { 9 | private static String NMS; 10 | private static String OBC; 11 | 12 | private static boolean initialized; 13 | 14 | private static void initialize() 15 | { 16 | if (! initialized) 17 | { 18 | initialized = true; 19 | 20 | String serverPackage = Bukkit.getServer().getClass().getPackage().getName(); 21 | String version = serverPackage.substring(serverPackage.lastIndexOf('.') + 1); 22 | NMS = "net.minecraft.server." + version + "."; 23 | OBC = "org.bukkit.craftbukkit." + version + "."; 24 | } 25 | } 26 | 27 | public static Class getMinecraftClass(String name) 28 | { 29 | initialize(); 30 | 31 | try 32 | { 33 | return Class.forName(NMS + name); 34 | } 35 | catch (Throwable ex) 36 | { 37 | LogHandler.globalDebug("Could not find Minecraft class {0}", NMS + name); 38 | return null; 39 | } 40 | } 41 | 42 | public static Class getCraftClass(String name) 43 | { 44 | initialize(); 45 | 46 | try 47 | { 48 | return Class.forName(OBC + name); 49 | } 50 | catch (Throwable ex) 51 | { 52 | LogHandler.globalDebug("Could not find CraftBukkit class {0}", NMS + name); 53 | return null; 54 | } 55 | } 56 | 57 | public static Class getMinecraftClass(String name, String... aliases) 58 | { 59 | Class clazz = getMinecraftClass(name); 60 | if (clazz == null) 61 | { 62 | for (String alias : aliases) 63 | { 64 | clazz = getMinecraftClass(alias); 65 | if (clazz != null) 66 | return clazz; 67 | } 68 | } 69 | 70 | return clazz; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.text.DateFormat; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | import java.util.TimeZone; 24 | import java.util.regex.Matcher; 25 | import java.util.regex.Pattern; 26 | 27 | import net.dmulloy2.swornapi.exception.BadTimeException; 28 | 29 | /** 30 | * Util for dealing with time. 31 | * 32 | * @author dmulloy2 33 | */ 34 | 35 | public class TimeUtil 36 | { 37 | private TimeUtil() { } 38 | 39 | /** 40 | * Returns the formatted time difference between two times. 41 | * 42 | * @param time1 First time in milliseconds 43 | * @param time2 Second time in milliseconds 44 | * @return Formatted time difference 45 | */ 46 | public static String formatTimeDifference(long time1, long time2) 47 | { 48 | return formatTime(getTimeDifference(time1, time2)); 49 | } 50 | 51 | /** 52 | * Returns the absolute difference between two times. 53 | * 54 | * @param time1 First time in milliseconds 55 | * @param time2 Second time in milliseconds 56 | * @return Absolute time difference 57 | */ 58 | public static long getTimeDifference(long time1, long time2) 59 | { 60 | return Math.abs(time2 - time1); 61 | } 62 | 63 | /** 64 | * Formats a given time. 65 | * 66 | * @param time Time in milliseconds 67 | * @return Formatted time 68 | */ 69 | public static String formatTime(long time) 70 | { 71 | StringBuilder ret = new StringBuilder(); 72 | int days = (int) Math.floor(time / (1000 * 3600 * 24)); 73 | int hours = (int) Math.floor((time % (1000 * 3600 * 24)) / (1000 * 3600)); 74 | int minutes = (int) Math.floor((time % (1000 * 3600 * 24)) % (1000 * 3600) / (1000 * 60)); 75 | int seconds = (int) Math.floor(time % (1000 * 3600 * 24) % (1000 * 3600) % (1000 * 60) / 1000); 76 | 77 | if (days != 0) 78 | ret.append(days).append("d"); 79 | if (hours != 0 || days != 0) 80 | ret.append(hours).append("h"); 81 | if (minutes != 0 || hours != 0 || days != 0) 82 | ret.append(minutes).append("m"); 83 | ret.append(seconds).append("s"); 84 | 85 | return ret.toString(); 86 | } 87 | 88 | /** 89 | * Gets the current long date in a given time zone. 90 | * 91 | * @param timeZone Time zone, defaults to GMT 92 | * @return The current long date 93 | */ 94 | public static String getLongDateCurr(String timeZone) 95 | { 96 | if (timeZone == null || timeZone.isEmpty()) 97 | timeZone = "GMT"; 98 | 99 | DateFormat dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm"); 100 | Date date = new Date(); 101 | dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone)); 102 | return dateFormat.format(date); 103 | } 104 | 105 | /** 106 | * Gets the current long date in GMT. 107 | * 108 | * @see TimeUtil#getLongDateCurr(String) 109 | */ 110 | public static String getLongDateCurr() 111 | { 112 | return getLongDateCurr("GMT"); 113 | } 114 | 115 | /** 116 | * Gets the current short date in a given time zone. 117 | * 118 | * @param time Time in milliseconds 119 | * @param timeZone Time zone, defaults to GMT 120 | * @return The current short date 121 | */ 122 | public static String getSimpleDate(long time, String timeZone) 123 | { 124 | if (timeZone == null || timeZone.isEmpty()) 125 | timeZone = "GMT"; 126 | 127 | DateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy"); 128 | Date date = new Date(time); 129 | dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone)); 130 | return dateFormat.format(date); 131 | } 132 | 133 | /** 134 | * Gets the simple date of a given time in GMT. 135 | * 136 | * @param time Time in milliseconds 137 | * @see TimeUtil#getSimpleDate(long, String) 138 | */ 139 | public static String getSimpleDate(long time) 140 | { 141 | return getSimpleDate(time, "GMT"); 142 | } 143 | 144 | /** 145 | * Parses a given time. 146 | * 147 | * @param time Time 148 | * @return The parsed time 149 | * @throws BadTimeException If parsing fails 150 | */ 151 | public static long parseTime(String time) throws BadTimeException 152 | { 153 | try 154 | { 155 | if (! time.matches("[0-9]+d[a-z]*")) 156 | return Math.round(Double.parseDouble(time) * 60) * 1000; 157 | else 158 | { 159 | Pattern dayPattern = Pattern.compile("([0-9]+)d[a-z]*", Pattern.CASE_INSENSITIVE); 160 | Matcher m = dayPattern.matcher(time); 161 | 162 | if (m.matches()) 163 | { 164 | return Integer.parseInt(m.group(1)) * 24 * 60 * 60 * 1000; 165 | } 166 | } 167 | } 168 | catch (NumberFormatException ex) 169 | { 170 | Pattern hourPattern = Pattern.compile("([0-9]+)h[a-z]*", Pattern.CASE_INSENSITIVE); 171 | Pattern minPattern = Pattern.compile("([0-9]+)m[a-z]*", Pattern.CASE_INSENSITIVE); 172 | Pattern secPattern = Pattern.compile("([0-9]+)s[a-z]*", Pattern.CASE_INSENSITIVE); 173 | 174 | Matcher m = hourPattern.matcher(time); 175 | 176 | if (m.matches()) 177 | { 178 | return Integer.parseInt(m.group(1)) * 60 * 60 * 1000; 179 | } 180 | 181 | m = minPattern.matcher(time); 182 | 183 | if (m.matches()) 184 | { 185 | return Integer.parseInt(m.group(1)) * 60 * 1000; 186 | } 187 | 188 | m = secPattern.matcher(time); 189 | 190 | if (m.matches()) 191 | { 192 | return Integer.parseInt(m.group(1)) * 1000; 193 | } 194 | } 195 | catch (Throwable ex) 196 | { 197 | throw new BadTimeException("Failed to parse time", ex); 198 | } 199 | 200 | // Message for backwards compatibility. 201 | throw new BadTimeException("badtime"); 202 | } 203 | 204 | // ---- Conversion Methods 205 | 206 | public static long toTicks(Number seconds) 207 | { 208 | return seconds.intValue() * 20; 209 | } 210 | 211 | public static int toSeconds(Number ticks) 212 | { 213 | return ticks.intValue() / 20; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/net/dmulloy2/swornapi/util/Util.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SwornAPI - common API for MineSworn and Shadowvolt plugins 3 | * Copyright (C) 2016 dmulloy2 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package net.dmulloy2.swornapi.util; 19 | 20 | import java.net.URLDecoder; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Iterator; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.Map.Entry; 26 | import java.util.Random; 27 | import java.util.UUID; 28 | 29 | import net.dmulloy2.swornapi.types.StringJoiner; 30 | 31 | import org.apache.commons.lang.Validate; 32 | import org.bukkit.Bukkit; 33 | import org.bukkit.Effect; 34 | import org.bukkit.Location; 35 | import org.bukkit.OfflinePlayer; 36 | import org.bukkit.entity.Player; 37 | 38 | /** 39 | * General utility class. 40 | * 41 | * @author dmulloy2 42 | */ 43 | 44 | public class Util 45 | { 46 | private Util() { } 47 | 48 | /** 49 | * Gets the {@link Player} from a given name or {@link UUID}. 50 | * 51 | * @param identifier Player name or UUID 52 | * @return Player from the given name or UUID, or null if none exists. 53 | * @see Bukkit#getPlayer(UUID) 54 | * @see Bukkit#getPlayer(String) 55 | */ 56 | public static Player matchPlayer(String identifier) 57 | { 58 | Validate.notNull(identifier, "identifier cannot be null!"); 59 | 60 | // First, get by UUID 61 | if (identifier.length() == 36) 62 | return Bukkit.getPlayer(UUID.fromString(identifier)); 63 | 64 | // Last, get by name 65 | return Bukkit.getPlayer(identifier); 66 | } 67 | 68 | /** 69 | * Gets the {@link OfflinePlayer} from a given name or {@link UUID}.
70 | * This method is potentially blocking, especially when using names. 71 | * 72 | * @param identifier Player name or UUID 73 | * @return OfflinePlayer from the given name or UUID, or null if none exists 74 | * @see #matchPlayer(String) 75 | * @see Bukkit#getOfflinePlayer(UUID) 76 | * @see Bukkit#getOfflinePlayer(String) 77 | */ 78 | @SuppressWarnings("deprecation") // Bukkit#getOfflinePlayer(String) 79 | public static OfflinePlayer matchOfflinePlayer(String identifier) 80 | { 81 | Validate.notNull(identifier, "identifier cannot be null!"); 82 | 83 | // First, check online players 84 | Player player = matchPlayer(identifier); 85 | if (player != null) 86 | return player; 87 | 88 | // Then, check UUID 89 | if (identifier.length() == 36) 90 | return Bukkit.getOfflinePlayer(UUID.fromString(identifier)); 91 | 92 | // Last, get by name 93 | return Bukkit.getOfflinePlayer(identifier); 94 | } 95 | 96 | /** 97 | * Gets a list of currently online Players. 98 | * 99 | * @return A list of currently online Players 100 | */ 101 | @SuppressWarnings("unchecked") 102 | public static List getOnlinePlayers() 103 | { 104 | return (List) Bukkit.getOnlinePlayers(); 105 | } 106 | 107 | /** 108 | * Plays an effect to all online players. 109 | * 110 | * @param effect Effect type to play 111 | * @param loc Location where the effect should be played 112 | * @param data Effect data, can be null 113 | * @see Player#playEffect(Location, Effect, Object) 114 | */ 115 | public static void playEffect(Effect effect, Location loc, T data) 116 | { 117 | Validate.notNull(effect, "effect cannot be null!"); 118 | Validate.notNull(loc, "loc cannot be null!"); 119 | 120 | for (Player player : getOnlinePlayers()) 121 | { 122 | if (player.getWorld().equals(loc.getWorld())) 123 | player.playEffect(loc, effect, data); 124 | } 125 | } 126 | 127 | /** 128 | * Whether or not two locations share the same coordinates.
129 | * This method does not take pitch or yaw into account. 130 | * 131 | * @param first First location 132 | * @param second Second location 133 | * @return True if they share coordinates, false if not. 134 | */ 135 | public static boolean coordsEqual(Location first, Location second) 136 | { 137 | Validate.notNull(first, "first location cannot be null!"); 138 | Validate.notNull(second, "second location cannot be null!"); 139 | 140 | return first.equals(second) || first.getBlock().equals(second.getBlock()); 141 | } 142 | 143 | /** 144 | * Converts a {@link Location} to a String for debugging purposes. 145 | * 146 | * @param loc Location to convert 147 | * @return String for debugging purposes 148 | */ 149 | public static String locationToString(Location loc) 150 | { 151 | Validate.notNull(loc, "loc cannot be null!"); 152 | 153 | return "Location[world=" + loc.getWorld().getName() + 154 | ", x=" + loc.getBlockX() + 155 | ", y=" + loc.getBlockY() + 156 | ", z=" + loc.getBlockZ() + "]"; 157 | } 158 | 159 | private static Random random; 160 | 161 | /** 162 | * Returns a pseudorandom integer out of x. 163 | * 164 | * @param x Integer the random should be out of 165 | * @return A random integer out of x. 166 | * @throws IllegalArgumentException if x is less than 0. 167 | */ 168 | public static int random(int x) 169 | { 170 | Validate.isTrue(x > 0, "x cannot be negative!"); 171 | 172 | if (random == null) 173 | random = new Random(); 174 | 175 | return random.nextInt(x); 176 | } 177 | 178 | private static void appendStackTrace(Throwable ex, StringJoiner joiner) 179 | { 180 | for (StackTraceElement ste : ex.getStackTrace()) 181 | { 182 | String className = ste.getClassName(); 183 | if (! className.contains("net.minecraft")) 184 | { 185 | StringBuilder line = new StringBuilder(); 186 | line.append("\t").append(className).append(".").append(ste.getMethodName()); 187 | if (ste.getLineNumber() > 0) 188 | line.append("(Line ").append(ste.getLineNumber()).append(")"); 189 | else 190 | line.append("(Native Method)"); 191 | 192 | String jar = getWorkingJar(className); 193 | if (jar != null) 194 | line.append(" [").append(jar).append("]"); 195 | 196 | joiner.append(line.toString()); 197 | } 198 | } 199 | } 200 | 201 | /** 202 | * Returns a useful Stack Trace for debugging purposes. 203 | * 204 | * @param ex {@link Throwable} to get the stack trace for 205 | * @param circumstance Circumstance in which the Throwable was thrown 206 | * @param args Arguments to format into circumstance 207 | */ 208 | public static String getUsefulStack(Throwable ex, String circumstance, Object... args) 209 | { 210 | Validate.notNull(ex, "ex cannot be null!"); 211 | 212 | StringJoiner joiner = new StringJoiner("\n"); 213 | circumstance = circumstance != null ? FormatUtil.format(" while " + circumstance, args) : ""; 214 | joiner.append("Encountered an exception" + circumstance + ": " + ex.toString()); 215 | joiner.append("Affected classes:"); 216 | 217 | appendStackTrace(ex, joiner); 218 | 219 | while (ex.getCause() != null) 220 | { 221 | ex = ex.getCause(); 222 | joiner.append("Caused by: " + ex.toString()); 223 | joiner.append("Affected classes:"); 224 | appendStackTrace(ex, joiner); 225 | } 226 | 227 | return joiner.toString(); 228 | } 229 | 230 | /** 231 | * Gets the current thread's stack. 232 | * 233 | * @return The current thread's stack 234 | */ 235 | public static String getThreadStack() 236 | { 237 | try 238 | { 239 | throw new Exception("Thread Stack"); 240 | } 241 | catch (Exception ex) 242 | { 243 | return getUsefulStack(ex, null); 244 | } 245 | } 246 | 247 | /** 248 | * Gets the working jar of a given Class. This is the same as 249 | * {@link #getWorkingJar(Class)}, but the class name is passed through 250 | * {@link Class#forName(String)} first. 251 | * 252 | * @param clazzName Class name 253 | * @return The working jar, or null if not found 254 | */ 255 | public static String getWorkingJar(String clazzName) 256 | { 257 | try 258 | { 259 | return getWorkingJar(Class.forName(clazzName)); 260 | } catch (Throwable ignored) { } 261 | return null; 262 | } 263 | 264 | /** 265 | * Gets the working jar of a given {@link Class}. 266 | * 267 | * @param clazz Class to get the jar for 268 | * @return The working jar, or null if not found 269 | */ 270 | public static String getWorkingJar(Class clazz) 271 | { 272 | try 273 | { 274 | String path = clazz.getProtectionDomain().getCodeSource().getLocation().getPath(); 275 | path = URLDecoder.decode(path, StandardCharsets.UTF_8); 276 | path = path.substring(path.lastIndexOf("/") + 1); 277 | return ! path.isEmpty() ? path : null; 278 | } catch (Throwable ignored) { } 279 | return null; 280 | } 281 | 282 | /** 283 | * Filters duplicate entries from a {@link Map} according to the original 284 | * map. 285 | * 286 | * @param map {@link Map} to filter 287 | * @param original Original map 288 | * @return Filtered map 289 | */ 290 | public static Map filterDuplicateEntries(Map map, Map original) 291 | { 292 | Validate.notNull(map, "map cannot be null!"); 293 | Validate.notNull(original, "original cannot be null!"); 294 | 295 | Iterator> iter = map.entrySet().iterator(); 296 | while (iter.hasNext()) 297 | { 298 | Entry entry = iter.next(); 299 | 300 | K key = entry.getKey(); 301 | if (original.containsKey(key)) 302 | { 303 | V val = entry.getValue(); 304 | V def = original.get(key); 305 | if (val.equals(def)) 306 | iter.remove(); 307 | } 308 | } 309 | 310 | return map; 311 | } 312 | 313 | /** 314 | * Parses a given {@link Object} (preferably a {@link String}) and returns a 315 | * boolean value. 316 | * 317 | * @param object Object to parse 318 | * @return Boolean value from the given object 319 | */ 320 | public static boolean toBoolean(Object object) 321 | { 322 | Validate.notNull(object, "object cannot be null!"); 323 | 324 | if (object instanceof Boolean) 325 | { 326 | return ((Boolean) object); 327 | } 328 | 329 | String str = object.toString(); 330 | return str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1"); 331 | } 332 | } -------------------------------------------------------------------------------- /src/test/java/net/dmulloy2/swornapi/BukkitTesting.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package net.dmulloy2.swornapi; 5 | 6 | import java.util.logging.Logger; 7 | 8 | import net.minecraft.SharedConstants; 9 | import net.minecraft.core.IRegistry; 10 | import net.minecraft.server.DispenserRegistry; 11 | 12 | import org.bukkit.Bukkit; 13 | import org.bukkit.Server; 14 | import org.bukkit.craftbukkit.v1_19_R1.CraftServer; 15 | import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemFactory; 16 | import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers; 17 | import org.bukkit.craftbukkit.v1_19_R1.util.Versioning; 18 | import org.mockito.stubbing.Answer; 19 | 20 | import static org.mockito.Mockito.*; 21 | 22 | /** 23 | * @author dmulloy2 24 | */ 25 | 26 | public class BukkitTesting 27 | { 28 | private static boolean prepared; 29 | private static String fakeVersion; 30 | 31 | public static void prepare() 32 | { 33 | if (! prepared) 34 | { 35 | prepared = true; 36 | 37 | System.setProperty("swornapi.debug", "true"); 38 | 39 | SharedConstants.a(); 40 | DispenserRegistry.a(); // Basically registers everything 41 | 42 | try { 43 | IRegistry.class.getName(); 44 | } catch (Throwable ex) { 45 | ex.printStackTrace(); 46 | } 47 | 48 | // Mock the server object 49 | Server mockedServer = mock(Server.class); 50 | 51 | when(mockedServer.getLogger()).thenReturn(Logger.getLogger("Minecraft")); 52 | when(mockedServer.getName()).thenReturn("Mock Server"); 53 | when(mockedServer.getVersion()).thenReturn(CraftServer.class.getPackage().getImplementationVersion()); 54 | when(mockedServer.getBukkitVersion()).thenAnswer( 55 | (Answer) invocation -> fakeVersion != null ? fakeVersion : Versioning.getBukkitVersion()); 56 | when(mockedServer.getUnsafe()).thenReturn(CraftMagicNumbers.INSTANCE); 57 | 58 | when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance()); 59 | when(mockedServer.isPrimaryThread()).thenReturn(true); 60 | 61 | // Inject this fake server 62 | Bukkit.setServer(mockedServer); 63 | } 64 | } 65 | 66 | public static void setBukkitVersion(String version) 67 | { 68 | fakeVersion = version; 69 | } 70 | 71 | public static void resetBukkitVersion() 72 | { 73 | setBukkitVersion(null); 74 | } 75 | } -------------------------------------------------------------------------------- /src/test/java/net/dmulloy2/swornapi/config/ConfigTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package net.dmulloy2.swornapi.config; 5 | 6 | import static org.junit.Assert.*; 7 | import static org.mockito.Mockito.mock; 8 | import static org.mockito.Mockito.when; 9 | 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.util.List; 13 | import java.util.logging.Logger; 14 | 15 | import net.dmulloy2.swornapi.BukkitTesting; 16 | import net.dmulloy2.swornapi.SwornPlugin; 17 | import net.dmulloy2.swornapi.handlers.LogHandler; 18 | import net.dmulloy2.swornapi.util.ListUtil; 19 | 20 | import org.bukkit.ChatColor; 21 | import org.bukkit.Material; 22 | import org.bukkit.configuration.file.YamlConfiguration; 23 | import org.bukkit.enchantments.Enchantment; 24 | import org.bukkit.inventory.ItemStack; 25 | import org.bukkit.inventory.meta.PotionMeta; 26 | import org.bukkit.potion.PotionData; 27 | import org.bukkit.potion.PotionType; 28 | import org.junit.BeforeClass; 29 | import org.junit.Test; 30 | 31 | import com.google.common.base.Charsets; 32 | import com.google.common.io.Resources; 33 | 34 | /** 35 | * @author dmulloy2 36 | */ 37 | 38 | public class ConfigTest 39 | { 40 | @BeforeClass 41 | public static void beforeClass() throws Throwable 42 | { 43 | BukkitTesting.prepare(); 44 | 45 | SwornPlugin plugin = mock(SwornPlugin.class); 46 | when(plugin.getLogHandler()).thenReturn(new LogHandler(plugin, Logger.getGlobal())); 47 | 48 | // Mock the config 49 | YamlConfiguration config = new YamlConfiguration(); 50 | InputStream stream = Resources.getResource("config.yml").openStream(); 51 | InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8); 52 | config.load(reader); 53 | 54 | when(plugin.getConfig()).thenReturn(config); 55 | 56 | ConfigParser.parse(plugin, Config.class); 57 | } 58 | 59 | @Test 60 | public void testStrings() 61 | { 62 | assertEquals(Config.string, "succeeded"); 63 | } 64 | 65 | @Test 66 | public void testMaterial() 67 | { 68 | assertEquals(Config.material, Material.GOLDEN_APPLE); 69 | } 70 | 71 | @Test 72 | public void testMaterials() 73 | { 74 | assertEquals(Config.materials, ListUtil.toList(Material.GOLDEN_APPLE, Material.DIAMOND_BLOCK)); 75 | } 76 | 77 | @Test 78 | public void testItems() 79 | { 80 | assertNotNull(Config.items); 81 | assertEquals(Config.items.size(), 4); 82 | 83 | ItemStack sword = Config.items.get(0); 84 | assertEquals(sword.getType(), Material.DIAMOND_SWORD); 85 | assertEquals(sword.getAmount(), 1); 86 | assertTrue(sword.getEnchantments().containsKey(Enchantment.DAMAGE_ALL)); 87 | assertTrue(sword.getEnchantments().containsKey(Enchantment.DURABILITY)); 88 | assertTrue(sword.getEnchantments().containsKey(Enchantment.FIRE_ASPECT)); 89 | assertNotNull(sword.getItemMeta()); 90 | assertEquals(sword.getItemMeta().getDisplayName(), ChatColor.DARK_RED.toString() + ChatColor.BOLD.toString() + "Oathbreaker"); 91 | 92 | ItemStack apple = Config.items.get(1); 93 | assertEquals(apple.getType(), Material.GOLDEN_APPLE); 94 | assertEquals(apple.getAmount(), 2); 95 | 96 | ItemStack flint = Config.items.get(2); 97 | assertEquals(flint.getType(), Material.FLINT_AND_STEEL); 98 | assertEquals(flint.getAmount(), 1); 99 | 100 | ItemStack potion = Config.items.get(3); 101 | assertEquals(potion.getType(), Material.POTION); 102 | assertEquals(potion.getAmount(), 2); 103 | assertNotNull(potion.getItemMeta()); 104 | 105 | PotionData data = ((PotionMeta) potion.getItemMeta()).getBasePotionData(); 106 | assertEquals(data.getType(), PotionType.SPEED); 107 | assertFalse(data.isUpgraded()); 108 | assertTrue(data.isExtended()); 109 | } 110 | 111 | private static class Config 112 | { 113 | @Key("string") 114 | public static String string = "failed"; 115 | 116 | @Key("material") 117 | @ValueOptions(ValueOptions.ValueOption.PARSE_MATERIAL) 118 | public static Material material = Material.ROTTEN_FLESH; 119 | 120 | @Key("materials") 121 | @ValueOptions(ValueOptions.ValueOption.PARSE_MATERIALS) 122 | public static List materials = ListUtil.toList(Material.ROTTEN_FLESH); 123 | 124 | @Key("items") 125 | @ValueOptions(ValueOptions.ValueOption.PARSE_ITEMS) 126 | public static List items = ListUtil.toList(new ItemStack(Material.ROTTEN_FLESH)); 127 | } 128 | } -------------------------------------------------------------------------------- /src/test/java/net/dmulloy2/swornapi/types/VersioningTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package net.dmulloy2.swornapi.types; 5 | 6 | import static org.junit.Assert.assertFalse; 7 | import static org.junit.Assert.assertTrue; 8 | 9 | import net.dmulloy2.swornapi.BukkitTesting; 10 | 11 | import org.junit.BeforeClass; 12 | import org.junit.Test; 13 | 14 | /** 15 | * @author dmulloy2 16 | */ 17 | 18 | public class VersioningTest 19 | { 20 | @BeforeClass 21 | public static void beforeClass() 22 | { 23 | BukkitTesting.prepare(); 24 | } 25 | 26 | @Test 27 | public void testSupported() 28 | { 29 | Versioning.setVersion(null); 30 | // assertEquals(Versioning.getVersion(), Version.MC_111); 31 | assertTrue(Versioning.isSupported()); 32 | } 33 | 34 | @Test 35 | public void testUnsupported() 36 | { 37 | Versioning.setVersion(null); 38 | BukkitTesting.setBukkitVersion("4.2.0-R6.9-SNAPSHOT"); 39 | assertFalse(Versioning.isSupported()); 40 | BukkitTesting.resetBukkitVersion(); 41 | } 42 | 43 | @Test 44 | public void testDropped() 45 | { 46 | Versioning.setVersion(null); 47 | BukkitTesting.setBukkitVersion("1.7.10-R0.1-SNAPSHOT"); 48 | assertTrue(Versioning.getVersion().wasDropped()); 49 | assertFalse(Versioning.isSupported()); 50 | BukkitTesting.resetBukkitVersion(); 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/resources/config.yml: -------------------------------------------------------------------------------- 1 | string: "succeeded" 2 | 3 | material: "golden_apple" 4 | 5 | materials: 6 | - "golden_apple" 7 | - "diamond_block" 8 | 9 | items: 10 | - "diamond_sword, 1, sharp:5, dura:3, fireaspect:2, name:&4&lOathbreaker" 11 | - "golden_apple, 2" 12 | - "flint_and_steel" 13 | - "potion: speed, 2, 1, false, true" --------------------------------------------------------------------------------