From 23c03207dc7ba2f632bd3baab1ce177b651aa6a7 Mon Sep 17 00:00:00 2001 From: Esophose Date: Thu, 22 Sep 2016 17:16:52 -0600 Subject: [PATCH 1/3] Update to v4 Add Styles API, refactor some things, make things more efficient --- src/com/esophose/playerparticles/PPlayer.java | 123 ++ .../ParticleCommandCompleter.java | 27 +- .../ParticleCommandExecutor.java | 467 ++++-- .../playerparticles/ParticleCreator.java | 537 +----- .../playerparticles/ParticleStyle.java | 35 - .../playerparticles/ParticlesUtil.java | 23 + .../playerparticles/PlayerParticles.java | 100 +- .../libraries/particles/ParticleEffect.java | 431 ----- .../library/{database => }/Database.java | 48 +- .../playerparticles/library/MySQL.java | 64 + .../library/ParticleEffect.java | 1474 +++++++++++++++++ .../library/ReflectionUtils.java | 659 ++++++++ .../library/database/MySQL.java | 78 - .../manager/ConfigManager.java | 445 +++-- .../manager/MessageManager.java | 43 +- .../manager/PermissionManager.java | 65 +- .../playerparticles/styles/DefaultStyles.java | 36 + .../styles/ParticleStyleFeet.java | 23 + .../styles/ParticleStyleHalo.java | 40 + .../styles/ParticleStyleMove.java | 36 + .../styles/ParticleStyleNone.java | 125 ++ .../styles/ParticleStyleOrbit.java | 35 + .../styles/ParticleStylePoint.java | 22 + .../styles/ParticleStyleQuadhelix.java | 44 + .../styles/ParticleStyleSpin.java | 35 + .../styles/ParticleStyleSpiral.java | 39 + .../playerparticles/styles/api/PParticle.java | 98 ++ .../styles/api/ParticleStyle.java | 23 + .../styles/api/ParticleStyleManager.java | 72 + .../updater/PluginUpdateListener.java | 6 +- .../playerparticles/updater/Updater.java | 1362 +++++++-------- src/config.yml | 151 +- src/plugin.yml | 4 +- 33 files changed, 4654 insertions(+), 2116 deletions(-) create mode 100644 src/com/esophose/playerparticles/PPlayer.java delete mode 100644 src/com/esophose/playerparticles/ParticleStyle.java create mode 100644 src/com/esophose/playerparticles/ParticlesUtil.java delete mode 100644 src/com/esophose/playerparticles/libraries/particles/ParticleEffect.java rename src/com/esophose/playerparticles/library/{database => }/Database.java (65%) create mode 100644 src/com/esophose/playerparticles/library/MySQL.java create mode 100644 src/com/esophose/playerparticles/library/ParticleEffect.java create mode 100644 src/com/esophose/playerparticles/library/ReflectionUtils.java delete mode 100644 src/com/esophose/playerparticles/library/database/MySQL.java create mode 100644 src/com/esophose/playerparticles/styles/DefaultStyles.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleFeet.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleHalo.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleMove.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleNone.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleOrbit.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStylePoint.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleSpin.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleSpiral.java create mode 100644 src/com/esophose/playerparticles/styles/api/PParticle.java create mode 100644 src/com/esophose/playerparticles/styles/api/ParticleStyle.java create mode 100644 src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java diff --git a/src/com/esophose/playerparticles/PPlayer.java b/src/com/esophose/playerparticles/PPlayer.java new file mode 100644 index 0000000..80d55b1 --- /dev/null +++ b/src/com/esophose/playerparticles/PPlayer.java @@ -0,0 +1,123 @@ +package com.esophose.playerparticles; + +import java.util.UUID; + +import org.bukkit.Material; + +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.library.ParticleEffect.BlockData; +import com.esophose.playerparticles.library.ParticleEffect.ItemData; +import com.esophose.playerparticles.library.ParticleEffect.NoteColor; +import com.esophose.playerparticles.library.ParticleEffect.OrdinaryColor; +import com.esophose.playerparticles.library.ParticleEffect.ParticleColor; +import com.esophose.playerparticles.library.ParticleEffect.ParticleData; +import com.esophose.playerparticles.library.ParticleEffect.ParticleProperty; +import com.esophose.playerparticles.styles.DefaultStyles; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class PPlayer { + + private final UUID playerUUID; + + private ParticleEffect particleEffect; + private ParticleStyle particleStyle; + + private ItemData particleItemData; + private BlockData particleBlockData; + private OrdinaryColor particleColorData; + private NoteColor particleNoteColorData; + + public PPlayer(UUID uuid, ParticleEffect effect, ParticleStyle style, ItemData itemData, BlockData blockData, OrdinaryColor colorData, NoteColor noteColorData) { + this.playerUUID = uuid; + this.particleEffect = effect; + this.particleStyle = style; + this.particleItemData = itemData; + this.particleBlockData = blockData; + this.particleColorData = colorData; + this.particleNoteColorData = noteColorData; + } + + public UUID getUniqueId() { + return this.playerUUID; + } + + public ParticleEffect getParticleEffect() { + return this.particleEffect; + } + + public ParticleStyle getParticleStyle() { + return this.particleStyle; + } + + public ItemData getItemData() { + return this.particleItemData; + } + + public BlockData getBlockData() { + return this.particleBlockData; + } + + public OrdinaryColor getColorData() { + return this.particleColorData; + } + + public NoteColor getNoteColorData() { + return this.particleNoteColorData; + } + + public void setParticleEffect(ParticleEffect effect) { + this.particleEffect = effect; + } + + public void setParticleStyle(ParticleStyle style) { + this.particleStyle = style; + } + + public void setItemData(ItemData itemData) { + this.particleItemData = itemData; + } + + public void setBlockData(BlockData blockData) { + this.particleBlockData = blockData; + } + + public void setColorData(OrdinaryColor colorData) { + this.particleColorData = colorData; + } + + public void setNoteColorData(NoteColor noteColorData) { + this.particleNoteColorData = noteColorData; + } + + public ParticleData getParticleSpawnData() { + if (particleEffect.hasProperty(ParticleProperty.REQUIRES_DATA)) { + if (particleEffect == ParticleEffect.BLOCK_CRACK || particleEffect == ParticleEffect.BLOCK_DUST || particleEffect == ParticleEffect.FALLING_DUST) { + return particleBlockData; + } else if (particleEffect == ParticleEffect.ITEM_CRACK) { + return particleItemData; + } + } + return null; + } + + public ParticleColor getParticleSpawnColor() { + if (particleEffect.hasProperty(ParticleProperty.COLORABLE)) { + if (particleEffect == ParticleEffect.NOTE) { + return particleNoteColorData; + } else return particleColorData; + } + return null; + } + + public static PPlayer getNewPPlayer(UUID playerUUID) { + ParticleEffect particleEffect = ParticleEffect.NONE; + ParticleStyle particleStyle = DefaultStyles.NONE; + ItemData particleItemData = new ItemData(Material.IRON_SPADE, (byte) 0); + BlockData particleBlockData = new BlockData(Material.STONE, (byte) 0); + OrdinaryColor particleColorData = new OrdinaryColor(0, 0, 0); + NoteColor particleNoteColorData = new NoteColor(0); + + return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); + } + +} diff --git a/src/com/esophose/playerparticles/ParticleCommandCompleter.java b/src/com/esophose/playerparticles/ParticleCommandCompleter.java index 0607a65..f870013 100644 --- a/src/com/esophose/playerparticles/ParticleCommandCompleter.java +++ b/src/com/esophose/playerparticles/ParticleCommandCompleter.java @@ -8,6 +8,7 @@ package com.esophose.playerparticles; +import java.util.ArrayList; import java.util.List; import org.bukkit.command.Command; @@ -20,7 +21,7 @@ import com.esophose.playerparticles.manager.PermissionManager; public class ParticleCommandCompleter implements TabCompleter { /** - * Activated when a user pushes tab in chat prefixed with /pp + * Activated when a user pushes tab in chat prefixed with /pp * * @param sender The sender that hit tab, should always be a player * @param cmd The command the player is executing @@ -29,18 +30,24 @@ public class ParticleCommandCompleter implements TabCompleter { * @return A list of commands available to the sender */ public List onTabComplete(CommandSender sender, Command cmd, String alias, String[] args) { - if(cmd.getName().equalsIgnoreCase("pp")) { - if(args.length == 1) { - List list = PermissionManager.getParticlesUserHasPermissionFor((Player)sender); - list.add("list"); - list.add("styles"); - list.add("style"); - list.add("version"); - list.add("worlds"); + if (cmd.getName().equalsIgnoreCase("pp")) { + if (args.length == 0) { + List list = new ArrayList(); list.add("help"); + list.add("effect"); + list.add("effects"); + list.add("style"); + list.add("styles"); + list.add("worlds"); + list.add("version"); return list; + } else if (args.length == 1) { + if (args[0].equalsIgnoreCase("effect")) { + return PermissionManager.getParticlesUserHasPermissionFor((Player) sender); + } else if (args[0].equalsIgnoreCase("style")) { + return PermissionManager.getStylesUserHasPermissionFor((Player) sender); + } } - if(args.length == 2) return PermissionManager.getStylesUserHasPermissionFor((Player)sender); } return null; } diff --git a/src/com/esophose/playerparticles/ParticleCommandExecutor.java b/src/com/esophose/playerparticles/ParticleCommandExecutor.java index 13d0ce7..1a479e0 100644 --- a/src/com/esophose/playerparticles/ParticleCommandExecutor.java +++ b/src/com/esophose/playerparticles/ParticleCommandExecutor.java @@ -1,22 +1,30 @@ package com.esophose.playerparticles; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType; +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.library.ParticleEffect.BlockData; +import com.esophose.playerparticles.library.ParticleEffect.ItemData; +import com.esophose.playerparticles.library.ParticleEffect.NoteColor; +import com.esophose.playerparticles.library.ParticleEffect.OrdinaryColor; +import com.esophose.playerparticles.library.ParticleEffect.ParticleProperty; import com.esophose.playerparticles.manager.ConfigManager; import com.esophose.playerparticles.manager.MessageManager; import com.esophose.playerparticles.manager.PermissionManager; +import com.esophose.playerparticles.styles.DefaultStyles; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; public class ParticleCommandExecutor implements CommandExecutor { /** - * Called when a player does a command and continues if the command is /pp - * Executes all the commands and methods - * Does some sorcery + * Called when a player executes a /pp command + * Checks what /pp command it is and calls the correct method * * @param sender Who executed the command * @param cmd The command @@ -25,118 +33,369 @@ public class ParticleCommandExecutor implements CommandExecutor { * @return True if everything went as planned (should always be true) */ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - if(!(sender instanceof Player)) return true; + if (!(sender instanceof Player)) return true; Player p = (Player) sender; - if(args.length == 1 && args[0].equalsIgnoreCase("worlds")) { - String worlds = ""; - if(ConfigManager.getInstance().getDisabledWorlds() == null) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-disabled-worlds-none", null, null), ChatColor.GREEN); + + if (args.length == 0) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-arguments", null) + ChatColor.GREEN + " /pp help", ChatColor.RED); + return true; + } else { + switch (args[0].toLowerCase()) { + case "help": + onHelp(p, args); + break; + case "worlds": + onWorlds(p, args); + break; + case "version": + onVersion(p, args); + break; + case "effect": + onEffect(p, args); + break; + case "effects": + onEffects(p, args); + break; + case "style": + onStyle(p, args); + break; + case "styles": + onStyles(p, args); + break; + case "data": + onData(p, args); + break; + case "reset": + onReset(p, args); + break; + default: + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-arguments", null) + ChatColor.GREEN + " /pp help", ChatColor.RED); } - for(String s : ConfigManager.getInstance().getDisabledWorlds()) { - worlds += s + ", "; - } - if(worlds.length() > 2) worlds = worlds.substring(0, worlds.length() - 2); - if(worlds.equals("")) { - worlds = MessageManager.getMessageFromConfig("message-disabled-worlds-none", null, null); - }else{ - worlds = MessageManager.getMessageFromConfig("message-disabled-worlds", null, null) + " " + ChatColor.AQUA + worlds; - } - MessageManager.getInstance().sendMessage(p, worlds, ChatColor.GREEN); return true; } - if(args.length > 1 && args[0].equalsIgnoreCase("style")) { - String argument = args[1].replace("_", ""); - if(ParticleStyle.styleFromString(argument) != null){ - ParticleStyle style = ParticleStyle.styleFromString(argument); - if(!PermissionManager.hasStylePermission(p, style)) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-permission-style", null, ChatColor.AQUA + style.toString().toLowerCase() + ChatColor.RED), ChatColor.RED); - return true; + } + + /** + * Called when a player uses /pp help + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onHelp(Player p, String[] args) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-available-commands", null), ChatColor.GREEN); + MessageManager.getInstance().sendMessage(p, "effect, effects, style, styles, data, reset, worlds, version, help", ChatColor.AQUA); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp ", ChatColor.YELLOW); + } + + /** + * Called when a player uses /pp worlds + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onWorlds(Player p, String[] args) { + String worlds = ""; + if (ConfigManager.getInstance().getDisabledWorlds() == null) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-disabled-worlds-none", null), ChatColor.GREEN); + } + for (String s : ConfigManager.getInstance().getDisabledWorlds()) { + worlds += s + ", "; + } + if (worlds.length() > 2) worlds = worlds.substring(0, worlds.length() - 2); + if (worlds.equals("")) { + worlds = MessageManager.getMessageFromConfig("message-disabled-worlds-none", null); + } else { + worlds = MessageManager.getMessageFromConfig("message-disabled-worlds", null) + " " + ChatColor.AQUA + worlds; + } + MessageManager.getInstance().sendMessage(p, worlds, ChatColor.GREEN); + } + + /** + * Called when a player uses /pp version + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onVersion(Player p, String[] args) { + MessageManager.getInstance().sendMessage(p, "Running PlayerParticles v" + PlayerParticles.getPlugin().getDescription().getVersion(), ChatColor.GOLD); + MessageManager.getInstance().sendMessage(p, "Plugin created by: Esophose", ChatColor.GOLD); + } + + /** + * Called when a player uses /pp data + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onData(Player p, String[] args) { + ParticleEffect effect = ConfigManager.getInstance().getPPlayer(p.getUniqueId()).getParticleEffect(); + if (args.length == 1) { + if (effect.hasProperty(ParticleProperty.COLORABLE)) { + if (effect == ParticleEffect.NOTE) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-usage", null), ChatColor.YELLOW); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-23>", ChatColor.YELLOW); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-color-data-usage", null), ChatColor.YELLOW); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-255> <0-255> <0-255>", ChatColor.YELLOW); } - ConfigManager.getStyleInstance().setStyle(style, p); - ParticleCreator.addStyleMap(p, style); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-now-using-style", null, ChatColor.AQUA + style.toString().toLowerCase() + ChatColor.GREEN), ChatColor.GREEN); - return true; + } else if (effect.hasProperty(ParticleProperty.REQUIRES_DATA)) { + if (effect == ParticleEffect.ITEM_CRACK) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-usage", null), ChatColor.YELLOW); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-usage", null), ChatColor.YELLOW); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + } + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-data-usage", null), ChatColor.YELLOW); } - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type-style", null, null) + ChatColor.GREEN + " /pp styles", ChatColor.RED); - return true; + return; } - if(args.length != 1){ - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-arguments", null, null) + ChatColor.GREEN + " /pp list", ChatColor.RED); - return true; - } - String argument = args[0].replace("_", ""); - if(ParticleCreator.particleFromString(argument) != null){ - ParticleType effect = ParticleCreator.particleFromString(argument); - if(!PermissionManager.hasPermission(p, effect)){ - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-permission", ChatColor.AQUA + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase() + ChatColor.RED), null), ChatColor.RED); - return true; - } - ConfigManager.getInstance().setParticle(effect, p); - ParticleCreator.addMap(p, effect); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-now-using", ChatColor.AQUA + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase() + ChatColor.GREEN), null), ChatColor.GREEN); - return true; - } - if(argument.equalsIgnoreCase("clear")) { - ConfigManager.getInstance().resetParticle(p); - ParticleCreator.removeMap(p); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-cleared-particles", null, null), ChatColor.GREEN); - return true; - } - if(argument.equalsIgnoreCase("version")) { - MessageManager.getInstance().sendMessage(p, "Running PlayerParticles v" + PlayerParticles.getPlugin().getDescription().getVersion(), ChatColor.GOLD); - MessageManager.getInstance().sendMessage(p, "Plugin created by: Esophose", ChatColor.GOLD); - return true; - } - if(argument.equalsIgnoreCase("help")) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-available-commands", null, null), ChatColor.GREEN); - MessageManager.getInstance().sendMessage(p, "list, styles, style, worlds, version, help", ChatColor.AQUA); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null, null) + ChatColor.AQUA + " /pp ", ChatColor.YELLOW); - return true; - } - if(argument.equalsIgnoreCase("list")) { - String toSend = MessageManager.getMessageFromConfig("message-use", null, null) + " "; - for(ParticleType effect : ParticleType.values()){ - if(PermissionManager.hasPermission(p, effect)){ - toSend = toSend + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase()) + ", "; - continue; + if (effect.hasProperty(ParticleProperty.COLORABLE)) { + if (effect == ParticleEffect.NOTE) { + if (args.length >= 2) { + int note = -1; + try { + note = Integer.parseInt(args[1]); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-23>", ChatColor.YELLOW); + return; + } + + if (note < 0 || note > 23) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-23>", ChatColor.YELLOW); + return; + } + + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), new NoteColor(note)); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-applied", null), ChatColor.GREEN); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-23>", ChatColor.YELLOW); + } + } else { + if (args.length >= 4) { + int r = -1; + int g = -1; + int b = -1; + + try { + r = Integer.parseInt(args[1]); + g = Integer.parseInt(args[2]); + b = Integer.parseInt(args[3]); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-color-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-255> <0-255> <0-255>", ChatColor.YELLOW); + return; + } + + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-color-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-255> <0-255> <0-255>", ChatColor.YELLOW); + return; + } + + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), new OrdinaryColor(r, g, b)); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-color-data-applied", null), ChatColor.GREEN); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-color-data-invalid-arguments", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-255> <0-255> <0-255>", ChatColor.YELLOW); } } - if(toSend.equals(MessageManager.getMessageFromConfig("message-use", null, null) + " ")) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-particles", null, null), ChatColor.RED); - return true; - } - toSend = toSend + "clear"; - MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null, null) + ChatColor.AQUA + " /pp ", ChatColor.YELLOW); - return true; - } - if(argument.equalsIgnoreCase("style")) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type-style", null, null) + ChatColor.GREEN + " /pp styles", ChatColor.RED); - return true; - } - if(argument.equalsIgnoreCase("styles")) { - String toSend = MessageManager.getMessageFromConfig("message-use-style", null, null) + " "; - for(ParticleStyle style : ParticleStyle.values()){ - if(PermissionManager.hasStylePermission(p, style)){ - toSend = toSend + style.toString().toLowerCase(); - toSend += ", "; + } else if (effect.hasProperty(ParticleProperty.REQUIRES_DATA)) { + if (effect == ParticleEffect.ITEM_CRACK) { + Material material = null; + int data = -1; + + try { + material = ParticlesUtil.closestMatch(args[1]); + if (material == null) material = Material.matchMaterial(args[1]); + if (material == null) throw new Exception(); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-unknown", args[1]), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; } + + try { + data = Integer.parseInt(args[2]); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + if (material.isBlock()) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-mismatch", material.name()), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + if (data < 0 || data > 15) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), new ItemData(material, (byte) data)); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-applied", null), ChatColor.GREEN); + } else { + Material material = null; + int data = -1; + + try { + material = ParticlesUtil.closestMatch(args[1]); + if (material == null) material = Material.matchMaterial(args[1]); + if (material == null) throw new Exception(); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-unknown", args[1]), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + try { + data = Integer.parseInt(args[2]); + } catch (Exception e) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + if (!material.isBlock()) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-mismatch", material.name()), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + if (data < 0 || data > 15) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); + return; + } + + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), new BlockData(material, (byte) data)); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-applied", null), ChatColor.GREEN); } - if(toSend.endsWith(", ")) { - toSend = toSend.substring(0, toSend.length() - 2); - } - if(toSend.equals(MessageManager.getMessageFromConfig("message-use-style", null, null) + " " + ParticleStyle.NONE.toString().toLowerCase())) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-styles", null, null), ChatColor.RED); - return true; - } - MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN); - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null, null) + ChatColor.AQUA + " /pp style ", ChatColor.YELLOW); - return true; } - - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type", null, null) + ChatColor.GREEN + " /pp list", ChatColor.RED); - - return true; + } + + /** + * Called when a player uses /pp reset + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onReset(Player p, String[] args) { + ConfigManager.getInstance().saveEntirePPlayer(PPlayer.getNewPPlayer(p.getUniqueId())); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-reset", null), ChatColor.GREEN); + } + + /** + * Called when a player uses /pp effect + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onEffect(Player p, String[] args) { + if (args.length == 1) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type", null) + ChatColor.GREEN + " /pp effects | /pp effect ", ChatColor.RED); + return; + } + String argument = args[1].replace("_", ""); + if (ParticleCreator.particleFromString(argument) != null) { + ParticleEffect effect = ParticleCreator.particleFromString(argument); + if (!PermissionManager.hasEffectPermission(p, effect)) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-permission", ChatColor.AQUA + effect.getName().toLowerCase() + ChatColor.RED), ChatColor.RED); + return; + } + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), effect); + if (effect != ParticleEffect.NONE) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-now-using", ChatColor.AQUA + effect.getName().toLowerCase() + ChatColor.GREEN), ChatColor.GREEN); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-cleared-particles", null), ChatColor.GREEN); + } + return; + } + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type", null) + ChatColor.GREEN + " /pp effects", ChatColor.RED); + } + + /** + * Called when a player uses /pp effects + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onEffects(Player p, String[] args) { + String toSend = MessageManager.getMessageFromConfig("message-use", null) + " "; + for (ParticleEffect effect : ParticleEffect.getSupportedEffects()) { + if (PermissionManager.hasEffectPermission(p, effect)) { + toSend += effect.getName().toLowerCase().replace("_", "") + ", "; + continue; + } + } + if (toSend.equals(MessageManager.getMessageFromConfig("message-use", null) + " ")) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-particles", null), ChatColor.RED); + return; + } + toSend = toSend + "clear"; + MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp effect ", ChatColor.YELLOW); + } + + /** + * Called when a player uses /pp style + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onStyle(Player p, String[] args) { + if (args.length == 1) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp style ", ChatColor.YELLOW); + return; + } + String argument = args[1].replace("_", ""); + if (ParticleStyleManager.styleFromString(argument) != null) { + ParticleStyle style = ParticleStyleManager.styleFromString(argument); + if (!PermissionManager.hasStylePermission(p, style)) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-permission-style", ChatColor.AQUA + style.getName().toLowerCase() + ChatColor.RED), ChatColor.RED); + return; + } + ConfigManager.getInstance().savePPlayer(p.getUniqueId(), style); + if (style != DefaultStyles.NONE) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-now-using-style", ChatColor.AQUA + style.getName().toLowerCase() + ChatColor.GREEN), ChatColor.GREEN); + } else { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-cleared-style", null), ChatColor.GREEN); + } + return; + } + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-invalid-type-style", null) + ChatColor.GREEN + " /pp styles", ChatColor.RED); + } + + /** + * Called when a player uses /pp styles + * + * @param p The player who used the command + * @param args The arguments for the command + */ + private void onStyles(Player p, String[] args) { + String toSend = MessageManager.getMessageFromConfig("message-use-style", null) + " "; + for (ParticleStyle style : ParticleStyleManager.getStyles()) { + if (PermissionManager.hasStylePermission(p, style)) { + toSend += style.getName().toLowerCase(); + toSend += ", "; + } + } + if (toSend.endsWith(", ")) { + toSend = toSend.substring(0, toSend.length() - 2); + } + if (toSend.equals(MessageManager.getMessageFromConfig("message-use-style", null) + " " + DefaultStyles.NONE.getName().toLowerCase())) { + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-no-styles", null), ChatColor.RED); + return; + } + MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp style ", ChatColor.YELLOW); } } diff --git a/src/com/esophose/playerparticles/ParticleCreator.java b/src/com/esophose/playerparticles/ParticleCreator.java index 166257a..8b1ac98 100644 --- a/src/com/esophose/playerparticles/ParticleCreator.java +++ b/src/com/esophose/playerparticles/ParticleCreator.java @@ -8,10 +8,7 @@ package com.esophose.playerparticles; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.HashMap; +import java.util.ArrayList; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -19,187 +16,73 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.scheduler.BukkitRunnable; -import com.esophose.playerparticles.libraries.particles.ParticleEffect; -import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType; +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.library.ParticleEffect.ParticleProperty; import com.esophose.playerparticles.manager.ConfigManager; import com.esophose.playerparticles.manager.PermissionManager; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; public class ParticleCreator extends BukkitRunnable implements Listener { - + /** - * The map containing all the effects for players + * The list containing all the player effect info */ - private static HashMap map = new HashMap(); + public static ArrayList particlePlayers = new ArrayList(); + /** - * The map containing all the styles for players - */ - private static HashMap styleMap = new HashMap(); - - /** - * The timing system used for the styles HALO and SPIRAL - */ - private double step = 0; - - /** - * The timing system used for the styles QUAD_HELIX and ORB - */ - private double helixStep = 0; - private double helixYStep = 0; - private boolean reverse = false; - - /** - * Used to check for the database timing out - */ - private double mysqltimer = 0; - - /** - * First checks if the player is in the database (if it is enabled), if they are not then add them to the database - * Checks to see if that player has any effects or styles saved in either the database or config - * If so add the values to the map and/or styleMap - * - * Problematically clears the map and style map every time a player joins and refills the values - * Why does it do this? - * Figure out why or remove updateMap() and updateStyleMap() + * Adds the player to the array when they join * * @param e The event */ @EventHandler - public void onPlayerJoin(PlayerJoinEvent e){ - if(PlayerParticles.useMySQL) { - Statement s = null; - Statement statement = null; - ResultSet res = null; - try { - s = PlayerParticles.c.createStatement(); - res = s.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + e.getPlayer().getName() + "';"); - if(!res.next()) { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("INSERT INTO playerparticles SET player_name = '" + e.getPlayer().getName() + "', particle = NULL, style = 'none';"); - PlayerParticles.getPlugin().getLogger().info("[PlayerParticles] New player added to database: " + e.getPlayer().getName()); - } - } catch (SQLException e2) { - e2.printStackTrace(); - } finally { - if(s != null) try { s.close(); } catch (SQLException e1) { e1.printStackTrace(); } - if(statement != null) try { statement.close(); } catch (SQLException e1) { e1.printStackTrace(); } - if(res != null) try { res.close(); } catch (SQLException e1) { e1.printStackTrace(); } - } - } - if(ConfigManager.getInstance().getParticle(e.getPlayer()) == null) return; - map.put(e.getPlayer().getName(), ConfigManager.getInstance().getParticle(e.getPlayer())); - styleMap.put(e.getPlayer().getName(), ConfigManager.getStyleInstance().getStyle(e.getPlayer())); - updateMap(); - updateStyleMap(); + public void onPlayerJoin(PlayerJoinEvent e) { + ConfigManager.getInstance().getPPlayer(e.getPlayer().getUniqueId()); } - + /** - * Removes the player from the map and styleMap if they have any values in them - * Prevents spawning particles at a null location + * Removes the player from the array when they log off * * @param e The event */ @EventHandler - public void onPlayerQuit(PlayerQuitEvent e){ - if(map.containsKey(e.getPlayer().getName())){ - map.remove(e.getPlayer().getName()); - } - if(styleMap.containsKey(e.getPlayer().getName())) { - styleMap.remove(e.getPlayer().getName()); - } + public void onPlayerQuit(PlayerQuitEvent e) { + particlePlayers.remove(ConfigManager.getInstance().getPPlayer(e.getPlayer().getUniqueId())); } - + /** - * A somewhat costly solution to updating the MOVE style and displaying the appropriate particles - * - * @param e The event - */ - @EventHandler - public void onPlayerMove(PlayerMoveEvent e) { - if(map.containsKey(e.getPlayer().getName()) && styleMap.get(e.getPlayer().getName()) == ParticleStyle.MOVE) { - if(PermissionManager.hasStylePermission(e.getPlayer(), ParticleStyle.MOVE)) { - Location loc = e.getPlayer().getLocation(); - loc.setY(loc.getY() + 1); - handleStyleNone(map.get(e.getPlayer().getName()), loc); - } - } - } - - /** - * Adds the player with the given effect to the map - * - * @param player The player to add the effect to - * @param effect The effect - */ - public static void addMap(Player player, ParticleType effect){ - map.remove(player.getName()); - map.put(player.getName(), effect); - } - - /** - * Removes the player from the map - * - * @param player The player to remove - */ - public static void removeMap(Player player){ - map.remove(player.getName()); - } - - /** - * Clears the map then adds everybody on the server if they have effects saved + * Clears the list then adds everybody on the server * Used for when the server reloads and we can't rely on players rejoining */ - public static void updateMap(){ - map.clear(); - for(Player player : Bukkit.getOnlinePlayers()){ - if(ConfigManager.getInstance().getParticle(player) == null) continue; - map.put(player.getName(), ConfigManager.getInstance().getParticle(player)); + public static void refreshPPlayers() { + particlePlayers.clear(); + for (Player player : Bukkit.getOnlinePlayers()) { + ConfigManager.getInstance().getPPlayer(player.getUniqueId()); } } - /** - * Adds the player with the given style to the styleMap - * - * @param player The player to add the style to - * @param style The style - */ - public static void addStyleMap(Player player, ParticleStyle style) { - styleMap.remove(player.getName()); - styleMap.put(player.getName(), style); - } - - /** - * Removes the player from the styleMap - * - * @param player The player to remove - */ - public static void removeStyleMap(Player player){ - styleMap.remove(player.getName()); - } - - /** - * Clears the styleMap then adds everybody on the server if they have effects saved - * Used for when the server reloads and we can't rely on the players rejoining - */ - public static void updateStyleMap(){ - styleMap.clear(); - for(Player player : Bukkit.getOnlinePlayers()){ - styleMap.put(player.getName(), ConfigManager.getStyleInstance().getStyle(player)); + public static void updateIfContains(PPlayer pplayer) { + for (PPlayer pp : particlePlayers) { + if (pp.getUniqueId() == pplayer.getUniqueId()) { + particlePlayers.remove(pp); + particlePlayers.add(pplayer); + break; + } } } - + /** * Gets a particle type from a string, used for getting ParticleType's from the saved data * * @param particle The name of the particle to check for * @return The ParticleType with the given name, will be null if name was not found */ - public static ParticleType particleFromString(String particle) { - for(ParticleType effect : ParticleType.values()){ - if(effect.toString().toLowerCase().replace("_", "").equals(particle)) return effect; + public static ParticleEffect particleFromString(String particle) { + for (ParticleEffect effect : ParticleEffect.getSupportedEffects()) { + if (effect.getName().toLowerCase().replace("_", "").equals(particle.toLowerCase())) return effect; } return null; } @@ -211,338 +94,58 @@ public class ParticleCreator extends BukkitRunnable implements Listener { * Displays the particles for all players on the server */ public void run() { - step++; - if(step > 30) { - step = 0; - } - helixStep++; - if(helixStep > 90) { - helixStep = 0; - } - if(reverse) { - helixYStep++; - if(helixYStep > 60) reverse = false; - }else{ - helixYStep--; - if(helixYStep < -60) reverse = true; - } - if(PlayerParticles.useMySQL) { - mysqltimer++; - if(mysqltimer > 600) { - try { - if(PlayerParticles.c != null && PlayerParticles.c.isClosed()) { - PlayerParticles.c = PlayerParticles.mySQL.openConnection(); - if(PlayerParticles.c.isClosed()) { - PlayerParticles.getPlugin().getLogger().info("[PlayerParticles] Cannot connect to database! Is the database available and is your connection information correct?"); - } - } - } catch (SQLException | ClassNotFoundException e) { - e.printStackTrace(); - } - mysqltimer = 0; - } - } - for(Player player : Bukkit.getOnlinePlayers()){ - if(!map.containsKey(player.getName()) || ConfigManager.getInstance().isWorldDisabled(player.getWorld().getName())) continue; - ParticleType effect = map.get(player.getName()); - if(PermissionManager.hasPermission(player, effect)){ + ParticleStyleManager.updateTimers(); + + for (Player player : Bukkit.getOnlinePlayers()) { + if (ConfigManager.getInstance().isWorldDisabled(player.getWorld().getName())) continue; + PPlayer pplayer = ConfigManager.getInstance().getPPlayer(player.getUniqueId()); + if (PermissionManager.hasEffectPermission(player, pplayer.getParticleEffect())) { Location loc = player.getLocation(); loc.setY(loc.getY() + 1); - displayParticle(effect, styleMap.get(player.getName()), loc); + displayParticles(pplayer, loc); } } } - + /** - * Displays particles at the given player location with the effect and style given - * Checks all the effects and styles to make sure we display what is requested + * Displays particles at the given player location with their settings * - * @param effect The effect to display - * @param style The style to display + * @param pplayer The PPlayer to use for getting particle settings * @param location The location to display at */ - private void displayParticle(ParticleType effect, ParticleStyle style, Location location){ - if(style == null || style == ParticleStyle.NONE) { - handleStyleNone(effect, location); - }else if(style == ParticleStyle.SPIRAL) { - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - int points = 16; - double radius = 1; - double slice = 2 * Math.PI / points; - for(int i = 0; i < points; i++) { - double angle = slice * i; - double newX = location.getX() + radius * Math.cos(angle); - double newY = location.getY() + (step / 10) - 1; - double newZ = location.getZ() + radius * Math.sin(angle); - Location newLocation = new Location(location.getWorld(), newX, newY, newZ); - particle.display(newLocation); - } - }else if(style == ParticleStyle.HALO) { - if(step % 2 == 0) return; - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - int points = 16; - double radius = .65; - double slice = 2 * Math.PI / points; - for(int i = 0; i < points; i++) { - double angle = slice * i; - double newX = location.getX() + radius * Math.cos(angle); - double newY = location.getY() + 1.5; - double newZ = location.getZ() + radius * Math.sin(angle); - Location newLocation = new Location(location.getWorld(), newX, newY, newZ); - particle.display(newLocation); - } - }else if(style == ParticleStyle.POINT) { - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - particle.display(location.add(0.0, 1.5, 0.0)); - }else if(style == ParticleStyle.SPIN) { - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - int points = 15; - double radius = .5; - double slice = 2 * Math.PI / points; - double angle = slice * (step % 15); - double newX = location.getX() + radius * Math.cos(angle); - double newY = location.getY() + 1.5; - double newZ = location.getZ() + radius * Math.sin(angle); - Location newLocation = new Location(location.getWorld(), newX, newY, newZ); - particle.display(newLocation); - }else if(style == ParticleStyle.QUADHELIX) { - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - for(int i = 0; i < 4; i++) { - double dx = -(Math.cos((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(helixYStep)) / 60); - double dy = ((helixYStep) / 60) * 1.5; - double dz = -(Math.sin((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(helixYStep)) / 60); - particle.display(new Location(location.getWorld(), location.getX() + dx, location.getY() + dy, location.getZ() + dz)); - } - }else if(style == ParticleStyle.ORB) { - ParticleEffect particle = null; - if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1); - else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1); - for(int i = 0; i < 4; i++) { - double dx = -(Math.cos((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))); - double dz = -(Math.sin((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))); - particle.display(new Location(location.getWorld(), location.getX() + dx, location.getY(), location.getZ() + dz)); + private void displayParticles(PPlayer pplayer, Location location) { + if (!ParticleStyleManager.isCustomHandled(pplayer.getParticleStyle())) { + ParticleEffect effect = pplayer.getParticleEffect(); + if (effect == ParticleEffect.NONE) return; + for (PParticle particle : pplayer.getParticleStyle().getParticles(pplayer, location)) { + if (effect.hasProperty(ParticleProperty.REQUIRES_DATA)) { + effect.display(pplayer.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } else if (effect.hasProperty(ParticleProperty.COLORABLE)) { + effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } else { + effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } } } } - + /** - * Displays particles at the given location with the default spread out style, NONE - * Only check against every type to make sure they look nice, it isn't completely required + * An alternative method typically used for custom handled styles * - * @param effect The effect to display as - * @param location The locatio to display at + * @param pplayer The PPlayer to use for getting particle settings + * @param location The location to display at */ - public void handleStyleNone(ParticleType effect, Location location) { - if(effect == null || location == null) return; - if(effect.equals(ParticleType.ANGRY_VILLAGER)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.BUBBLE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.CLOUD)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.CRIT)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DEPTH_SUSPEND)){ - ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DRIP_LAVA)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DRIP_WATER)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.ENCHANTMENT_TABLE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.05F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.EXPLODE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.FIREWORKS_SPARK)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.FLAME)){ - ParticleEffect particle = new ParticleEffect(effect, 0.1F, 0.1F, 0.1F, 0.05F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.FOOTSTEP)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.0F, 0.4F, 0.0F, 1); - particle.display(location.subtract(0, 0.98, 0)); - return; - }else - if(effect.equals(ParticleType.HAPPY_VILLAGER)){ - ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.HEART)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.HUGE_EXPLOSION)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.INSTANT_SPELL)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.LARGE_EXPLODE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.LARGE_SMOKE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.LAVA)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.MAGIC_CRIT)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.MOB_SPELL)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.MOB_SPELL_AMBIENT)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.NOTE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 1.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.PORTAL)){ - ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.05F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.RAINBOW)){ - ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 1.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.RED_DUST)){ - ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SLIME)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SMOKE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SNOW_SHOVEL)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SNOWBALL_POOF)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SPELL)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SUSPENDED)){ - ParticleEffect particle = new ParticleEffect(effect, 0.8F, 0.8F, 0.8F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.WAKE)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 3); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.WITCH_MAGIC)){ - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.BARRIER)){ - ParticleEffect particle = new ParticleEffect(effect, 1.2F, 1.2F, 1.2F, 0.0F, 1); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DROPLET)){ - ParticleEffect particle = new ParticleEffect(effect, 0.8F, 0.8F, 0.8F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DRAGON_BREATH)) { - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.END_ROD)) { - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.DAMAGE_INDICATOR)) { - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5); - particle.display(location); - return; - }else - if(effect.equals(ParticleType.SWEEP_ATTACK)) { - ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5); - particle.display(location); - return; + public static void displayParticles(PPlayer pplayer, PParticle[] particles) { + ParticleEffect effect = pplayer.getParticleEffect(); + if (effect == ParticleEffect.NONE) return; + for (PParticle particle : particles) { + if (effect.hasProperty(ParticleProperty.REQUIRES_DATA)) { + effect.display(pplayer.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } else if (effect.hasProperty(ParticleProperty.COLORABLE)) { + effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } else { + effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), 256); + } } } diff --git a/src/com/esophose/playerparticles/ParticleStyle.java b/src/com/esophose/playerparticles/ParticleStyle.java deleted file mode 100644 index ee2362c..0000000 --- a/src/com/esophose/playerparticles/ParticleStyle.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright Esophose 2016 - * While using any of the code provided by this plugin - * you must not claim it as your own. This plugin may - * be modified and installed on a server, but may not - * be distributed to any person by any means. - */ - -package com.esophose.playerparticles; - -public enum ParticleStyle { - - NONE, - SPIRAL, - HALO, - POINT, - MOVE, - SPIN, - QUADHELIX, - ORB; - - /** - * Gets the ParticleStyle with the name given, returns null if not found - * - * @param particle The string of the style to search for - * @return The ParticleStyle with the name requested - */ - public static ParticleStyle styleFromString(String particle){ - for(ParticleStyle style : ParticleStyle.values()){ - if(style.toString().toLowerCase().replace("_", "").equals(particle)) return style; - } - return ParticleStyle.NONE; - } - -} diff --git a/src/com/esophose/playerparticles/ParticlesUtil.java b/src/com/esophose/playerparticles/ParticlesUtil.java new file mode 100644 index 0000000..d36dcc5 --- /dev/null +++ b/src/com/esophose/playerparticles/ParticlesUtil.java @@ -0,0 +1,23 @@ +package com.esophose.playerparticles; + +import java.util.ArrayList; + +import org.bukkit.Material; + +public class ParticlesUtil { + + // TODO: Find a more reliable way of doing this that works better + @SuppressWarnings("deprecation") + public static Material closestMatch(String input) { + ArrayList matchList = new ArrayList(); + for (Material mat : Material.values()) + if (mat.name().replace("_", " ").toLowerCase().equals(input.toLowerCase()) || String.valueOf(mat.getId()).equals(input)) + return mat; + else if (mat.name().replace("_", " ").toLowerCase().contains(input.toLowerCase())) + matchList.add(mat); + + if (matchList.size() == 1) return matchList.get(0); + else return null; + } + +} diff --git a/src/com/esophose/playerparticles/PlayerParticles.java b/src/com/esophose/playerparticles/PlayerParticles.java index 3dad12d..a773fa5 100644 --- a/src/com/esophose/playerparticles/PlayerParticles.java +++ b/src/com/esophose/playerparticles/PlayerParticles.java @@ -4,45 +4,46 @@ * you must not claim it as your own. This plugin may * be modified and installed on a server, but may not * be distributed to any person by any means. + * + * TODO: Make sure copyright notice is on all files + * TODO: Make sure all the comments are properly formatted still */ -// Fixed worlds missing from /pp help -// Add style "feet" - package com.esophose.playerparticles; import java.io.File; -import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; -import com.esophose.playerparticles.library.database.MySQL; +import com.esophose.playerparticles.library.MySQL; +import com.esophose.playerparticles.styles.DefaultStyles; import com.esophose.playerparticles.updater.PluginUpdateListener; import com.esophose.playerparticles.updater.Updater; public class PlayerParticles extends JavaPlugin { - + /** - * The version a new update has, will be null if the config has it disabled or if there is no new version + * The version a new update has, will be null if the config has it disabled + * or if there is no new version */ public static String updateVersion = null; - + /** * The MySQL connection */ public static MySQL mySQL = null; - public static Connection c = null; - + /** * Whether or not to use MySQL as determined in the config */ public static boolean useMySQL = false; - + /** + * Registers all the styles available by default * Saves the default config if it doesn't exist * Registers the tab completer and the event listeners * Checks if the config needs to be updated to the new version @@ -52,12 +53,14 @@ public class PlayerParticles extends JavaPlugin { * Registers the command executor * Checks for any updates if checking is enabled in the config */ - public void onEnable(){ + public void onEnable() { + DefaultStyles.registerStyles(); saveDefaultConfig(); getCommand("pp").setTabCompleter(new ParticleCommandCompleter()); + getCommand("pp").setExecutor(new ParticleCommandExecutor()); Bukkit.getPluginManager().registerEvents(new ParticleCreator(), this); Bukkit.getPluginManager().registerEvents(new PluginUpdateListener(), this); - if(getConfig().getDouble("version") < Double.parseDouble(getDescription().getVersion())) { + if (getConfig().getDouble("version") < Double.parseDouble(getDescription().getVersion())) { File configFile = new File(getDataFolder(), "config.yml"); configFile.delete(); saveDefaultConfig(); @@ -65,33 +68,27 @@ public class PlayerParticles extends JavaPlugin { getLogger().warning("[PlayerParticles] config.yml has been updated!"); } checkDatabase(); - ParticleCreator.updateMap(); - ParticleCreator.updateStyleMap(); - startTasks(); - - getCommand("pp").setExecutor(new ParticleCommandExecutor()); - - if(shouldCheckUpdates()) { - getLogger().info("[PlayerParticles] Checking for an update..."); + ParticleCreator.refreshPPlayers(); + startTask(); + + if (shouldCheckUpdates()) { Updater updater = new Updater(this, 82823, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false); - if(Double.parseDouble(updater.getLatestName().replaceAll("PlayerParticles v", "")) > Double.parseDouble(getPlugin().getDescription().getVersion())) { + if (Double.parseDouble(updater.getLatestName().replaceAll("PlayerParticles v", "")) > Double.parseDouble(getPlugin().getDescription().getVersion())) { updateVersion = updater.getLatestName().replaceAll("PlayerParticles v", ""); getLogger().info("[PlayerParticles] An update (v" + updateVersion + ") is available! You are running v" + getPlugin().getDescription().getVersion()); - } else { - getLogger().info("[PlayerParticles] No update was found"); } } } - + /** * Gets the instance of the plugin running on the server * * @return The PlayerParticles plugin instance */ - public static Plugin getPlugin(){ + public static Plugin getPlugin() { return Bukkit.getPluginManager().getPlugin("PlayerParticles"); } - + /** * Checks the config if the plugin can look for updates * @@ -100,47 +97,56 @@ public class PlayerParticles extends JavaPlugin { public boolean shouldCheckUpdates() { return getConfig().getBoolean("check-updates"); } - + /** * Checks if database-enable is true in the config, if it is then continue * Gets the database connection information from the config and tries to connect to the server - * Creates a new table if it doesn't exist called playerparticles + * Removes old table from previous versions of the plugin + * Creates new tables if they don't exist * Sets useMySQL to true if it connects successfully, and false if it fails or isn't enabled */ private void checkDatabase() { - if(getConfig().getBoolean("database-enable")) { + if (getConfig().getBoolean("database-enable")) { String hostname = getConfig().getString("database-hostname"); String port = getConfig().getString("database-port"); String database = getConfig().getString("database-name"); String user = getConfig().getString("database-user-name"); String pass = getConfig().getString("database-user-password"); mySQL = new MySQL(hostname, port, database, user, pass); - try { - c = mySQL.openConnection(); - Statement statement = c.createStatement(); - statement.executeUpdate("CREATE TABLE IF NOT EXISTS playerparticles (player_name VARCHAR(32), particle VARCHAR(32), style VARCHAR(32));"); + try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'playerparticles'")) { + if (res.next()) { + mySQL.updateSQL("DROP TABLE playerparticles"); + } + } catch (ClassNotFoundException | SQLException e1) { + getLogger().info("[PlayerParticles] Failed to connect to the MySQL Database! Check to see if your login information is correct!"); + useMySQL = false; + return; + } + try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'pp_users'")) { + if (!res.next()) { // @formatter:off + mySQL.updateSQL("CREATE TABLE pp_users (player_uuid VARCHAR(36), effect VARCHAR(32), style VARCHAR(32));" + + "CREATE TABLE pp_data_item (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + + "CREATE TABLE pp_data_block (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + + "CREATE TABLE pp_data_color (player_uuid VARCHAR(36), r TINYINT, g TINYINT, b TINYINT)" + + "CREATE TABLE pp_data_note (player_uuid VARCHAR(36), note TINYINT)" + ); // @formatter:on + } useMySQL = true; } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - getLogger().info("[PlayerParticles] Failed to connect to MySQL Database! Check to see if your config is correct!"); + getLogger().info("[PlayerParticles] Failed to connect to the MySQL Database! Check to see if your login information is correct!"); useMySQL = false; } } else { useMySQL = false; } - getLogger().info("[PlayerParticles] Using mySQL for data storage: " + useMySQL); } - + /** * Starts the task reponsible for spawning particles - * Starts two with 1 tick delay if ticks-per-particle is set to 0.5 */ - private void startTasks() { - double ticks = getConfig().getDouble("ticks-per-particle"); - if(ticks == 0.5) { - new ParticleCreator().runTaskTimer(this, 20, 1); - new ParticleCreator().runTaskTimer(this, 20, 1); - } else new ParticleCreator().runTaskTimer(this, 20, (long) ticks); + private void startTask() { + double ticks = getConfig().getInt("ticks-per-particle"); + new ParticleCreator().runTaskTimer(this, 20, (long) ticks); } - + } diff --git a/src/com/esophose/playerparticles/libraries/particles/ParticleEffect.java b/src/com/esophose/playerparticles/libraries/particles/ParticleEffect.java deleted file mode 100644 index e9dacdc..0000000 --- a/src/com/esophose/playerparticles/libraries/particles/ParticleEffect.java +++ /dev/null @@ -1,431 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2014 Maxim Roncace - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.esophose.playerparticles.libraries.particles; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; - -/** - * Particle effects utility library - * @author Maxim Roncace - * @version 0.1.0 - */ - -/** - * Slightly modified to suit the needs - * of the plugin - * @author Esophose - */ - -@SuppressWarnings({ "unchecked", "rawtypes" }) -public class ParticleEffect { - - private static Class packetClass = null; - private static Constructor packetConstructor = null; - private static Field[] fields = null; - private static boolean netty = true; - private static Field player_connection = null; - private static Method player_sendPacket = null; - private static HashMap, Method> handles = new HashMap, Method>(); - - private static boolean newParticlePacketConstructor = false; - private static Class enumParticle = null; - - private ParticleType type; - private double speed; - private int count; - private double offsetX, offsetY, offsetZ; - - private static boolean compatible = true; - - static { - String vString = getVersion().replace("v", ""); - double v = 0; - if (!vString.isEmpty()){ - String[] array = vString.split("_"); - v = Integer.parseInt(array[1]); // Take the second value to fix MC 1.10 looking like 1.1 and failing to be greater than 1.7 - } - try { - if (v < 7) { // Maintain support for versions below 1.6 (Probably doesn't even work) - netty = false; - packetClass = getNmsClass("Packet63WorldParticles"); - packetConstructor = packetClass.getConstructor(); - fields = packetClass.getDeclaredFields(); - } else { // Use the greater than 1.7 particle packet class - packetClass = getNmsClass("PacketPlayOutWorldParticles"); - if (v < 8){ - packetConstructor = packetClass.getConstructor(String.class, float.class, float.class, float.class, float.class, float.class, float.class, float.class, int.class); - } else { // use the new constructor for 1.8 - newParticlePacketConstructor = true; - enumParticle = (Class)getNmsClass("EnumParticle"); - packetConstructor = packetClass.getDeclaredConstructor(enumParticle, boolean.class, float.class, float.class, float.class, float.class, float.class, float.class, float.class, int.class, int[].class); - } - } - } catch (Exception ex) { - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to initialize NMS components! This occurs if you are running the plugin on a version of Minecraft that is not supported!"); - compatible = false; - } - } - - /** - * Constructs a new particle effect for use. - *

- * Note: different values for speed and radius may hav;e different effects - * depending on the particle's type. - *

- * @param type the particle type - * @param speed the speed of the particles - * @param count the number of particles to spawn - * @param radius the radius of the particles - */ - public ParticleEffect(ParticleType type, double offsetX, double offsetY, double offsetZ, double speed, int count){ - this.type = type; - this.speed = speed; - this.count = count; - this.offsetX = offsetX; - this.offsetY = offsetY; - this.offsetZ = offsetZ; - } - - /** - * Gets the name of this effect - * @return The name of this effect - */ - public String getName() { - return type.name; - } - - /** - * Gets the speed of the particles in this effect - * @return The speed of the particles in this effect - */ - public double getSpeed(){ - return speed; - } - - /** - * Retrieves the number of particles spawned by the effect - * @return The number of particles spawned by the effect - */ - public int getCount(){ - return count; - } - - /** - * Gets the offsetX of the particle effect - * @return The offsetX of the particle effect - */ - public double getOffsetX(){ - return offsetX; - } - - /** - * Gets the offsetY of the particle effect - * @return The offsetY of the particle effect - */ - public double getOffsetY(){ - return offsetY; - } - - /** - * Gets the offsetZ of the particle effect - * @return The offsetZ of the particle effect - */ - public double getOffsetZ(){ - return offsetZ; - } - - /** - * Send a particle effect to all players - * @param location The location to send the effect to - */ - public void display(Location location){ - try { - Object packet = createPacket(location); - for (Player player : Bukkit.getOnlinePlayers()){ - if(player.getLocation().getWorld().getName().equals(location.getWorld().getName())) // Patch a bug where particles will be shown in all worlds - sendPacket(player, packet); - } - } - catch (Exception e){ - e.printStackTrace(); - } - } - - /** - * Constructs a new particle packet - * @param location the location to spawn the particle effect at - * @return the constructed packet - */ - private Object createPacket(Location location){ - try { - if (this.count <= 0){ - this.count = 1; - } - Object packet; - if (netty){ - if (newParticlePacketConstructor){ - Object particleType = enumParticle.getEnumConstants()[type.getId()]; - packet = packetConstructor.newInstance(particleType, - true, (float)location.getX(), (float)location.getY(), (float)location.getZ(), - (float)this.offsetX, (float)this.offsetY, (float)this.offsetZ, - (float)this.speed, this.count, new int[0]); - } - else { - packet = packetConstructor.newInstance(type.getName(), - (float)location.getX(), (float)location.getY(), (float)location.getZ(), - (float)this.offsetX, (float)this.offsetY, (float)this.offsetZ, - (float)this.speed, this.count); - } - } - else { - packet = packetConstructor.newInstance(); - for (Field f : fields){ - f.setAccessible(true); - if (f.getName().equals("a")) - f.set(packet, type.getName()); - else if (f.getName().equals("b")) - f.set(packet, (float)location.getX()); - else if (f.getName().equals("c")) - f.set(packet, (float)location.getY()); - else if (f.getName().equals("d")) - f.set(packet, (float)location.getZ()); - else if (f.getName().equals("e")) - f.set(packet, this.offsetX); - else if (f.getName().equals("f")) - f.set(packet, this.offsetY); - else if (f.getName().equals("g")) - f.set(packet, this.offsetZ); - else if (f.getName().equals("h")) - f.set(packet, this.speed); - else if (f.getName().equals("i")) - f.set(packet, this.count); - } - } - return packet; - } - catch (IllegalAccessException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to construct particle effect packet!"); - } - catch (InstantiationException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to construct particle effect packet!"); - } - catch (InvocationTargetException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to construct particle effect packet!"); - } - return null; - } - - /** - * Sends a packet to a player. - *

- * Note: this method is not typesafe! - *

- * @param p the player to send a packet to - * @param packet the packet to send - * @throws IllegalArgumentException if packet is not of a proper type - */ - private static void sendPacket(Player p, Object packet) throws IllegalArgumentException { - try { - if (player_connection == null){ - player_connection = getHandle(p).getClass().getField("playerConnection"); - for (Method m : player_connection.get(getHandle(p)).getClass().getMethods()){ - if (m.getName().equalsIgnoreCase("sendPacket")){ - player_sendPacket = m; - } - } - } - player_sendPacket.invoke(player_connection.get(getHandle(p)), packet); - } - catch (IllegalAccessException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to send packet!"); - } - catch (InvocationTargetException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to send packet!"); - } - catch (NoSuchFieldException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to send packet!"); - } - } - - /** - * Gets the NMS handle of the given {@link Entity}. - * @param entity the entity get the handle of - * @return the entity's NMS handle - */ - private static Object getHandle(Entity entity){ - try { - if (handles.get(entity.getClass()) != null) - return handles.get(entity.getClass()).invoke(entity); - else { - Method entity_getHandle = entity.getClass().getMethod("getHandle"); - handles.put(entity.getClass(), entity_getHandle); - return entity_getHandle.invoke(entity); - } - } - catch (Exception ex) { - ex.printStackTrace(); - return null; - } - } - - /** - * Gets the NMS class by the given name. - * @param name the name of the NMS class to get - * @return the NMS class of the given name - */ - private static Class getNmsClass(String name){ - String version = getVersion(); - String className = "net.minecraft.server." + version + name; - Class clazz = null; - try { - clazz = Class.forName(className); - } - catch (ClassNotFoundException ex){ - ex.printStackTrace(); - Bukkit.getLogger().severe("[PlayerParticles] Failed to load NMS class " + name + "!"); - } - return clazz; - } - - /** - * Determines the version string used by Craftbukkit's safeguard (e.g. 1_7_R4). - * @return the version string used by Craftbukkit's safeguard - */ - private static String getVersion(){ - String[] array = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(","); - if (array.length == 4) - return array[3] + "."; - return ""; - } - - /** - * Gets whether PlayerParticles is compatible with the server software. - * @return whether PlayerParticles is compatible with the server software. - */ - public static boolean isCompatible(){ - return compatible; - } - - /** - * Enum representing valid particle types in Minecraft 1.10 minus a few which are too similar or too spammy - */ - public enum ParticleType { - - EXPLODE("explode", 0, 17), - LARGE_EXPLODE("largeexplode", 1, 1), - HUGE_EXPLOSION("hugeexplosion", 2, 0), - FIREWORKS_SPARK("fireworksSpark", 3, 2), - BUBBLE("bubble", 4, 3), - WAKE("wake", 6, -1), - SUSPENDED("suspended", 7, 4), - DEPTH_SUSPEND("depthsuspend", 8, 5), - CRIT("crit", 9, 7), - MAGIC_CRIT("magicCrit", 10, 8), - SMOKE("smoke", 11, -1), - LARGE_SMOKE("largesmoke", 12, 22), - SPELL("spell", 13, 11), - INSTANT_SPELL("instantSpell", 14, 12), - MOB_SPELL("mobSpell", 15, 9), - MOB_SPELL_AMBIENT("mobSpellAmbient", 16, 10), - WITCH_MAGIC("witchMagic", 17, 13), - DRIP_WATER("dripWater", 18, 27), - DRIP_LAVA("dripLava", 19, 28), - ANGRY_VILLAGER("angryVillager", 20, 31), - HAPPY_VILLAGER("happyVillager", 21, 32), - NOTE("note", 23, 24), - PORTAL("portal", 24, 15), - ENCHANTMENT_TABLE("enchantmenttable", 25, 16), - FLAME("flame", 26, 18), - LAVA("lava", 27, 19), - FOOTSTEP("footstep", 28, 20), - CLOUD("cloud", 29, 23), - RED_DUST("reddust", 30, 24), - SNOWBALL_POOF("snowballpoof", 31, 25), - SNOW_SHOVEL("snowshovel", 32, 28), - SLIME("slime", 33, 29), - HEART("heart", 34, 30), - BARRIER("barrier", 35, -1), - DROPLET("droplet", 39, -1), - DRAGON_BREATH("dragonbreath", 42, -1), - END_ROD("endRod", 43, -1), - DAMAGE_INDICATOR("damageIndicator", 44, -1), - SWEEP_ATTACK("sweepAttack", 45, -1), - RAINBOW("rainbow", 30, -1); - - private String name; - private int id; - private int legacyId; - - ParticleType(String name, int id, int legacyId){ - this.name = name; - this.id = id; - this.legacyId = legacyId; - } - - /** - * Gets the name of the particle effect - * - * @return The name of the particle effect - */ - public String getName(){ - return name; - } - - /** - * Gets the ID of the particle effect - * - * @return The ID of the particle effect - */ - int getId(){ - return id; - } - - /** - * Gets the legacy ID (pre-1.8) of the particle effect - * - * @return the legacy ID of the particle effect (or -1 if introduced after 1.7) - */ - int getLegacyId(){ - return legacyId; - } - } - -} \ No newline at end of file diff --git a/src/com/esophose/playerparticles/library/database/Database.java b/src/com/esophose/playerparticles/library/Database.java similarity index 65% rename from src/com/esophose/playerparticles/library/database/Database.java rename to src/com/esophose/playerparticles/library/Database.java index 10f94ca..a0420c6 100644 --- a/src/com/esophose/playerparticles/library/database/Database.java +++ b/src/com/esophose/playerparticles/library/Database.java @@ -1,4 +1,4 @@ -package com.esophose.playerparticles.library.database; +package com.esophose.playerparticles.library; import java.sql.Connection; import java.sql.ResultSet; @@ -28,20 +28,16 @@ public abstract class Database { * Opens a connection with the database * * @return Opened connection - * @throws SQLException - * if the connection can not be opened - * @throws ClassNotFoundException - * if the driver cannot be found + * @throws SQLException if the connection can not be opened + * @throws ClassNotFoundException if the driver cannot be found */ - public abstract Connection openConnection() throws SQLException, - ClassNotFoundException; + public abstract Connection openConnection() throws SQLException, ClassNotFoundException; /** * Checks if a connection is open with the database * * @return true if the connection is open - * @throws SQLException - * if the connection cannot be checked + * @throws SQLException if the connection cannot be checked */ public boolean checkConnection() throws SQLException { return connection != null && !connection.isClosed(); @@ -60,8 +56,7 @@ public abstract class Database { * Closes the connection with the database * * @return true if successful - * @throws SQLException - * if the connection cannot be closed + * @throws SQLException if the connection cannot be closed */ public boolean closeConnection() throws SQLException { if (connection == null) { @@ -71,22 +66,18 @@ public abstract class Database { return true; } - /** * Executes a SQL Query
* * If the connection is closed, it will be opened * - * @param query - * Query to be run + * @param query Query to be run * @return the results of the query - * @throws SQLException - * If the query cannot be executed - * @throws ClassNotFoundException - * If the driver cannot be found; see {@link #openConnection()} + * @throws SQLException If the query cannot be executed + * @throws ClassNotFoundException If the driver cannot be found; see + * {@link #openConnection()} */ - public ResultSet querySQL(String query) throws SQLException, - ClassNotFoundException { + public ResultSet querySQL(String query) throws SQLException, ClassNotFoundException { if (!checkConnection()) { openConnection(); } @@ -103,16 +94,13 @@ public abstract class Database { * See {@link java.sql.Statement#executeUpdate(String)}
* If the connection is closed, it will be opened * - * @param query - * Query to be run + * @param query Query to be run * @return Result Code, see {@link java.sql.Statement#executeUpdate(String)} - * @throws SQLException - * If the query cannot be executed - * @throws ClassNotFoundException - * If the driver cannot be found; see {@link #openConnection()} + * @throws SQLException If the query cannot be executed + * @throws ClassNotFoundException If the driver cannot be found; see + * {@link #openConnection()} */ - public int updateSQL(String query) throws SQLException, - ClassNotFoundException { + public int updateSQL(String query) throws SQLException, ClassNotFoundException { if (!checkConnection()) { openConnection(); } @@ -121,6 +109,8 @@ public abstract class Database { int result = statement.executeUpdate(query); + statement.close(); + return result; } -} \ No newline at end of file +} diff --git a/src/com/esophose/playerparticles/library/MySQL.java b/src/com/esophose/playerparticles/library/MySQL.java new file mode 100644 index 0000000..bb76f1e --- /dev/null +++ b/src/com/esophose/playerparticles/library/MySQL.java @@ -0,0 +1,64 @@ +package com.esophose.playerparticles.library; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Connects to and uses a MySQL database + * + * @author -_Husky_- + * @author tips48 + */ +public class MySQL extends Database { + private final String user; + private final String database; + private final String password; + private final String port; + private final String hostname; + + /** + * Creates a new MySQL instance + * + * @param hostname Name of the host + * @param port Port number + * @param username Username + * @param password Password + */ + public MySQL(String hostname, String port, String username, String password) { + this(hostname, port, null, username, password); + } + + /** + * Creates a new MySQL instance for a specific database + * + * @param hostname Name of the host + * @param port Port number + * @param database Database name + * @param username Username + * @param password Password + */ + public MySQL(String hostname, String port, String database, String username, String password) { + this.hostname = hostname; + this.port = port; + this.database = database; + this.user = username; + this.password = password; + } + + @Override + public Connection openConnection() throws SQLException, ClassNotFoundException { + if (checkConnection()) { + return connection; + } + + String connectionURL = "jdbc:mysql://" + this.hostname + ":" + this.port; + if (database != null) { + connectionURL = connectionURL + "/" + this.database; + } + + Class.forName("com.mysql.jdbc.Driver"); + connection = DriverManager.getConnection(connectionURL, this.user, this.password); + return connection; + } +} diff --git a/src/com/esophose/playerparticles/library/ParticleEffect.java b/src/com/esophose/playerparticles/library/ParticleEffect.java new file mode 100644 index 0000000..b3f0ad1 --- /dev/null +++ b/src/com/esophose/playerparticles/library/ParticleEffect.java @@ -0,0 +1,1474 @@ +package com.esophose.playerparticles.library; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import com.esophose.playerparticles.library.ReflectionUtils.PackageType; + +/** + * ParticleEffect Library + *

+ * This library was created by @DarkBlade12 and allows you to display all Minecraft particle effects on a Bukkit server + *

+ * You are welcome to use it, modify it and redistribute it under the following conditions: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * Special thanks: + *

    + *
  • @microgeek (original idea, names and packet parameters) + *
  • @ShadyPotato (1.8 names, ids and packet parameters) + *
  • @RingOfStorms (particle behavior) + *
  • @Cybermaxke (particle behavior) + *
  • @JamieSinn (hosting a jenkins server and documentation for particleeffect) + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a published project + * + * @author DarkBlade12 + * @version 1.7 + */ + +/** + * Modified a couple things for the plugin + * Updated to 1.10 + * + * @author (of changes) Esophose + */ +public enum ParticleEffect { + + NONE("none", -1, -1), + EXPLODE("explode", 0, -1, ParticleProperty.DIRECTIONAL), + LARGE_EXPLODE("largeexplode", 1, -1), + HUGE_EXPLOSION("hugeexplosion", 2, -1), + FIREWORKS_SPARK("fireworksSpark", 3, -1, ParticleProperty.DIRECTIONAL), + BUBBLE("bubble", 4, -1, ParticleProperty.DIRECTIONAL), // Removed ParticleProperty.REQUIRES_WATER + // SPLASH("splash", 5, -1, ParticleProperty.DIRECTIONAL), // Same thing as wake + WAKE("wake", 6, 7, ParticleProperty.DIRECTIONAL), + SUSPENDED("suspended", 7, -1), // Removed ParticleProperty.REQUIRES_WATER + DEPTH_SUSPEND("depthSuspend", 8, -1, ParticleProperty.DIRECTIONAL), + CRIT("crit", 9, -1, ParticleProperty.DIRECTIONAL), + MAGIC_CRIT("magicCrit", 10, -1, ParticleProperty.DIRECTIONAL), + SMOKE("smoke", 11, -1, ParticleProperty.DIRECTIONAL), + LARGE_SMOKE("largesmoke", 12, -1, ParticleProperty.DIRECTIONAL), + SPELL("spell", 13, -1), + INSTANT_SPELL("instantSpell", 14, -1), + MOB_SPELL("mobSpell", 15, -1, ParticleProperty.COLORABLE), + MOB_SPELL_AMBIENT("mobSpellAmbient", 16, -1, ParticleProperty.COLORABLE), + WITCH_MAGIC("witchMagic", 17, -1), + DRIP_WATER("dripWater", 18, -1), + DRIP_LAVA("dripLava", 19, -1), + ANGRY_VILLAGER("angryVillager", 20, -1), + HAPPY_VILLAGER("happyVillager", 21, -1, ParticleProperty.DIRECTIONAL), + // TOWN_AURA("townaura", 22, -1, ParticleProperty.DIRECTIONAL), // Same thing as depthsuspend + NOTE("note", 23, -1, ParticleProperty.COLORABLE), + PORTAL("portal", 24, -1, ParticleProperty.DIRECTIONAL), + ENCHANTMENT_TABLE("enchantmenttable", 25, -1, ParticleProperty.DIRECTIONAL), + FLAME("flame", 26, -1, ParticleProperty.DIRECTIONAL), + LAVA("lava", 27, -1), + FOOTSTEP("footstep", 28, -1), + CLOUD("cloud", 29, -1, ParticleProperty.DIRECTIONAL), + RED_DUST("reddust", 30, -1, ParticleProperty.COLORABLE), + SNOWBALL_POOF("snowballpoof", 31, -1), + SNOW_SHOVEL("snowshovel", 32, -1, ParticleProperty.DIRECTIONAL), + SLIME("slime", 33, -1), + HEART("heart", 34, -1), + // RAINBOW("rainbow", 30, -1), + BARRIER("barrier", 35, 8), + ITEM_CRACK("iconcrack", 36, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + BLOCK_CRACK("blockcrack", 37, -1, ParticleProperty.REQUIRES_DATA), + BLOCK_DUST("blockdust", 38, 7, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), + DROPLET("droplet", 39, 8), + // ITEM_TAKE("take", 40, 8), // Doesn't do anything + // MOB_APPEARANCE("mobappearance", 41, 8), // Too spammy + DRAGON_BREATH("dragonbreath", 42, 9), + END_ROD("endrod", 43, 9), + DAMAGE_INDICATOR("damageindicator", 44, 9), + SWEEP_ATTACK("sweepattack", 45, 9), + FALLING_DUST("fallingdust", 46, 10, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA); + + private static final Map NAME_MAP = new HashMap(); + private static final Map ID_MAP = new HashMap(); + private final String name; + private final int id; + private final int requiredVersion; + private final List properties; + + // Initialize map for quick name and id lookup + static { + for (ParticleEffect effect : values()) { + NAME_MAP.put(effect.name, effect); + ID_MAP.put(effect.id, effect); + } + } + + /** + * Construct a new particle effect + * + * @param name Name of this particle effect + * @param id Id of this particle effect + * @param requiredVersion Version which is required (1.x) + * @param properties Properties of this particle effect + */ + private ParticleEffect(String name, int id, int requiredVersion, ParticleProperty... properties) { + this.name = name; + this.id = id; + this.requiredVersion = requiredVersion; + this.properties = Arrays.asList(properties); + } + + /** + * Returns the name of this particle effect + * + * @return The name + */ + public String getName() { + return name; + } + + /** + * Returns the id of this particle effect + * + * @return The id + */ + public int getId() { + return id; + } + + /** + * Returns the required version for this particle effect (1.x) + * + * @return The required version + */ + public int getRequiredVersion() { + return requiredVersion; + } + + /** + * Determine if this particle effect has a specific property + * + * @return Whether it has the property or not + */ + public boolean hasProperty(ParticleProperty property) { + return properties.contains(property); + } + + /** + * Determine if this particle effect is supported by your current server + * version + * + * @return Whether the particle effect is supported or not + */ + public boolean isSupported() { + if (requiredVersion == -1) { + return true; + } + return ParticlePacket.getVersion() >= requiredVersion; + } + + /** + * Returns a List of all supported effects for the server + * version + * + * @return Supported effects + */ + public static List getSupportedEffects() { + List effects = new ArrayList(); + for (ParticleEffect pe : values()) + if (pe.isSupported()) effects.add(pe); + return effects; + } + + /** + * Returns the particle effect with the given name + * + * @param name Name of the particle effect + * @return The particle effect + */ + public static ParticleEffect fromName(String name) { + for (Entry entry : NAME_MAP.entrySet()) { + if (!entry.getKey().equalsIgnoreCase(name)) { + continue; + } + return entry.getValue(); + } + return null; + } + + /** + * Returns the particle effect with the given id + * + * @param id Id of the particle effect + * @return The particle effect + */ + public static ParticleEffect fromId(int id) { + for (Entry entry : ID_MAP.entrySet()) { + if (entry.getKey() != id) { + continue; + } + return entry.getValue(); + } + return null; + } + + /** + * Determine if water is at a certain location + * + * @param location Location to check + * @return Whether water is at this location or not + */ + private static boolean isWater(Location location) { + Material material = location.getBlock().getType(); + return material == Material.WATER || material == Material.STATIONARY_WATER; + } + + /** + * Determine if the distance between @param location and one of the players + * exceeds 256 + * + * @param location Location to check + * @return Whether the distance exceeds 256 or not + */ + private static boolean isLongDistance(Location location, List players) { + String world = location.getWorld().getName(); + for (Player player : players) { + Location playerLocation = player.getLocation(); + if (!world.equals(playerLocation.getWorld().getName()) || playerLocation.distanceSquared(location) < 65536) { + continue; + } + return true; + } + return false; + } + + /** + * Determine if the data type for a particle effect is correct + * + * @param effect Particle effect + * @param data Particle data + * @return Whether the data type is correct or not + */ + private static boolean isDataCorrect(ParticleEffect effect, ParticleData data) { + return ((effect == BLOCK_CRACK || effect == BLOCK_DUST || effect == FALLING_DUST) && data instanceof BlockData) || (effect == ITEM_CRACK && data instanceof ItemData); + } + + /** + * Determine if the color type for a particle effect is correct + * + * @param effect Particle effect + * @param color Particle color + * @return Whether the color type is correct or not + */ + private static boolean isColorCorrect(ParticleEffect effect, ParticleColor color) { + return ((effect == MOB_SPELL || effect == MOB_SPELL_AMBIENT || effect == RED_DUST) && color instanceof OrdinaryColor) || (effect == NOTE && color instanceof NoteColor); + } + + /** + * Displays a particle effect which is only visible for all players within a + * certain range in the world of @param center + * + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect requires water + * and none is at the center location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, null).sendTo(center, range); + } + + /** + * Displays a particle effect which is only visible for the specified + * players + * + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect requires water + * and none is at the center location + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), null).sendTo(center, players); + } + + /** + * Displays a particle effect which is only visible for the specified + * players + * + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect requires water + * and none is at the center location + * @see #display(float, float, float, float, int, Location, List) + */ + public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + display(offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for all players within a certain range in the world + * of @param center + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect is not + * directional or if it requires water and none is at the center + * location + * @see ParticlePacket#ParticlePacket(ParticleEffect, Vector, float, + * boolean, ParticleData) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (!hasProperty(ParticleProperty.DIRECTIONAL)) { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, range > 256, null).sendTo(center, range); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for the specified players + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect is not + * directional or if it requires water and none is at the center + * location + * @see ParticlePacket#ParticlePacket(ParticleEffect, Vector, float, + * boolean, ParticleData) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect requires additional data"); + } + if (!hasProperty(ParticleProperty.DIRECTIONAL)) { + throw new IllegalArgumentException("This particle effect is not directional"); + } + if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + } + new ParticlePacket(this, direction, speed, isLongDistance(center, players), null).sendTo(center, players); + } + + /** + * Displays a single particle which flies into a determined direction and is + * only visible for the specified players + * + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect requires additional + * data + * @throws IllegalArgumentException If the particle effect is not + * directional or if it requires water and none is at the center + * location + * @see #display(Vector, float, Location, List) + */ + public void display(Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { + display(direction, speed, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which is colored and only visible for all + * players within a certain range in the world of @param center + * + * @param color Color of the particle + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleColorException If the particle effect is not colorable or + * the color type is incorrect + * @see ParticlePacket#ParticlePacket(ParticleEffect, ParticleColor, + * boolean) + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleColor color, Location center, double range) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); + } + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, range > 256).sendTo(center, range); + } + + /** + * Displays a single particle which is colored and only visible for the + * specified players + * + * @param color Color of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleColorException If the particle effect is not colorable or + * the color type is incorrect + * @see ParticlePacket#ParticlePacket(ParticleEffect, ParticleColor, + * boolean) + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleColor color, Location center, List players) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); + } + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, color, isLongDistance(center, players)).sendTo(center, players); + } + + /** + * Displays a single particle which is colored and only visible for the + * specified players + * + * @param color Color of the particle + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleColorException If the particle effect is not colorable or + * the color type is incorrect + * @see #display(ParticleColor, Location, List) + */ + public void display(ParticleColor color, Location center, Player... players) throws ParticleVersionException, ParticleColorException { + display(color, center, Arrays.asList(players)); + } + + /** + * Displays a particle effect which requires additional data and is only + * visible for all players within a certain range in the world of @param + * center + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, data).sendTo(center, range); + } + + /** + * Displays a particle effect which requires additional data and is only + * visible for the specified players + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Displays a particle effect which requires additional data and is only + * visible for the specified players + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on + * the x-axis + * @param offsetY Maximum distance particles can fly away from the center on + * the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on + * the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see #display(ParticleData, float, float, float, float, int, Location, + * List) + */ + public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException { + display(data, offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); + } + + /** + * Displays a single particle which requires additional data that flies into + * a determined direction and is only visible for all players within a + * certain range in the world of @param center + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, double) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, direction, speed, range > 256, data).sendTo(center, range); + } + + /** + * Displays a single particle which requires additional data that flies into + * a determined direction and is only visible for the specified players + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see ParticlePacket + * @see ParticlePacket#sendTo(Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException { + if (!isSupported()) { + throw new ParticleVersionException("This particle effect is not supported by your server version"); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ParticleDataException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ParticleDataException("The particle data type is incorrect"); + } + new ParticlePacket(this, direction, speed, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Displays a single particle which requires additional data that flies into + * a determined direction and is only visible for the specified players + * + * @param data Data of the effect + * @param direction Direction of the particle + * @param speed Display speed of the particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported + * by the server version + * @throws ParticleDataException If the particle effect does not require + * additional data or if the data type is incorrect + * @see #display(ParticleData, Vector, float, Location, List) + */ + public void display(ParticleData data, Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException { + display(data, direction, speed, center, Arrays.asList(players)); + } + + /** + * Represents the property of a particle effect + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static enum ParticleProperty { + /** + * The particle effect requires water to be displayed + */ + REQUIRES_WATER, + /** + * The particle effect requires block or item data to be displayed + */ + REQUIRES_DATA, + /** + * The particle effect uses the offsets as direction values + */ + DIRECTIONAL, + /** + * The particle effect uses the offsets as color values + */ + COLORABLE; + } + + /** + * Represents the particle data for effects like + * {@link ParticleEffect#ITEM_CRACK}, {@link ParticleEffect#BLOCK_CRACK} and + * {@link ParticleEffect#BLOCK_DUST} + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static abstract class ParticleData { + private final Material material; + private final byte data; + private final int[] packetData; + + /** + * Construct a new particle data + * + * @param material Material of the item/block + * @param data Data value of the item/block + */ + @SuppressWarnings("deprecation") + public ParticleData(Material material, byte data) { + this.material = material; + this.data = data; + this.packetData = new int[] { material.getId(), data }; + } + + /** + * Returns the material of this data + * + * @return The material + */ + public Material getMaterial() { + return material; + } + + /** + * Returns the data value of this data + * + * @return The data value + */ + public byte getData() { + return data; + } + + /** + * Returns the data as an int array for packet construction + * + * @return The data for the packet + */ + public int[] getPacketData() { + return packetData; + } + + /** + * Returns the data as a string for pre 1.8 versions + * + * @return The data string for the packet + */ + public String getPacketDataString() { + return "_" + packetData[0] + "_" + packetData[1]; + } + } + + /** + * Represents the item data for the {@link ParticleEffect#ITEM_CRACK} effect + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class ItemData extends ParticleData { + /** + * Construct a new item data + * + * @param material Material of the item + * @param data Data value of the item + * @see ParticleData#ParticleData(Material, byte) + */ + public ItemData(Material material, byte data) { + super(material, data); + } + } + + /** + * Represents the block data for the {@link ParticleEffect#BLOCK_CRACK} and + * {@link ParticleEffect#BLOCK_DUST} effects + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + public static final class BlockData extends ParticleData { + /** + * Construct a new block data + * + * @param material Material of the block + * @param data Data value of the block + * @throws IllegalArgumentException If the material is not a block + * @see ParticleData#ParticleData(Material, byte) + */ + public BlockData(Material material, byte data) throws IllegalArgumentException { + super(material, data); + if (!material.isBlock()) { + throw new IllegalArgumentException("The material is not a block"); + } + } + } + + /** + * Represents the color for effects like {@link ParticleEffect#SPELL_MOB}, + * {@link ParticleEffect#SPELL_MOB_AMBIENT}, {@link ParticleEffect#REDSTONE} + * and {@link ParticleEffect#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static abstract class ParticleColor { + /** + * Returns the value for the offsetX field + * + * @return The offsetX value + */ + public abstract float getValueX(); + + /** + * Returns the value for the offsetY field + * + * @return The offsetY value + */ + public abstract float getValueY(); + + /** + * Returns the value for the offsetZ field + * + * @return The offsetZ value + */ + public abstract float getValueZ(); + } + + /** + * Represents the color for effects like {@link ParticleEffect#SPELL_MOB}, + * {@link ParticleEffect#SPELL_MOB_AMBIENT} and {@link ParticleEffect#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class OrdinaryColor extends ParticleColor { + private final int red; + private final int green; + private final int blue; + + /** + * Construct a new ordinary color + * + * @param red Red value of the RGB format + * @param green Green value of the RGB format + * @param blue Blue value of the RGB format + * @throws IllegalArgumentException If one of the values is lower than 0 + * or higher than 255 + */ + public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException { + if (red < 0) { + throw new IllegalArgumentException("The red value is lower than 0"); + } + if (red > 255) { + throw new IllegalArgumentException("The red value is higher than 255"); + } + this.red = red; + if (green < 0) { + throw new IllegalArgumentException("The green value is lower than 0"); + } + if (green > 255) { + throw new IllegalArgumentException("The green value is higher than 255"); + } + this.green = green; + if (blue < 0) { + throw new IllegalArgumentException("The blue value is lower than 0"); + } + if (blue > 255) { + throw new IllegalArgumentException("The blue value is higher than 255"); + } + this.blue = blue; + } + + /** + * Construct a new ordinary color + * + * @param color Bukkit color + */ + public OrdinaryColor(Color color) { + this(color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * Returns the red value of the RGB format + * + * @return The red value + */ + public int getRed() { + return red; + } + + /** + * Returns the green value of the RGB format + * + * @return The green value + */ + public int getGreen() { + return green; + } + + /** + * Returns the blue value of the RGB format + * + * @return The blue value + */ + public int getBlue() { + return blue; + } + + /** + * Returns the red value divided by 255 + * + * @return The offsetX value + */ + @Override + public float getValueX() { + return (float) red / 255F; + } + + /** + * Returns the green value divided by 255 + * + * @return The offsetY value + */ + @Override + public float getValueY() { + return (float) green / 255F; + } + + /** + * Returns the blue value divided by 255 + * + * @return The offsetZ value + */ + @Override + public float getValueZ() { + return (float) blue / 255F; + } + } + + /** + * Represents the color for the {@link ParticleEffect#NOTE} effect + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class NoteColor extends ParticleColor { + private final int note; + + /** + * Construct a new note color + * + * @param note Note id which determines color + * @throws IllegalArgumentException If the note value is lower than 0 or + * higher than 24 + */ + public NoteColor(int note) throws IllegalArgumentException { + if (note < 0) { + throw new IllegalArgumentException("The note value is lower than 0"); + } + if (note > 24) { + throw new IllegalArgumentException("The note value is higher than 24"); + } + this.note = note; + } + + /** + * Returns the note value divided by 24 + * + * @return The offsetX value + */ + @Override + public float getValueX() { + return (float) note / 24F; + } + + /** + * Returns zero because the offsetY value is unused + * + * @return zero + */ + @Override + public float getValueY() { + return 0; + } + + /** + * Returns zero because the offsetZ value is unused + * + * @return zero + */ + @Override + public float getValueZ() { + return 0; + } + + } + + /** + * Represents a runtime exception that is thrown either if the displayed + * particle effect requires data and has none or vice-versa or if the data + * type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleDataException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle data exception + * + * @param message Message that will be logged + */ + public ParticleDataException(String message) { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown either if the displayed + * particle effect is not colorable or if the particle color type is + * incorrect + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + private static final class ParticleColorException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle color exception + * + * @param message Message that will be logged + */ + public ParticleColorException(String message) { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown if the displayed particle + * effect requires a newer version + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleVersionException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle version exception + * + * @param message Message that will be logged + */ + public ParticleVersionException(String message) { + super(message); + } + } + + /** + * Represents a particle effect packet with all attributes which is used for + * sending packets to the players + *

+ * This class is part of the ParticleEffect Library and follows the + * same usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + public static final class ParticlePacket { + private static int version; + private static Class enumParticle; + private static Constructor packetConstructor; + private static Method getHandle; + private static Field playerConnection; + private static Method sendPacket; + private static boolean initialized; + private final ParticleEffect effect; + private float offsetX; + private final float offsetY; + private final float offsetZ; + private final float speed; + private final int amount; + private final boolean longDistance; + private final ParticleData data; + private Object packet; + + /** + * Construct a new particle packet + * + * @param effect Particle effect + * @param offsetX Maximum distance particles can fly away from the + * center on the x-axis + * @param offsetY Maximum distance particles can fly away from the + * center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the + * center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param longDistance Indicates whether the maximum distance is + * increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed or amount is lower than + * 0 + * @see #initialize() + */ + public ParticlePacket(ParticleEffect effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException { + initialize(); + if (speed < 0) { + throw new IllegalArgumentException("The speed is lower than 0"); + } + if (amount < 0) { + throw new IllegalArgumentException("The amount is lower than 0"); + } + this.effect = effect; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.offsetZ = offsetZ; + this.speed = speed; + this.amount = amount; + this.longDistance = longDistance; + this.data = data; + } + + /** + * Construct a new particle packet of a single particle flying into a + * determined direction + * + * @param effect Particle effect + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param longDistance Indicates whether the maximum distance is + * increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed is lower than 0 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, + * boolean, ParticleData) + */ + public ParticlePacket(ParticleEffect effect, Vector direction, float speed, boolean longDistance, ParticleData data) throws IllegalArgumentException { + this(effect, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), speed, 0, longDistance, data); + } + + /** + * Construct a new particle packet of a single colored particle + * + * @param effect Particle effect + * @param color Color of the particle + * @param longDistance Indicates whether the maximum distance is + * increased from 256 to 65536 + * @see #ParticleEffect(ParticleEffect, float, float, float, float, int, + * boolean, ParticleData) + */ + public ParticlePacket(ParticleEffect effect, ParticleColor color, boolean longDistance) { + this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), 1, 0, longDistance, null); + if (effect == ParticleEffect.RED_DUST && color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) { + offsetX = Float.MIN_NORMAL; + } + } + + /** + * Initializes {@link #packetConstructor}, {@link #getHandle}, + * {@link #playerConnection} and {@link #sendPacket} and sets + * {@link #initialized} to true if it succeeds + *

+ * Note: These fields only have to be initialized once, so it + * will return if {@link #initialized} is already set to + * true + * + * @throws VersionIncompatibleException if your bukkit version is not + * supported by this library + */ + public static void initialize() throws VersionIncompatibleException { + if (initialized) { + return; + } + try { + String ver = PackageType.getServerVersion(); + int un1 = ver.indexOf("_") + 1; + int un2 = ver.lastIndexOf("_"); + version = Integer.parseInt(ver.substring(un1, un2)); + if (version > 7) { + enumParticle = PackageType.MINECRAFT_SERVER.getClass("EnumParticle"); + } + Class packetClass = PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles"); + packetConstructor = ReflectionUtils.getConstructor(packetClass); + getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle"); + playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection"); + sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet")); + } catch (Exception exception) { + throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with PlayerParticles", exception); + } + initialized = true; + } + + /** + * Returns the version of your server (1.x) + * + * @return The version number + */ + public static int getVersion() { + if (!initialized) { + initialize(); + } + return version; + } + + /** + * Determine if {@link #packetConstructor}, {@link #getHandle}, + * {@link #playerConnection} and {@link #sendPacket} are initialized + * + * @return Whether these fields are initialized or not + * @see #initialize() + */ + public static boolean isInitialized() { + return initialized; + } + + /** + * Initializes {@link #packet} with all set values + * + * @param center Center location of the effect + * @throws PacketInstantiationException If instantion fails due to an + * unknown error + */ + private void initializePacket(Location center) throws PacketInstantiationException { + if (packet != null) { + return; + } + try { + packet = packetConstructor.newInstance(); + if (version < 8) { + String name = effect.getName(); + if (data != null) { + name += data.getPacketDataString(); + } + ReflectionUtils.setValue(packet, true, "a", name); + } else { + ReflectionUtils.setValue(packet, true, "a", enumParticle.getEnumConstants()[effect.getId()]); + ReflectionUtils.setValue(packet, true, "j", longDistance); + if (data != null) { + int[] packetData = data.getPacketData(); + ReflectionUtils.setValue(packet, true, "k", effect == ParticleEffect.ITEM_CRACK ? packetData : new int[] { packetData[0] | (packetData[1] << 12) }); + } + } + ReflectionUtils.setValue(packet, true, "b", (float) center.getX()); + ReflectionUtils.setValue(packet, true, "c", (float) center.getY()); + ReflectionUtils.setValue(packet, true, "d", (float) center.getZ()); + ReflectionUtils.setValue(packet, true, "e", offsetX); + ReflectionUtils.setValue(packet, true, "f", offsetY); + ReflectionUtils.setValue(packet, true, "g", offsetZ); + ReflectionUtils.setValue(packet, true, "h", speed); + ReflectionUtils.setValue(packet, true, "i", amount); + } catch (Exception exception) { + throw new PacketInstantiationException("Packet instantiation failed", exception); + } + } + + /** + * Sends the packet to a single player and caches it + * + * @param center Center location of the effect + * @param player Receiver of the packet + * @throws PacketInstantiationException If instantion fails due to an + * unknown error + * @throws PacketSendingException If sending fails due to an unknown + * error + * @see #initializePacket(Location) + */ + public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException { + initializePacket(center); + try { + sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), packet); + } catch (Exception exception) { + throw new PacketSendingException("Failed to send the packet to player '" + player.getName() + "'", exception); + } + } + + /** + * Sends the packet to all players in the list + * + * @param center Center location of the effect + * @param players Receivers of the packet + * @throws IllegalArgumentException If the player list is empty + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, List players) throws IllegalArgumentException { + if (players.isEmpty()) { + throw new IllegalArgumentException("The player list is empty"); + } + for (Player player : players) { + sendTo(center, player); + } + } + + /** + * Sends the packet to all players in a certain range + * + * @param center Center location of the effect + * @param range Range in which players will receive the packet (Maximum + * range for particles is usually 16, but it can differ for + * some types) + * @throws IllegalArgumentException If the range is lower than 1 + * @see #sendTo(Location center, Player player) + */ + public void sendTo(Location center, double range) throws IllegalArgumentException { + if (range < 1) { + throw new IllegalArgumentException("The range is lower than 1"); + } + String worldName = center.getWorld().getName(); + double squared = range * range; + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.getWorld().getName().equals(worldName) || player.getLocation().distanceSquared(center) > squared) { + continue; + } + sendTo(center, player); + } + } + + /** + * Represents a runtime exception that is thrown if a bukkit version is + * not compatible with this library + *

+ * This class is part of the ParticleEffect Library and follows + * the same usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + private static final class VersionIncompatibleException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new version incompatible exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public VersionIncompatibleException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet instantiation + * fails + *

+ * This class is part of the ParticleEffect Library and follows + * the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketInstantiationException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet instantiation exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketInstantiationException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet sending fails + *

+ * This class is part of the ParticleEffect Library and follows + * the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketSendingException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet sending exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketSendingException(String message, Throwable cause) { + super(message, cause); + } + } + } +} diff --git a/src/com/esophose/playerparticles/library/ReflectionUtils.java b/src/com/esophose/playerparticles/library/ReflectionUtils.java new file mode 100644 index 0000000..49f367e --- /dev/null +++ b/src/com/esophose/playerparticles/library/ReflectionUtils.java @@ -0,0 +1,659 @@ +package com.esophose.playerparticles.library; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; + +/** + * ReflectionUtils + *

+ * This class provides useful methods which makes dealing with reflection much + * easier, especially when working with Bukkit + *

+ * You are welcome to use it, modify it and redistribute it under the following + * conditions: + *

    + *
  • Don't claim this class as your own + *
  • Don't remove this disclaimer + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a + * published project + * + * @author DarkBlade12 + * @version 1.1 + */ +public final class ReflectionUtils { + // Prevent accidental construction + private ReflectionUtils() { + + } + + /** + * Returns the constructor of a given class with the given parameter types + * + * @param clazz Target class + * @param parameterTypes Parameter types of the desired constructor + * @return The constructor of the target class with the specified parameter + * types + * @throws NoSuchMethodException If the desired constructor with the + * specified parameter types cannot be found + * @see DataType + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Constructor getConstructor(Class clazz, Class... parameterTypes) throws NoSuchMethodException { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for (Constructor constructor : clazz.getConstructors()) { + if (!DataType.compare(DataType.getPrimitive(constructor.getParameterTypes()), primitiveTypes)) { + continue; + } + return constructor; + } + throw new NoSuchMethodException("There is no such constructor in this class with the specified parameter types"); + } + + /** + * Returns the constructor of a desired class with the given parameter types + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param parameterTypes Parameter types of the desired constructor + * @return The constructor of the desired target class with the specified + * parameter types + * @throws NoSuchMethodException If the desired constructor with the + * specified parameter types cannot be found + * @throws ClassNotFoundException ClassNotFoundException If the desired + * target class with the specified name and package cannot be + * found + * @see #getClass(String, PackageType) + * @see #getConstructor(Class, Class...) + */ + public static Constructor getConstructor(String className, PackageType packageType, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException { + return getConstructor(packageType.getClass(className), parameterTypes); + } + + /** + * Returns an instance of a class with the given arguments + * + * @param clazz Target class + * @param arguments Arguments which are used to construct an object of the + * target class + * @return The instance of the target class with the specified arguments + * @throws InstantiationException If you cannot create an instance of the + * target class due to certain circumstances + * @throws IllegalAccessException If the desired constructor cannot be + * accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not + * match the parameter types of the constructor (this should not + * occur since it searches for a constructor with the types of + * the arguments) + * @throws InvocationTargetException If the desired constructor cannot be + * invoked + * @throws NoSuchMethodException If the desired constructor with the + * specified arguments cannot be found + */ + public static Object instantiateObject(Class clazz, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getConstructor(clazz, DataType.getPrimitive(arguments)).newInstance(arguments); + } + + /** + * Returns an instance of a desired class with the given arguments + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param arguments Arguments which are used to construct an object of the + * desired target class + * @return The instance of the desired target class with the specified + * arguments + * @throws InstantiationException If you cannot create an instance of the + * desired target class due to certain circumstances + * @throws IllegalAccessException If the desired constructor cannot be + * accessed due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not + * match the parameter types of the constructor (this should not + * occur since it searches for a constructor with the types of + * the arguments) + * @throws InvocationTargetException If the desired constructor cannot be + * invoked + * @throws NoSuchMethodException If the desired constructor with the + * specified arguments cannot be found + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #instantiateObject(Class, Object...) + */ + public static Object instantiateObject(String className, PackageType packageType, Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { + return instantiateObject(packageType.getClass(className), arguments); + } + + /** + * Returns a method of a class with the given parameter types + * + * @param clazz Target class + * @param methodName Name of the desired method + * @param parameterTypes Parameter types of the desired method + * @return The method of the target class with the specified name and + * parameter types + * @throws NoSuchMethodException If the desired method of the target class + * with the specified name and parameter types cannot be found + * @see DataType#getPrimitive(Class[]) + * @see DataType#compare(Class[], Class[]) + */ + public static Method getMethod(Class clazz, String methodName, Class... parameterTypes) throws NoSuchMethodException { + Class[] primitiveTypes = DataType.getPrimitive(parameterTypes); + for (Method method : clazz.getMethods()) { + if (!method.getName().equals(methodName) || !DataType.compare(DataType.getPrimitive(method.getParameterTypes()), primitiveTypes)) { + continue; + } + return method; + } + throw new NoSuchMethodException("There is no such method in this class with the specified name and parameter types"); + } + + /** + * Returns a method of a desired class with the given parameter types + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param methodName Name of the desired method + * @param parameterTypes Parameter types of the desired method + * @return The method of the desired target class with the specified name + * and parameter types + * @throws NoSuchMethodException If the desired method of the desired target + * class with the specified name and parameter types cannot be + * found + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #getMethod(Class, String, Class...) + */ + public static Method getMethod(String className, PackageType packageType, String methodName, Class... parameterTypes) throws NoSuchMethodException, ClassNotFoundException { + return getMethod(packageType.getClass(className), methodName, parameterTypes); + } + + /** + * Invokes a method on an object with the given arguments + * + * @param instance Target object + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed + * due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not + * match the parameter types of the method (this should not + * occur since it searches for a method with the types of the + * arguments) + * @throws InvocationTargetException If the desired method cannot be invoked + * on the target object + * @throws NoSuchMethodException If the desired method of the class of the + * target object with the specified name and arguments cannot be + * found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getMethod(instance.getClass(), methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of the target class on an object with the given + * arguments + * + * @param instance Target object + * @param clazz Target class + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed + * due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not + * match the parameter types of the method (this should not + * occur since it searches for a method with the types of the + * arguments) + * @throws InvocationTargetException If the desired method cannot be invoked + * on the target object + * @throws NoSuchMethodException If the desired method of the target class + * with the specified name and arguments cannot be found + * @see #getMethod(Class, String, Class...) + * @see DataType#getPrimitive(Object[]) + */ + public static Object invokeMethod(Object instance, Class clazz, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return getMethod(clazz, methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments); + } + + /** + * Invokes a method of a desired class on an object with the given arguments + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param methodName Name of the desired method + * @param arguments Arguments which are used to invoke the desired method + * @return The result of invoking the desired method on the target object + * @throws IllegalAccessException If the desired method cannot be accessed + * due to certain circumstances + * @throws IllegalArgumentException If the types of the arguments do not + * match the parameter types of the method (this should not + * occur since it searches for a method with the types of the + * arguments) + * @throws InvocationTargetException If the desired method cannot be invoked + * on the target object + * @throws NoSuchMethodException If the desired method of the desired target + * class with the specified name and arguments cannot be found + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getClass(String, PackageType) + * @see #invokeMethod(Object, Class, String, Object...) + */ + public static Object invokeMethod(Object instance, String className, PackageType packageType, String methodName, Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { + return invokeMethod(instance, packageType.getClass(className), methodName, arguments); + } + + /** + * Returns a field of the target class with the given name + * + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The field of the target class with the specified name + * @throws NoSuchFieldException If the desired field of the given class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + */ + public static Field getField(Class clazz, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException { + Field field = declared ? clazz.getDeclaredField(fieldName) : clazz.getField(fieldName); + field.setAccessible(true); + return field; + } + + /** + * Returns a field of a desired class with the given name + * + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The field of the desired target class with the specified name + * @throws NoSuchFieldException If the desired field of the desired class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getField(Class, boolean, String) + */ + public static Field getField(String className, PackageType packageType, boolean declared, String fieldName) throws NoSuchFieldException, SecurityException, ClassNotFoundException { + return getField(packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field of the given class of an object + * + * @param instance Target object + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature + * the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static Object getValue(Object instance, Class clazz, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + return getField(clazz, declared, fieldName).get(instance); + } + + /** + * Returns the value of a field of a desired class of an object + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature + * the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the desired class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException { + return getValue(instance, packageType.getClass(className), declared, fieldName); + } + + /** + * Returns the value of a field with the given name of an object + * + * @param instance Target object + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @return The value of field of the target object + * @throws IllegalArgumentException If the target object does not feature + * the desired field (should not occur since it searches for a + * field with the given name in the class of the object) + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target object + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getValue(Object, Class, boolean, String) + */ + public static Object getValue(Object instance, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + return getValue(instance, instance.getClass(), declared, fieldName); + } + + /** + * Sets the value of a field of the given class of an object + * + * @param instance Target object + * @param clazz Target class + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match + * the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #getField(Class, boolean, String) + */ + public static void setValue(Object instance, Class clazz, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + getField(clazz, declared, fieldName).set(instance, value); + } + + /** + * Sets the value of a field of a desired class of an object + * + * @param instance Target object + * @param className Name of the desired target class + * @param packageType Package where the desired target class is located + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match + * the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the desired class + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @throws ClassNotFoundException If the desired target class with the + * specified name and package cannot be found + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, String className, PackageType packageType, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException { + setValue(instance, packageType.getClass(className), declared, fieldName, value); + } + + /** + * Sets the value of a field with the given name of an object + * + * @param instance Target object + * @param declared Whether the desired field is declared or not + * @param fieldName Name of the desired field + * @param value New value + * @throws IllegalArgumentException If the type of the value does not match + * the type of the desired field + * @throws IllegalAccessException If the desired field cannot be accessed + * @throws NoSuchFieldException If the desired field of the target object + * cannot be found + * @throws SecurityException If the desired field cannot be made accessible + * @see #setValue(Object, Class, boolean, String, Object) + */ + public static void setValue(Object instance, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + setValue(instance, instance.getClass(), declared, fieldName, value); + } + + /** + * Represents an enumeration of dynamic packages of NMS and CraftBukkit + *

+ * This class is part of the ReflectionUtils and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum PackageType { + MINECRAFT_SERVER("net.minecraft.server." + getServerVersion()), CRAFTBUKKIT("org.bukkit.craftbukkit." + getServerVersion()), CRAFTBUKKIT_BLOCK(CRAFTBUKKIT, "block"), CRAFTBUKKIT_CHUNKIO(CRAFTBUKKIT, "chunkio"), CRAFTBUKKIT_COMMAND(CRAFTBUKKIT, "command"), CRAFTBUKKIT_CONVERSATIONS(CRAFTBUKKIT, "conversations"), CRAFTBUKKIT_ENCHANTMENS(CRAFTBUKKIT, "enchantments"), CRAFTBUKKIT_ENTITY(CRAFTBUKKIT, "entity"), CRAFTBUKKIT_EVENT(CRAFTBUKKIT, "event"), CRAFTBUKKIT_GENERATOR(CRAFTBUKKIT, "generator"), CRAFTBUKKIT_HELP(CRAFTBUKKIT, "help"), CRAFTBUKKIT_INVENTORY(CRAFTBUKKIT, "inventory"), CRAFTBUKKIT_MAP(CRAFTBUKKIT, "map"), CRAFTBUKKIT_METADATA(CRAFTBUKKIT, "metadata"), CRAFTBUKKIT_POTION(CRAFTBUKKIT, "potion"), CRAFTBUKKIT_PROJECTILES(CRAFTBUKKIT, "projectiles"), CRAFTBUKKIT_SCHEDULER(CRAFTBUKKIT, "scheduler"), CRAFTBUKKIT_SCOREBOARD(CRAFTBUKKIT, "scoreboard"), CRAFTBUKKIT_UPDATER(CRAFTBUKKIT, "updater"), CRAFTBUKKIT_UTIL(CRAFTBUKKIT, "util"); + + private final String path; + + /** + * Construct a new package type + * + * @param path Path of the package + */ + private PackageType(String path) { + this.path = path; + } + + /** + * Construct a new package type + * + * @param parent Parent package of the package + * @param path Path of the package + */ + private PackageType(PackageType parent, String path) { + this(parent + "." + path); + } + + /** + * Returns the path of this package type + * + * @return The path + */ + public String getPath() { + return path; + } + + /** + * Returns the class with the given name + * + * @param className Name of the desired class + * @return The class with the specified name + * @throws ClassNotFoundException If the desired class with the + * specified name and package cannot be found + */ + public Class getClass(String className) throws ClassNotFoundException { + return Class.forName(this + "." + className); + } + + // Override for convenience + @Override + public String toString() { + return path; + } + + /** + * Returns the version of your server + * + * @return The server version + */ + public static String getServerVersion() { + return Bukkit.getServer().getClass().getPackage().getName().substring(23); + } + } + + /** + * Represents an enumeration of Java data types with corresponding classes + *

+ * This class is part of the ReflectionUtils and follows the same + * usage conditions + * + * @author DarkBlade12 + * @since 1.0 + */ + public enum DataType { + BYTE(byte.class, Byte.class), SHORT(short.class, Short.class), INTEGER(int.class, Integer.class), LONG(long.class, Long.class), CHARACTER(char.class, Character.class), FLOAT(float.class, Float.class), DOUBLE(double.class, Double.class), BOOLEAN(boolean.class, Boolean.class); + + private static final Map, DataType> CLASS_MAP = new HashMap, DataType>(); + private final Class primitive; + private final Class reference; + + // Initialize map for quick class lookup + static { + for (DataType type : values()) { + CLASS_MAP.put(type.primitive, type); + CLASS_MAP.put(type.reference, type); + } + } + + /** + * Construct a new data type + * + * @param primitive Primitive class of this data type + * @param reference Reference class of this data type + */ + private DataType(Class primitive, Class reference) { + this.primitive = primitive; + this.reference = reference; + } + + /** + * Returns the primitive class of this data type + * + * @return The primitive class + */ + public Class getPrimitive() { + return primitive; + } + + /** + * Returns the reference class of this data type + * + * @return The reference class + */ + public Class getReference() { + return reference; + } + + /** + * Returns the data type with the given primitive/reference class + * + * @param clazz Primitive/Reference class of the data type + * @return The data type + */ + public static DataType fromClass(Class clazz) { + return CLASS_MAP.get(clazz); + } + + /** + * Returns the primitive class of the data type with the given reference + * class + * + * @param clazz Reference class of the data type + * @return The primitive class + */ + public static Class getPrimitive(Class clazz) { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getPrimitive(); + } + + /** + * Returns the reference class of the data type with the given primitive + * class + * + * @param clazz Primitive class of the data type + * @return The reference class + */ + public static Class getReference(Class clazz) { + DataType type = fromClass(clazz); + return type == null ? clazz : type.getReference(); + } + + /** + * Returns the primitive class array of the given class array + * + * @param classes Given class array + * @return The primitive class array + */ + public static Class[] getPrimitive(Class[] classes) { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getPrimitive(classes[index]); + } + return types; + } + + /** + * Returns the reference class array of the given class array + * + * @param classes Given class array + * @return The reference class array + */ + public static Class[] getReference(Class[] classes) { + int length = classes == null ? 0 : classes.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getReference(classes[index]); + } + return types; + } + + /** + * Returns the primitive class array of the given object array + * + * @param object Given object array + * @return The primitive class array + */ + public static Class[] getPrimitive(Object[] objects) { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getPrimitive(objects[index].getClass()); + } + return types; + } + + /** + * Returns the reference class array of the given object array + * + * @param object Given object array + * @return The reference class array + */ + public static Class[] getReference(Object[] objects) { + int length = objects == null ? 0 : objects.length; + Class[] types = new Class[length]; + for (int index = 0; index < length; index++) { + types[index] = getReference(objects[index].getClass()); + } + return types; + } + + /** + * Compares two class arrays on equivalence + * + * @param primary Primary class array + * @param secondary Class array which is compared to the primary array + * @return Whether these arrays are equal or not + */ + public static boolean compare(Class[] primary, Class[] secondary) { + if (primary == null || secondary == null || primary.length != secondary.length) { + return false; + } + for (int index = 0; index < primary.length; index++) { + Class primaryClass = primary[index]; + Class secondaryClass = secondary[index]; + if (primaryClass.equals(secondaryClass) || primaryClass.isAssignableFrom(secondaryClass)) { + continue; + } + return false; + } + return true; + } + } +} diff --git a/src/com/esophose/playerparticles/library/database/MySQL.java b/src/com/esophose/playerparticles/library/database/MySQL.java deleted file mode 100644 index 1dd0f8d..0000000 --- a/src/com/esophose/playerparticles/library/database/MySQL.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.esophose.playerparticles.library.database; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -/** - * Connects to and uses a MySQL database - * - * @author -_Husky_- - * @author tips48 - */ -public class MySQL extends Database { - private final String user; - private final String database; - private final String password; - private final String port; - private final String hostname; - - /** - * Creates a new MySQL instance - * - * @param hostname - * Name of the host - * @param port - * Port number - * @param username - * Username - * @param password - * Password - */ - public MySQL(String hostname, String port, String username, - String password) { - this(hostname, port, null, username, password); - } - - /** - * Creates a new MySQL instance for a specific database - * - * @param hostname - * Name of the host - * @param port - * Port number - * @param database - * Database name - * @param username - * Username - * @param password - * Password - */ - public MySQL(String hostname, String port, String database, - String username, String password) { - this.hostname = hostname; - this.port = port; - this.database = database; - this.user = username; - this.password = password; - } - - @Override - public Connection openConnection() throws SQLException, - ClassNotFoundException { - if (checkConnection()) { - return connection; - } - - String connectionURL = "jdbc:mysql://" - + this.hostname + ":" + this.port; - if (database != null) { - connectionURL = connectionURL + "/" + this.database; - } - - Class.forName("com.mysql.jdbc.Driver"); - connection = DriverManager.getConnection(connectionURL, - this.user, this.password); - return connection; - } -} diff --git a/src/com/esophose/playerparticles/manager/ConfigManager.java b/src/com/esophose/playerparticles/manager/ConfigManager.java index 69d7b54..5cc9166 100644 --- a/src/com/esophose/playerparticles/manager/ConfigManager.java +++ b/src/com/esophose/playerparticles/manager/ConfigManager.java @@ -12,28 +12,32 @@ import java.io.File; import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; +import java.util.UUID; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; +import com.esophose.playerparticles.PPlayer; import com.esophose.playerparticles.ParticleCreator; -import com.esophose.playerparticles.ParticleStyle; import com.esophose.playerparticles.PlayerParticles; -import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType; +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.library.ParticleEffect.BlockData; +import com.esophose.playerparticles.library.ParticleEffect.ItemData; +import com.esophose.playerparticles.library.ParticleEffect.NoteColor; +import com.esophose.playerparticles.library.ParticleEffect.OrdinaryColor; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; public class ConfigManager { - + /** * The instance of the ConfigManager used for effect data */ - private static ConfigManager instance = new ConfigManager("effectData"); - /** - * The instance of the ConfigManager used for style data - */ - private static ConfigManager styleInstance = new ConfigManager("styleData"); + private static ConfigManager instance = new ConfigManager("playerData"); /** * The file the data is located in for the instance */ @@ -42,216 +46,355 @@ public class ConfigManager { * The configuration used to edit the .yaml file */ private FileConfiguration config; - + /** * @return The instance of the config for effects */ public static ConfigManager getInstance() { return instance; } - + /** - * @return The instance of the config for styles + * @param fileName The name of the file */ - public static ConfigManager getStyleInstance() { - return styleInstance; - } - - /** - * @param fileName Will either be "effectData" or "styleData" - */ - private ConfigManager(String fileName) { + private ConfigManager(String fileName) { if (!PlayerParticles.getPlugin().getDataFolder().exists()) PlayerParticles.getPlugin().getDataFolder().mkdir(); - + file = new File(PlayerParticles.getPlugin().getDataFolder(), fileName + ".yml"); - + if (!file.exists()) { - try { file.createNewFile(); } - catch (Exception e) { e.printStackTrace(); } + try { + file.createNewFile(); + } catch (Exception e) { + e.printStackTrace(); + } } - + config = YamlConfiguration.loadConfiguration(file); } - + /** - * Removes any data contained within the current config instance - * Never used + * Saves the playerData.yml file to disk */ - public void flushData() { - for(String key : config.getKeys(false)) { - config.set(key, null); - } - try {config.save(file);} - catch (IOException e) {e.printStackTrace();} - } - - /** - * Removes all the player, effect, and style data from the connected database - * Never used - */ - public static void flushDatabase() { - if(PlayerParticles.useMySQL) { - Statement statement; - try { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("TRUNCATE playerparticles;"); - } catch (SQLException e) { - e.printStackTrace(); - } + private void save() { + try { + config.save(file); + } catch (IOException e) { + e.printStackTrace(); } } - + /** - * Saves the particle effect to the player's name in either the database or config - * Should only be called from the effectData instance + * Gets a player from the save data, creates one if it doesn't exist and adds it to the list + */ + public PPlayer getPPlayer(UUID playerUUID) { + for (PPlayer pp : ParticleCreator.particlePlayers) { + if (pp.getUniqueId() == playerUUID) return pp; + } + + PPlayer pplayer = buildPPlayer(playerUUID); + ParticleCreator.particlePlayers.add(pplayer); + return pplayer; + } + + /** + * Gets a PPlayer matching the UUID given + * One will be created if it doesn't exist * - * @param type The type of the particle - * @param player The player to save the particle to + * @param playerUUID The UUID to match the PPlayer to + * @return */ - public void setParticle(ParticleType type, Player player){ - if(PlayerParticles.useMySQL) { - Statement statement; - try { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("UPDATE playerparticles SET particle = '" + type.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';"); - } catch (SQLException e) { + private PPlayer buildPPlayer(UUID playerUUID) { + if (!PlayerParticles.useMySQL) { + if (config.getString(playerUUID.toString() + ".style.name") != null) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString()); + ConfigurationSection effectSection = section.getConfigurationSection("effect"); + ConfigurationSection styleSection = section.getConfigurationSection("style"); + ConfigurationSection itemDataSection = section.getConfigurationSection("itemData"); + ConfigurationSection blockDataSection = section.getConfigurationSection("blockData"); + ConfigurationSection colorDataSection = section.getConfigurationSection("colorData"); + ConfigurationSection noteColorDataSection = section.getConfigurationSection("noteColorData"); + + ParticleEffect particleEffect = ParticleEffect.fromName(effectSection.getString("name")); + ParticleStyle particleStyle = ParticleStyleManager.styleFromString(styleSection.getString("name")); + ItemData particleItemData = new ItemData(Material.matchMaterial(itemDataSection.getString("material")), (byte) itemDataSection.getInt("data")); + BlockData particleBlockData = new BlockData(Material.matchMaterial(blockDataSection.getString("material")), (byte) blockDataSection.getInt("data")); + OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(colorDataSection.getInt("r"), colorDataSection.getInt("g"), colorDataSection.getInt("b"))); + NoteColor particleNoteColorData = new NoteColor(noteColorDataSection.getInt("note")); + + return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); + } else { + PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); + saveEntirePPlayer(pplayer); + return pplayer; + } + } else { + String id = playerUUID.toString(); // @formatter:off + try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT * FROM pp_users u " + + "JOIN pp_data_item i ON u.player_uuid = i.player_uuid " + + "JOIN pp_data_block b ON u.player_uuid = b.player_uuid" + + "JOIN pp_data_color c ON u.player_uuid = c.player_uuid" + + "JOIN pp_data_note n ON u.player_uuid = n.player_uuid" + + "WHERE player_uuid = '" + id + "'")) { // @formatter:on + if (res.next()) { + ParticleEffect particleEffect = ParticleEffect.fromName(res.getString("u.effect")); + ParticleStyle particleStyle = ParticleStyleManager.styleFromString(res.getString("u.style")); + ItemData particleItemData = new ItemData(Material.matchMaterial(res.getString("i.material")), res.getByte("i.data")); + BlockData particleBlockData = new BlockData(Material.matchMaterial(res.getString("b.material")), res.getByte("b.data")); + OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(res.getByte("c.r"), res.getByte("c.g"), res.getByte("c.b"))); + NoteColor particleNoteColorData = new NoteColor(res.getByte("n.note")); + + return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); + } else { + PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); + saveEntirePPlayer(pplayer); + return pplayer; + } + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - config.set(player.getName(), type.toString().toLowerCase().replace("_", "")); - try {config.save(file);} - catch (IOException e) {e.printStackTrace();} } + + return null; // This should never get called unless there is a database error } - + /** - * Removes the particle effect from the player's name in either the database or config - * Should only be called from the effectData instance + * Saves an entire PPlayer to the database + * This is mainly used for when PPlayers are being created for the first time + * It can also be called when a player is getting reset with /pp reset + * Use the singular methods for updating individual parts of the PPlayer * - * @param player The player to clear the particle effect from + * @param pplayer The PPlayer to save */ - public void resetParticle(Player player){ - if(PlayerParticles.useMySQL) { - Statement statement; - try { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("UPDATE playerparticles SET particle = NULL WHERE player_name = '" + player.getName() + "';"); - } catch (SQLException e) { + public void saveEntirePPlayer(PPlayer pplayer) { + if (!PlayerParticles.useMySQL) { + if (!config.isConfigurationSection(pplayer.getUniqueId().toString())) { + String id = pplayer.getUniqueId().toString(); + config.createSection(id); + config.createSection(id + ".effect"); + config.createSection(id + ".style"); + config.createSection(id + ".itemData"); + config.createSection(id + ".blockData"); + config.createSection(id + ".colorData"); + config.createSection(id + ".noteColorData"); + } + + ConfigurationSection section = config.getConfigurationSection(pplayer.getUniqueId().toString()); + ConfigurationSection effectSection = section.getConfigurationSection("effect"); + ConfigurationSection styleSection = section.getConfigurationSection("style"); + ConfigurationSection itemDataSection = section.getConfigurationSection("itemData"); + ConfigurationSection blockDataSection = section.getConfigurationSection("blockData"); + ConfigurationSection colorDataSection = section.getConfigurationSection("colorData"); + ConfigurationSection noteColorDataSection = section.getConfigurationSection("noteColorData"); + + effectSection.set("name", pplayer.getParticleEffect().getName()); + styleSection.set("name", pplayer.getParticleStyle().getName()); + itemDataSection.set("material", pplayer.getItemData().getMaterial().name()); + itemDataSection.set("data", pplayer.getItemData().getData()); + blockDataSection.set("material", pplayer.getBlockData().getMaterial().name()); + blockDataSection.set("data", pplayer.getBlockData().getData()); + colorDataSection.set("r", pplayer.getColorData().getRed()); + colorDataSection.set("g", pplayer.getColorData().getGreen()); + colorDataSection.set("b", pplayer.getColorData().getBlue()); + noteColorDataSection.set("note", (byte) (pplayer.getNoteColorData().getValueX() * 24)); + + save(); + } else { + try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT COUNT(*) FROM pp_users WHERE player_uuid = '" + pplayer.getUniqueId() + "'")) { + if (res.next()) { // @formatter:off + PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET " + + "effect = '" + pplayer.getParticleEffect().getName() + "', " + + "style = '" + pplayer.getParticleStyle().getName() + "' " + + "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + + "UPDATE pp_data_item SET " + + "material = '" + pplayer.getItemData().getMaterial().name() + "', " + + "data = " + pplayer.getItemData().getData() + " " + + "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + + "UPDATE pp_date_block SET " + + "material = '" + pplayer.getBlockData().getMaterial().name() + "', " + + "data = " + pplayer.getBlockData().getData() + " " + + "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + + "UPDATE pp_data_color SET " + + "r = " + pplayer.getColorData().getRed() + ", " + + "g = " + pplayer.getColorData().getGreen() + ", " + + "b = " + pplayer.getColorData().getBlue() + " " + + "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + + "UPDATE pp_data_note SET" + + "note = " + (byte) (pplayer.getNoteColorData().getValueX() * 24) + " " + + "WHERE player_uuid = " + pplayer.getUniqueId().toString() + ";" + ); + } else { + PlayerParticles.mySQL.updateSQL("INSERT INTO pp_users (player_uuid, effect, style) VALUES (" + + "'" + pplayer.getUniqueId().toString() + "', " + + "'" + pplayer.getParticleEffect().getName() + "', " + + "'" + pplayer.getParticleStyle().getName() + "'" + + "); " + + "INSERT INTO pp_data_item (material, data) VALUES (" + + "'" + pplayer.getItemData().getMaterial().name() + "', " + + pplayer.getItemData().getData() + + "); " + + "INSERT INTO pp_data_block (material, data) VALUES (" + + "'" + pplayer.getBlockData().getMaterial().name() + "', " + + pplayer.getBlockData().getData() + + "); " + + "INSERT INTO pp_data_color (r, g, b) VALUES (" + + pplayer.getColorData().getRed() + ", " + + pplayer.getColorData().getGreen() + ", " + + pplayer.getColorData().getBlue() + + "); " + + "INSERT INTO pp_data_note (note) VALUES (" + + (byte) (pplayer.getNoteColorData().getValueX() * 24) + + ");" + ); + } // @formatter:on + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - config.set(player.getName(), ParticleStyle.NONE.toString().toLowerCase().replace("_", "")); - try {config.save(file);} - catch (IOException e) {e.printStackTrace();} } + + ParticleCreator.updateIfContains(pplayer); // Update the player in case this is a /pp reset } - + /** - * Gets the particle effect saved in either the database or config for the player + * Saves the effect to the player's save file or database entry * - * @param player The player to get the particle effect data for - * @return The particle effect for the player + * @param playerUUID The UUID of the player + * @param particleStyle The effect that is being saved */ - public ParticleType getParticle(Player player){ - if(PlayerParticles.useMySQL) { - Statement statement; + public void savePPlayer(UUID playerUUID, ParticleEffect particleEffect) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".effect"); + section.set("name", particleEffect.getName()); + save(); + } else { try { - statement = PlayerParticles.c.createStatement(); - ResultSet res = statement.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + player.getName() + "';"); - res.next(); - return ParticleCreator.particleFromString(res.getString("particle")); - } catch (SQLException e) { + PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET effect = '" + particleEffect.getName() + "' WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - String effectToLowerCase = (String) config.getString(player.getName()); - return ParticleCreator.particleFromString(effectToLowerCase); } - return null; + getPPlayer(playerUUID).setParticleEffect(particleEffect); } - + /** - * Saves the style effect to the player's name in either the database or config - * Should only be called from the effectData instance + * Saves the style to the player's save file or database entry * - * @param style The style to save for the player - * @param player The player to save the style to + * @param playerUUID The UUID of the player + * @param particleStyle The style that is being saved */ - public void setStyle(ParticleStyle style, Player player) { - if(PlayerParticles.useMySQL) { - Statement statement; + public void savePPlayer(UUID playerUUID, ParticleStyle particleStyle) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".style"); + section.set("name", particleStyle.getName()); + save(); + } else { try { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("UPDATE playerparticles SET style = '" + style.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';"); - } catch (SQLException e) { + PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET style = '" + particleStyle.getName() + "' WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - config.set(player.getName(), style.toString().toLowerCase().replace("_", "")); - try {config.save(file);} - catch (IOException e) {e.printStackTrace();} } + getPPlayer(playerUUID).setParticleStyle(particleStyle); } - + /** - * Removes the particle effect from the player's name in either the database or config - * Should only be called from the effectData instance + * Saves the item data to the player's save file or database entry * - * @param player The player to reset the style for + * @param playerUUID The UUID of the player + * @param particleItemData The data that is being saved */ - public void resetStyle(Player player) { - if(PlayerParticles.useMySQL) { - Statement statement; + public void savePPlayer(UUID playerUUID, ItemData particleItemData) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".itemData"); + section.set("material", particleItemData.getMaterial().name()); + section.set("data", particleItemData.getData()); + save(); + } else { try { - statement = PlayerParticles.c.createStatement(); - statement.executeUpdate("UPDATE playerparticles SET style = '" + ParticleStyle.NONE.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';"); - } catch (SQLException e) { + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_item SET material = '" + particleItemData.getMaterial().name() + "', data = '" + particleItemData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - config.set(player.getName(), ParticleStyle.NONE.toString().toLowerCase().replace("_", "")); - try {config.save(file);} - catch (IOException e) {e.printStackTrace();} } + getPPlayer(playerUUID).setItemData(particleItemData); } - + /** - * Gets the particle effect saved in either the database or config for the player + * Saves the block data to the player's save file or database entry * - * @param player The player to get the particle style for - * @return The particle style for the player + * @param playerUUID The UUID of the player + * @param particleBlockData The data that is being saved */ - public ParticleStyle getStyle(Player player) { - if(PlayerParticles.useMySQL) { - Statement statement; + public void savePPlayer(UUID playerUUID, BlockData particleBlockData) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".blockData"); + section.set("material", particleBlockData.getMaterial().name()); + section.set("data", particleBlockData.getData()); + save(); + } else { try { - statement = PlayerParticles.c.createStatement(); - ResultSet res = statement.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + player.getName() + "';"); - res.next(); - return ParticleStyle.styleFromString(res.getString("style")); - } catch (SQLException e) { + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_block SET material = '" + particleBlockData.getMaterial().name() + "', data = '" + particleBlockData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } - }else{ - String styleToLowerCase = (String) config.getString(player.getName()); - return ParticleStyle.styleFromString(styleToLowerCase); } - return ParticleStyle.NONE; + getPPlayer(playerUUID).setBlockData(particleBlockData); } - + + /** + * Saves the color data to the player's save file or database entry + * + * @param playerUUID The UUID of the player + * @param particleColorData The data that is being saved + */ + public void savePPlayer(UUID playerUUID, OrdinaryColor particleColorData) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".colorData"); + section.set("r", particleColorData.getRed()); + section.set("g", particleColorData.getGreen()); + section.set("b", particleColorData.getBlue()); + save(); + } else { + try { + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET r = " + particleColorData.getRed() + ", g = " + particleColorData.getGreen() + ", b = " + particleColorData.getBlue() + " WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + } + getPPlayer(playerUUID).setColorData(particleColorData); + } + + /** + * Saves the note color data to the player's save file or database entry + * + * @param playerUUID The UUID of the player + * @param particleNoteColorData The data that is being saved + */ + public void savePPlayer(UUID playerUUID, NoteColor particleNoteColorData) { + if (!PlayerParticles.useMySQL) { + ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".noteColorData"); + section.set("note", (byte) (particleNoteColorData.getValueX() * 24)); + save(); + } else { + try { + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET note = " + (byte) (particleNoteColorData.getValueX() * 24) + " WHERE player_uuid = " + playerUUID + ";"); + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + } + getPPlayer(playerUUID).setNoteColorData(particleNoteColorData); + } + /** * Checks if a world is disabled for particles to spawn in * * @param world The world name to check * @return True if the world is disabled */ - @SuppressWarnings("unchecked") public boolean isWorldDisabled(String world) { - if(PlayerParticles.getPlugin().getConfig().get("disabled-worlds") != null && ((ArrayList) PlayerParticles.getPlugin().getConfig().get("disabled-worlds")).contains(world)) { - return true; - }else return false; + return getDisabledWorlds().contains(world); } - + /** * Gets all the worlds that are disabled * @@ -259,9 +402,9 @@ public class ConfigManager { */ @SuppressWarnings("unchecked") public ArrayList getDisabledWorlds() { - if(PlayerParticles.getPlugin().getConfig().get("disabled-worlds") != null) { + if (PlayerParticles.getPlugin().getConfig().get("disabled-worlds") != null) { return ((ArrayList) PlayerParticles.getPlugin().getConfig().get("disabled-worlds")); - }else return null; + } else return null; } - + } diff --git a/src/com/esophose/playerparticles/manager/MessageManager.java b/src/com/esophose/playerparticles/manager/MessageManager.java index 78f7e07..3fbb36f 100644 --- a/src/com/esophose/playerparticles/manager/MessageManager.java +++ b/src/com/esophose/playerparticles/manager/MessageManager.java @@ -14,7 +14,7 @@ import org.bukkit.entity.Player; import com.esophose.playerparticles.PlayerParticles; public class MessageManager { - + /** * The instance of the MessageManager, we only need one of these */ @@ -27,7 +27,7 @@ public class MessageManager { * The prefix to place before all sent messages contained in the config */ private String messagePrefix; - + /** * Sets up all the above variables with values from the plugin config */ @@ -35,9 +35,9 @@ public class MessageManager { this.messagesEnabled = PlayerParticles.getPlugin().getConfig().getBoolean("messages-enabled"); this.prefixEnabled = PlayerParticles.getPlugin().getConfig().getBoolean("use-message-prefix"); this.messagePrefix = PlayerParticles.getPlugin().getConfig().getString("message-prefix"); - this.messagePrefix = this.messagePrefix.replace("&", "§"); + this.messagePrefix = ChatColor.translateAlternateColorCodes('&', this.messagePrefix); } - + /** * Gets the instance of the MessageManager * @@ -46,7 +46,7 @@ public class MessageManager { public static MessageManager getInstance() { return instance; } - + /** * Sends a message to a player * @@ -55,28 +55,41 @@ public class MessageManager { * @param color The chat color to put before the message */ public void sendMessage(Player player, String message, ChatColor color) { - if(!this.messagesEnabled) return; - if(this.prefixEnabled) { + if (!this.messagesEnabled) return; + if (this.prefixEnabled) { message = this.messagePrefix + color + " " + message; - }else{ + } else { message = color + message; } player.sendMessage(message); } - + + /** + * Sends a player a message without any custom coloring + * This will become the default in v4.1 + * + * @param player The player to send the message to + * @param message The message to send to the player + */ + public void sendMessage(Player player, String message) { + if (!this.messagesEnabled) return; + if (this.prefixEnabled) { + message = this.messagePrefix + message; + } + player.sendMessage(message); + } + /** * Gets a message from the config with the formatting specified * * @param target The string to find in the config - * @param particleReplacement The replacement for {PARTICLE}, can be null - * @param styleReplacement The replacement for {STYLE}, can be null + * @param replacement The replacement for {TYPE}, can be null * @return The message requested with the applied formatting */ - public static String getMessageFromConfig(String target, String particleReplacement, String styleReplacement) { + public static String getMessageFromConfig(String target, String replacement) { String message = ChatColor.translateAlternateColorCodes('&', PlayerParticles.getPlugin().getConfig().getString(target)); - if(particleReplacement != null) message = message.replaceAll("\\{PARTICLE\\}", particleReplacement); - if(styleReplacement != null) message = message.replaceAll("\\{STYLE\\}", styleReplacement); + if (replacement != null) message = message.replaceAll("\\{TYPE\\}", replacement); return message; } - + } diff --git a/src/com/esophose/playerparticles/manager/PermissionManager.java b/src/com/esophose/playerparticles/manager/PermissionManager.java index 1cc23d0..dc3030e 100644 --- a/src/com/esophose/playerparticles/manager/PermissionManager.java +++ b/src/com/esophose/playerparticles/manager/PermissionManager.java @@ -13,8 +13,10 @@ import java.util.List; import org.bukkit.entity.Player; -import com.esophose.playerparticles.ParticleStyle; -import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType; +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.styles.DefaultStyles; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; public class PermissionManager { @@ -22,76 +24,57 @@ public class PermissionManager { * Checks if a player has permission to use an effect * * @param player The player to check the permission for - * @param effect The effect to check + * @param effect The effect to check * @return True if the player has permission to use the effect */ - public static boolean hasPermission(Player player, ParticleType effect) { - if(player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.particles.*")) return true; - if(effect.equals(ParticleType.RED_DUST) && player.hasPermission("playerparticles.reddust")) { - return true; - }else{ - if(effect.equals(ParticleType.RED_DUST)) return false; - } - if(effect.equals(ParticleType.RAINBOW) && player.hasPermission("playerparticles.rainbow")) { - return true; - }else{ - if(effect.equals(ParticleType.RAINBOW)) return false; - } - if(player.hasPermission("playerparticles." + effect.getName().toLowerCase().replace("_", ""))) return true; + public static boolean hasEffectPermission(Player player, ParticleEffect effect) { + if (player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.effect.*")) return true; + if (player.hasPermission("playerparticles.effect." + effect.getName().toLowerCase().replace("_", ""))) return true; + if (effect == ParticleEffect.NONE) return true; return false; } - + /** * Checks if a player has permission to use a style + * Always returns true for 'none' so they can be reset * * @param player The player to check the permission for - * @param effect The style to check + * @param effect The style to check * @return True if the player has permission to use the style */ public static boolean hasStylePermission(Player player, ParticleStyle style) { - if(player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.styles.*") || style == ParticleStyle.NONE) return true; - if(player.hasPermission("playerparticles.style." + style.toString().toLowerCase().replace("_", ""))) return true; + if (player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.style.*")) return true; + if (player.hasPermission("playerparticles.style." + style.getName().toLowerCase().replace("_", ""))) return true; + if (style == DefaultStyles.NONE) return true; return false; } - + /** * Gets a List of all effect names a player has permission for * - * @param p The player to get names for + * @param p The player to get effect names for * @return A List of all effect names the given player has permission for */ public static List getParticlesUserHasPermissionFor(Player p) { List list = new ArrayList(); - if(p.hasPermission("playerparticles.*") || p.hasPermission("playerparticles.particles.*")) { - for(ParticleType pt : ParticleType.values()) { - list.add(pt.toString().toLowerCase().replace("_", "")); - } - }else{ - for(ParticleType pt : ParticleType.values()) { - if(p.hasPermission("playerparticles." + pt.toString().toLowerCase().replace("_", ""))) list.add(pt.toString().toLowerCase().replace("_", "")); - } + for (ParticleEffect pe : ParticleEffect.getSupportedEffects()) { + if (hasEffectPermission(p, pe)) list.add(pe.getName().toLowerCase().replace("_", "")); } return list; } - + /** * Gets a List of all style names a player has permission for * - * @param p The player to get names for + * @param p The player to get style names for * @return A List of all style names the given player has permission for */ public static List getStylesUserHasPermissionFor(Player p) { List list = new ArrayList(); - if(p.hasPermission("playerparticles.*") || p.hasPermission("playerparticles.styles.*")) { - for(ParticleStyle ps : ParticleStyle.values()) { - list.add(ps.toString().toLowerCase()); - } - }else{ - for(ParticleStyle pt : ParticleStyle.values()) { - if(p.hasPermission("playerparticles.style." + pt.toString().toLowerCase())) list.add(pt.toString().toLowerCase()); - } + for (ParticleStyle ps : ParticleStyleManager.getStyles()) { + if (hasStylePermission(p, ps)) list.add(ps.getName().toLowerCase().replace("_", "")); } return list; } - + } diff --git a/src/com/esophose/playerparticles/styles/DefaultStyles.java b/src/com/esophose/playerparticles/styles/DefaultStyles.java new file mode 100644 index 0000000..28212bc --- /dev/null +++ b/src/com/esophose/playerparticles/styles/DefaultStyles.java @@ -0,0 +1,36 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Bukkit; +import org.bukkit.event.Listener; + +import com.esophose.playerparticles.PlayerParticles; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; + +public class DefaultStyles { + + public static ParticleStyle NONE = new ParticleStyleNone(); + public static ParticleStyle SPIRAL = new ParticleStyleSpiral(); + public static ParticleStyle HALO = new ParticleStyleHalo(); + public static ParticleStyle POINT = new ParticleStylePoint(); + public static ParticleStyle MOVE = new ParticleStyleMove(); + public static ParticleStyle SPIN = new ParticleStyleSpin(); + public static ParticleStyle QUADHELIX = new ParticleStyleQuadhelix(); + public static ParticleStyle ORBIT = new ParticleStyleOrbit(); + public static ParticleStyle FEET = new ParticleStyleFeet(); + + public static void registerStyles() { + ParticleStyleManager.registerStyle(NONE); + ParticleStyleManager.registerStyle(SPIRAL); + ParticleStyleManager.registerStyle(HALO); + ParticleStyleManager.registerStyle(POINT); + ParticleStyleManager.registerCustomHandledStyle(MOVE); + ParticleStyleManager.registerStyle(SPIN); + ParticleStyleManager.registerStyle(QUADHELIX); + ParticleStyleManager.registerStyle(ORBIT); + ParticleStyleManager.registerStyle(FEET); + + Bukkit.getServer().getPluginManager().registerEvents((Listener) MOVE, PlayerParticles.getPlugin()); + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleFeet.java b/src/com/esophose/playerparticles/styles/ParticleStyleFeet.java new file mode 100644 index 0000000..1a0404a --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleFeet.java @@ -0,0 +1,23 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleFeet implements ParticleStyle { + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + return new PParticle[] { new PParticle(location.subtract(0, 0.95, 0), 0.4F, 0.0F, 0.4F, 0.0F) }; + } + + public void updateTimers() { + + } + + public String getName() { + return "feet"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleHalo.java b/src/com/esophose/playerparticles/styles/ParticleStyleHalo.java new file mode 100644 index 0000000..fec4c72 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleHalo.java @@ -0,0 +1,40 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleHalo implements ParticleStyle { + + private float step = 0; + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + if (step % 2 == 0) return null; + int points = 16; + double radius = .65; + double slice = 2 * Math.PI / points; + PParticle[] particles = new PParticle[points]; + for (int i = 0; i < points; i++) { + double angle = slice * i; + double newX = location.getX() + radius * Math.cos(angle); + double newY = location.getY() + 1.5; + double newZ = location.getZ() + radius * Math.sin(angle); + particles[i] = new PParticle(new Location(location.getWorld(), newX, newY, newZ)); + } + return particles; + } + + public void updateTimers() { + step++; + if (step > 30) { + step = 0; + } + } + + public String getName() { + return "halo"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleMove.java b/src/com/esophose/playerparticles/styles/ParticleStyleMove.java new file mode 100644 index 0000000..cee7939 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleMove.java @@ -0,0 +1,36 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.ParticleCreator; +import com.esophose.playerparticles.manager.ConfigManager; +import com.esophose.playerparticles.manager.PermissionManager; + +public class ParticleStyleMove extends ParticleStyleNone implements Listener { + + public String getName() { + return "move"; + } + + /** + * The event used to update the move style + * + * @param e The event + */ + @EventHandler + public void onPlayerMove(PlayerMoveEvent e) { + PPlayer pplayer = ConfigManager.getInstance().getPPlayer(e.getPlayer().getUniqueId()); + if (pplayer.getParticleStyle() == DefaultStyles.MOVE) { + if (PermissionManager.hasStylePermission(e.getPlayer(), DefaultStyles.MOVE)) { + Location loc = e.getPlayer().getLocation(); + loc.setY(loc.getY() + 0.05); + ParticleCreator.displayParticles(pplayer, DefaultStyles.MOVE.getParticles(pplayer, loc)); + } + } + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleNone.java b/src/com/esophose/playerparticles/styles/ParticleStyleNone.java new file mode 100644 index 0000000..fd195ae --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleNone.java @@ -0,0 +1,125 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.library.ParticleEffect; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleNone implements ParticleStyle { + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + ParticleEffect particleEffect = pplayer.getParticleEffect(); + if (particleEffect.equals(ParticleEffect.ANGRY_VILLAGER)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.BUBBLE)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.CLOUD)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.CRIT)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.DEPTH_SUSPEND)) { + PParticle[] particles = new PParticle[5]; + for (int i = 0; i < 5; i++) + particles[i] = new PParticle(location, 0.5F, 0.5F, 0.5F, 0.0F); + return particles; + } else if (particleEffect.equals(ParticleEffect.DRIP_LAVA)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.DRIP_WATER)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.ENCHANTMENT_TABLE)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.05F) }; + } else if (particleEffect.equals(ParticleEffect.EXPLODE)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.FIREWORKS_SPARK)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.FLAME)) { + return new PParticle[] { new PParticle(location, 0.1F, 0.1F, 0.1F, 0.05F) }; + } else if (particleEffect.equals(ParticleEffect.FOOTSTEP)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.HAPPY_VILLAGER)) { + return new PParticle[] { new PParticle(location, 0.5F, 0.5F, 0.5F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.HEART)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.HUGE_EXPLOSION)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.INSTANT_SPELL)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.LARGE_EXPLODE)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.LARGE_SMOKE)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.LAVA)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.MAGIC_CRIT)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.MOB_SPELL)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.MOB_SPELL_AMBIENT)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.NOTE)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.PORTAL)) { + return new PParticle[] { new PParticle(location, 0.5F, 0.5F, 0.5F, 0.05F) }; + } else if (particleEffect.equals(ParticleEffect.RED_DUST)) { + return new PParticle[] { new PParticle(location, 0.5F, 0.5F, 0.5F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SLIME)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SMOKE)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SNOW_SHOVEL)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SNOWBALL_POOF)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SPELL)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SUSPENDED)) { + PParticle[] particles = new PParticle[5]; + for (int i = 0; i < 5; i++) + particles[i] = new PParticle(location, 0.8F, 0.8F, 0.8F, 0.0F); + return particles; + } else if (particleEffect.equals(ParticleEffect.WAKE)) { + PParticle[] particles = new PParticle[3]; + for (int i = 0; i < 3; i++) + particles[i] = new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F); + return particles; + } else if (particleEffect.equals(ParticleEffect.WITCH_MAGIC)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.BARRIER)) { + return new PParticle[] { new PParticle(location, 1.2F, 1.2F, 1.2F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.DROPLET)) { + return new PParticle[] { new PParticle(location, 0.8F, 0.8F, 0.8F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.DRAGON_BREATH)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.END_ROD)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.DAMAGE_INDICATOR)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.SWEEP_ATTACK)) { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.BLOCK_CRACK)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.BLOCK_DUST)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.ITEM_CRACK)) { + return new PParticle[] { new PParticle(location, 0.6F, 0.6F, 0.6F, 0.0F) }; + } else if (particleEffect.equals(ParticleEffect.FALLING_DUST)) { + PParticle[] particles = new PParticle[2]; + for (int i = 0; i < 2; i++) + particles[i] = new PParticle(location.add(0, 0.75, 0), 0.6F, 0.4F, 0.6F, 0.0F); + return particles; + } else { + return new PParticle[] { new PParticle(location, 0.4F, 0.4F, 0.4F, 0.0F) }; + } + } + + public void updateTimers() { + + } + + public String getName() { + return "none"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleOrbit.java b/src/com/esophose/playerparticles/styles/ParticleStyleOrbit.java new file mode 100644 index 0000000..456601c --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleOrbit.java @@ -0,0 +1,35 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleOrbit implements ParticleStyle { + + private float step = 0; + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + int orbs = 3; + PParticle[] particles = new PParticle[orbs]; + for (int i = 0; i < orbs; i++) { + double dx = -(Math.cos((step / 120) * (Math.PI * 2) + (((Math.PI * 2) / orbs) * i))); + double dz = -(Math.sin((step / 120) * (Math.PI * 2) + (((Math.PI * 2) / orbs) * i))); + particles[i] = new PParticle(new Location(location.getWorld(), location.getX() + dx, location.getY(), location.getZ() + dz)); + } + return particles; + } + + public void updateTimers() { + step++; + if (step > 120) { + step = 0; + } + } + + public String getName() { + return "orbit"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStylePoint.java b/src/com/esophose/playerparticles/styles/ParticleStylePoint.java new file mode 100644 index 0000000..78ac45c --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStylePoint.java @@ -0,0 +1,22 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStylePoint implements ParticleStyle { + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + return new PParticle[] { new PParticle(location.add(0.0, 1.5, 0.0)) }; + } + + public void updateTimers() { + } + + public String getName() { + return "point"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java b/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java new file mode 100644 index 0000000..7bea5f4 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java @@ -0,0 +1,44 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleQuadhelix implements ParticleStyle { + + private float stepX = 0; + private float stepY = 0; + private boolean reverse = false; + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + PParticle[] particles = new PParticle[4]; + for (int i = 0; i < 4; i++) { + double dx = -(Math.cos((stepX / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(stepY)) / 60); + double dy = ((stepY) / 60) * 1.5; + double dz = -(Math.sin((stepX / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(stepY)) / 60); + particles[i] = new PParticle(new Location(location.getWorld(), location.getX() + dx, location.getY() + dy, location.getZ() + dz)); + } + return particles; + } + + public void updateTimers() { + stepX++; + if (stepX > 90) { + stepX = 0; + } + if (reverse) { + stepY++; + if (stepY > 60) reverse = false; + } else { + stepY--; + if (stepY < -60) reverse = true; + } + } + + public String getName() { + return "quadhelix"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleSpin.java b/src/com/esophose/playerparticles/styles/ParticleStyleSpin.java new file mode 100644 index 0000000..b4e8c86 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleSpin.java @@ -0,0 +1,35 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleSpin implements ParticleStyle { + + private float step = 0; + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + int points = 15; + double radius = .5; + double slice = 2 * Math.PI / points; + double angle = slice * (step % 15); + double newX = location.getX() + radius * Math.cos(angle); + double newY = location.getY() + 1.5; + double newZ = location.getZ() + radius * Math.sin(angle); + return new PParticle[] { new PParticle(new Location(location.getWorld(), newX, newY, newZ)) }; + } + + public void updateTimers() { + step++; + if (step > 30) { + step = 0; + } + } + + public String getName() { + return "spin"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleSpiral.java b/src/com/esophose/playerparticles/styles/ParticleStyleSpiral.java new file mode 100644 index 0000000..70fcb5b --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleSpiral.java @@ -0,0 +1,39 @@ +package com.esophose.playerparticles.styles; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; + +public class ParticleStyleSpiral implements ParticleStyle { + + private float step = 0; + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + int points = 16; + double radius = 1; + double slice = 2 * Math.PI / points; + PParticle[] particles = new PParticle[points]; + for (int i = 0; i < points; i++) { + double angle = slice * i; + double newX = location.getX() + radius * Math.cos(angle); + double newY = location.getY() + (step / 10) - 1; + double newZ = location.getZ() + radius * Math.sin(angle); + particles[i] = new PParticle(new Location(location.getWorld(), newX, newY, newZ)); + } + return particles; + } + + public void updateTimers() { + step++; + if (step > 30) { + step = 0; + } + } + + public String getName() { + return "spiral"; + } + +} diff --git a/src/com/esophose/playerparticles/styles/api/PParticle.java b/src/com/esophose/playerparticles/styles/api/PParticle.java new file mode 100644 index 0000000..cd502f6 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/api/PParticle.java @@ -0,0 +1,98 @@ +package com.esophose.playerparticles.styles.api; + +import org.bukkit.Location; + +public class PParticle { + + private Location location; + private float speed; + private float xOff, yOff, zOff; + + /** + * The constructor with all the fancy parameters for customization + * + * @param location The location to display the particle at + * @param xOff The offset for the x-axis + * @param yOff The offset for the y-axis + * @param zOff The offset for the z-axis + * @param speed The speed the particle will move at + */ + public PParticle(Location location, float xOff, float yOff, float zOff, float speed) { + this.location = location; + this.xOff = xOff; + this.yOff = yOff; + this.zOff = zOff; + this.speed = speed; + } + + /** + * The constructor used if you just want stand-still particles + * Useful for making shapes with the styles + * + * @param location The location to display the particles at + */ + public PParticle(Location location) { + this(location, 0.0F, 0.0F, 0.0F, 0.0F); + } + + /** + * Gets the location that the particle will be displayed at + * Offsets must be applied manually if this is a colorable effect + * + * @param colorable Whether or not this effect is colorable and we need to manually + * adjust for the offsets or not + * @return The location, either as normal or modified with the offsets + */ + public Location getLocation(boolean colorable) { + if (!colorable) { + return this.location; + } else { + double x = this.location.getX(); + double y = this.location.getY(); + double z = this.location.getZ(); + + x += this.xOff * 1.75D * (Math.random() > 0.5 ? Math.random() : -Math.random()); + y += this.yOff * 1.75D * (Math.random() > 0.5 ? Math.random() : -Math.random()); + z += this.zOff * 1.75D * (Math.random() > 0.5 ? Math.random() : -Math.random()); + + return new Location(this.location.getWorld(), x, y, z); + } + } + + /** + * Gets the speed of the particle + * + * @return The particle's speed + */ + public float getSpeed() { + return this.speed; + } + + /** + * Gets the offset on the x axis for the particle + * + * @return The x-axis offset + */ + public float getXOff() { + return this.xOff; + } + + /** + * Gets the offset on the y-axis for the particle + * + * @return The y-axis offset + */ + public float getYOff() { + return this.yOff; + } + + /** + * Gets the offset on the z-axis for the particle + * + * @return The z-axis offset + */ + public float getZOff() { + return this.zOff; + } + +} diff --git a/src/com/esophose/playerparticles/styles/api/ParticleStyle.java b/src/com/esophose/playerparticles/styles/api/ParticleStyle.java new file mode 100644 index 0000000..4cb74f3 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/api/ParticleStyle.java @@ -0,0 +1,23 @@ +/** + * Copyright Esophose 2016 + * While using any of the code provided by this plugin + * you must not claim it as your own. This plugin may + * be modified and installed on a server, but may not + * be distributed to any person by any means. + */ + +package com.esophose.playerparticles.styles.api; + +import org.bukkit.Location; + +import com.esophose.playerparticles.PPlayer; + +public interface ParticleStyle { + + public PParticle[] getParticles(PPlayer pplayer, Location location); + + public void updateTimers(); + + public String getName(); + +} diff --git a/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java b/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java new file mode 100644 index 0000000..980999d --- /dev/null +++ b/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java @@ -0,0 +1,72 @@ +package com.esophose.playerparticles.styles.api; + +import java.util.ArrayList; + +public class ParticleStyleManager { + + private static ArrayList styles = new ArrayList(); + private static ArrayList customHandledStyles = new ArrayList(); + + public static void registerStyle(ParticleStyle style) { + for (ParticleStyle testAgainst : styles) { + if (testAgainst.getName().replace("_", "").equalsIgnoreCase(style.getName())) { + throw new ParticleStyleAlreadyRegisteredException("Tried to register two styles with the same name!"); + } else if (testAgainst.equals(style)) { + throw new ParticleStyleAlreadyRegisteredException("Tried to register the same style twice!"); + } + } + styles.add(style); + } + + public static void registerCustomHandledStyle(ParticleStyle style) { + registerStyle(style); + customHandledStyles.add(style); + } + + public static boolean isCustomHandled(ParticleStyle style) { + return customHandledStyles.contains(style); + } + + public static ArrayList getStyles() { + return styles; + } + + /** + * Gets the ParticleStyle with the name given, returns null if not found + * + * @param particle The string of the style to search for + * @return The ParticleStyle with the name requested + */ + public static ParticleStyle styleFromString(String styleName) { + for (ParticleStyle style : styles) { + if (style.getName().toLowerCase().replace("_", "").equals(styleName)) return style; + } + return null; + } + + /** + * Updates all the timers for the particle styles to make the animations + * + * Do not call this in your plugin, it will mess with other styles + */ + public static void updateTimers() { + for (ParticleStyle style : styles) { + style.updateTimers(); + } + } + + /** + * The exception to throw if a style is already registered + */ + private static final class ParticleStyleAlreadyRegisteredException extends RuntimeException { + + private static final long serialVersionUID = -6116170395810178020L; + + private ParticleStyleAlreadyRegisteredException(String message) { + super(message); + } + + } + +} + diff --git a/src/com/esophose/playerparticles/updater/PluginUpdateListener.java b/src/com/esophose/playerparticles/updater/PluginUpdateListener.java index 09945dc..bb29c77 100644 --- a/src/com/esophose/playerparticles/updater/PluginUpdateListener.java +++ b/src/com/esophose/playerparticles/updater/PluginUpdateListener.java @@ -25,12 +25,12 @@ public class PluginUpdateListener implements Listener { */ @EventHandler public void onPlayerJoin(PlayerJoinEvent e) { - if(e.getPlayer().isOp()) { - if(PlayerParticles.updateVersion != null) { + if (e.getPlayer().isOp()) { + if (PlayerParticles.updateVersion != null) { MessageManager.getInstance().sendMessage(e.getPlayer(), "An update (" + ChatColor.AQUA + "v" + PlayerParticles.updateVersion + ChatColor.YELLOW + ") is available! You are running " + ChatColor.AQUA + "v" + PlayerParticles.getPlugin().getDescription().getVersion(), ChatColor.YELLOW); MessageManager.getInstance().sendMessage(e.getPlayer(), "Download from: http://dev.bukkit.org/bukkit-plugins/playerparticles/", ChatColor.YELLOW); } } } - + } diff --git a/src/com/esophose/playerparticles/updater/Updater.java b/src/com/esophose/playerparticles/updater/Updater.java index f87b8ae..520f08f 100644 --- a/src/com/esophose/playerparticles/updater/Updater.java +++ b/src/com/esophose/playerparticles/updater/Updater.java @@ -23,17 +23,22 @@ import org.json.simple.JSONObject; import org.json.simple.JSONValue; /** - * Check for updates on BukkitDev for a given plugin, and download the updates if needed. + * Check for updates on BukkitDev for a given plugin, and download the updates + * if needed. *

- * VERY, VERY IMPORTANT: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating. - *
- * It is a BUKKIT POLICY that you include a boolean value in your config that prevents the auto-updater from running AT ALL. - *
- * If you fail to include this option in your config, your plugin will be REJECTED when you attempt to submit it to dev.bukkit.org. + * VERY, VERY IMPORTANT: Because there are no standards for adding + * auto-update toggles in your plugin's config, this system provides NO CHECK + * WITH YOUR CONFIG to make sure the user has allowed auto-updating.
+ * It is a BUKKIT POLICY that you include a boolean value in your config + * that prevents the auto-updater from running AT ALL.
+ * If you fail to include this option in your config, your plugin will be + * REJECTED when you attempt to submit it to dev.bukkit.org. *

- * An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater. - *
- * If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l + * An example of a good configuration option would be something similar to + * 'auto-update: true' - if this value is set to false you may NOT run the + * auto-updater.
+ * If you are unsure about these rules, please read the plugin submission + * guidelines: http://goo.gl/8iU5l * * @author Gravity * @version 2.3 @@ -41,711 +46,750 @@ import org.json.simple.JSONValue; public class Updater { - /* Constants */ + /* Constants */ - // Remote file's title - private static final String TITLE_VALUE = "name"; - // Remote file's download link - private static final String LINK_VALUE = "downloadUrl"; - // Remote file's release type - private static final String TYPE_VALUE = "releaseType"; - // Remote file's build version - private static final String VERSION_VALUE = "gameVersion"; - // Path to GET - private static final String QUERY = "/servermods/files?projectIds="; - // Slugs will be appended to this to get to the project's RSS feed - private static final String HOST = "https://api.curseforge.com"; - // User-agent when querying Curse - private static final String USER_AGENT = "Updater (by Gravity)"; - // Used for locating version numbers in file names - private static final String DELIMETER = "^v|[\\s_-]v"; - // If the version number contains one of these, don't update. - private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; - // Used for downloading files - private static final int BYTE_SIZE = 1024; - // Config key for api key - private static final String API_KEY_CONFIG_KEY = "api-key"; - // Config key for disabling Updater - private static final String DISABLE_CONFIG_KEY = "disable"; - // Default api key value in config - private static final String API_KEY_DEFAULT = "PUT_API_KEY_HERE"; - // Default disable value in config - private static final boolean DISABLE_DEFAULT = false; + // Remote file's title + private static final String TITLE_VALUE = "name"; + // Remote file's download link + private static final String LINK_VALUE = "downloadUrl"; + // Remote file's release type + private static final String TYPE_VALUE = "releaseType"; + // Remote file's build version + private static final String VERSION_VALUE = "gameVersion"; + // Path to GET + private static final String QUERY = "/servermods/files?projectIds="; + // Slugs will be appended to this to get to the project's RSS feed + private static final String HOST = "https://api.curseforge.com"; + // User-agent when querying Curse + private static final String USER_AGENT = "Updater (by Gravity)"; + // Used for locating version numbers in file names + private static final String DELIMETER = "^v|[\\s_-]v"; + // If the version number contains one of these, don't update. + private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; + // Used for downloading files + private static final int BYTE_SIZE = 1024; + // Config key for api key + private static final String API_KEY_CONFIG_KEY = "api-key"; + // Config key for disabling Updater + private static final String DISABLE_CONFIG_KEY = "disable"; + // Default api key value in config + private static final String API_KEY_DEFAULT = "PUT_API_KEY_HERE"; + // Default disable value in config + private static final boolean DISABLE_DEFAULT = false; - /* User-provided variables */ + /* User-provided variables */ - // Plugin running Updater - private final Plugin plugin; - // Type of update check to run - private final UpdateType type; - // Whether to announce file downloads - private final boolean announce; - // The plugin file (jar) - private final File file; - // The folder that downloads will be placed in - private final File updateFolder; - // The provided callback (if any) - private final UpdateCallback callback; - // Project's Curse ID - private int id = -1; - // BukkitDev ServerMods API key - private String apiKey = null; + // Plugin running Updater + private final Plugin plugin; + // Type of update check to run + private final UpdateType type; + // Whether to announce file downloads + private final boolean announce; + // The plugin file (jar) + private final File file; + // The folder that downloads will be placed in + private final File updateFolder; + // The provided callback (if any) + private final UpdateCallback callback; + // Project's Curse ID + private int id = -1; + // BukkitDev ServerMods API key + private String apiKey = null; - /* Collected from Curse API */ + /* Collected from Curse API */ - private String versionName; - private String versionLink; - private String versionType; - private String versionGameVersion; + private String versionName; + private String versionLink; + private String versionType; + private String versionGameVersion; - /* Update process variables */ + /* Update process variables */ - // Connection to RSS - private URL url; - // Updater thread - private Thread thread; - // Used for determining the outcome of the update process - private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; + // Connection to RSS + private URL url; + // Updater thread + private Thread thread; + // Used for determining the outcome of the update process + private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; - /** - * Gives the developer the result of the update process. Can be obtained by called {@link #getResult()} - */ - public enum UpdateResult { - /** - * The updater found an update, and has readied it to be loaded the next time the server restarts/reloads. - */ - SUCCESS, - /** - * The updater did not find an update, and nothing was downloaded. - */ - NO_UPDATE, - /** - * The server administrator has disabled the updating system. - */ - DISABLED, - /** - * The updater found an update, but was unable to download it. - */ - FAIL_DOWNLOAD, - /** - * For some reason, the updater was unable to contact dev.bukkit.org to download the file. - */ - FAIL_DBO, - /** - * When running the version check, the file on DBO did not contain a recognizable version. - */ - FAIL_NOVERSION, - /** - * The id provided by the plugin running the updater was invalid and doesn't exist on DBO. - */ - FAIL_BADID, - /** - * The server administrator has improperly configured their API key in the configuration. - */ - FAIL_APIKEY, - /** - * The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded. - */ - UPDATE_AVAILABLE - } + /** + * Gives the developer the result of the update process. Can be obtained by + * called {@link #getResult()} + */ + public enum UpdateResult { + /** + * The updater found an update, and has readied it to be loaded the next + * time the server restarts/reloads. + */ + SUCCESS, + /** + * The updater did not find an update, and nothing was downloaded. + */ + NO_UPDATE, + /** + * The server administrator has disabled the updating system. + */ + DISABLED, + /** + * The updater found an update, but was unable to download it. + */ + FAIL_DOWNLOAD, + /** + * For some reason, the updater was unable to contact dev.bukkit.org to + * download the file. + */ + FAIL_DBO, + /** + * When running the version check, the file on DBO did not contain a + * recognizable version. + */ + FAIL_NOVERSION, + /** + * The id provided by the plugin running the updater was invalid and + * doesn't exist on DBO. + */ + FAIL_BADID, + /** + * The server administrator has improperly configured their API key in + * the configuration. + */ + FAIL_APIKEY, + /** + * The updater found an update, but because of the UpdateType being set + * to NO_DOWNLOAD, it wasn't downloaded. + */ + UPDATE_AVAILABLE + } - /** - * Allows the developer to specify the type of update that will be run. - */ - public enum UpdateType { - /** - * Run a version check, and then if the file is out of date, download the newest version. - */ - DEFAULT, - /** - * Don't run a version check, just find the latest update and download it. - */ - NO_VERSION_CHECK, - /** - * Get information about the version and the download size, but don't actually download anything. - */ - NO_DOWNLOAD - } + /** + * Allows the developer to specify the type of update that will be run. + */ + public enum UpdateType { + /** + * Run a version check, and then if the file is out of date, download + * the newest version. + */ + DEFAULT, + /** + * Don't run a version check, just find the latest update and download + * it. + */ + NO_VERSION_CHECK, + /** + * Get information about the version and the download size, but don't + * actually download anything. + */ + NO_DOWNLOAD + } - /** - * Represents the various release types of a file on BukkitDev. - */ - public enum ReleaseType { - /** - * An "alpha" file. - */ - ALPHA, - /** - * A "beta" file. - */ - BETA, - /** - * A "release" file. - */ - RELEASE - } + /** + * Represents the various release types of a file on BukkitDev. + */ + public enum ReleaseType { + /** + * An "alpha" file. + */ + ALPHA, + /** + * A "beta" file. + */ + BETA, + /** + * A "release" file. + */ + RELEASE + } - /** - * Initialize the updater. - * - * @param plugin The plugin that is checking for an update. - * @param id The dev.bukkit.org id of the project. - * @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class. - * @param type Specify the type of update this will be. See {@link UpdateType} - * @param announce True if the program should announce the progress of new updates in console. - */ - public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) { - this(plugin, id, file, type, null, announce); - } + /** + * Initialize the updater. + * + * @param plugin The plugin that is checking for an update. + * @param id The dev.bukkit.org id of the project. + * @param file The file that the plugin is running from, get this by doing + * this.getFile() from within your main class. + * @param type Specify the type of update this will be. See + * {@link UpdateType} + * @param announce True if the program should announce the progress of new + * updates in console. + */ + public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) { + this(plugin, id, file, type, null, announce); + } - /** - * Initialize the updater with the provided callback. - * - * @param plugin The plugin that is checking for an update. - * @param id The dev.bukkit.org id of the project. - * @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class. - * @param type Specify the type of update this will be. See {@link UpdateType} - * @param callback The callback instance to notify when the Updater has finished - */ - public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback) { - this(plugin, id, file, type, callback, false); - } + /** + * Initialize the updater with the provided callback. + * + * @param plugin The plugin that is checking for an update. + * @param id The dev.bukkit.org id of the project. + * @param file The file that the plugin is running from, get this by doing + * this.getFile() from within your main class. + * @param type Specify the type of update this will be. See + * {@link UpdateType} + * @param callback The callback instance to notify when the Updater has + * finished + */ + public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback) { + this(plugin, id, file, type, callback, false); + } - /** - * Initialize the updater with the provided callback. - * - * @param plugin The plugin that is checking for an update. - * @param id The dev.bukkit.org id of the project. - * @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class. - * @param type Specify the type of update this will be. See {@link UpdateType} - * @param callback The callback instance to notify when the Updater has finished - * @param announce True if the program should announce the progress of new updates in console. - */ - public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback, boolean announce) { - this.plugin = plugin; - this.type = type; - this.announce = announce; - this.file = file; - this.id = id; - this.updateFolder = this.plugin.getServer().getUpdateFolderFile(); - this.callback = callback; + /** + * Initialize the updater with the provided callback. + * + * @param plugin The plugin that is checking for an update. + * @param id The dev.bukkit.org id of the project. + * @param file The file that the plugin is running from, get this by doing + * this.getFile() from within your main class. + * @param type Specify the type of update this will be. See + * {@link UpdateType} + * @param callback The callback instance to notify when the Updater has + * finished + * @param announce True if the program should announce the progress of new + * updates in console. + */ + public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback, boolean announce) { + this.plugin = plugin; + this.type = type; + this.announce = announce; + this.file = file; + this.id = id; + this.updateFolder = this.plugin.getServer().getUpdateFolderFile(); + this.callback = callback; - final File pluginFile = this.plugin.getDataFolder().getParentFile(); - final File updaterFile = new File(pluginFile, "Updater"); - final File updaterConfigFile = new File(updaterFile, "config.yml"); + final File pluginFile = this.plugin.getDataFolder().getParentFile(); + final File updaterFile = new File(pluginFile, "Updater"); + final File updaterConfigFile = new File(updaterFile, "config.yml"); - YamlConfiguration config = new YamlConfiguration(); - config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n' - + "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n' - + "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration."); - config.addDefault(API_KEY_CONFIG_KEY, API_KEY_DEFAULT); - config.addDefault(DISABLE_CONFIG_KEY, DISABLE_DEFAULT); + YamlConfiguration config = new YamlConfiguration(); + config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n' + "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n' + "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration."); + config.addDefault(API_KEY_CONFIG_KEY, API_KEY_DEFAULT); + config.addDefault(DISABLE_CONFIG_KEY, DISABLE_DEFAULT); - if (!updaterFile.exists()) { - this.fileIOOrError(updaterFile, updaterFile.mkdir(), true); - } + if (!updaterFile.exists()) { + this.fileIOOrError(updaterFile, updaterFile.mkdir(), true); + } - boolean createFile = !updaterConfigFile.exists(); - try { - if (createFile) { - this.fileIOOrError(updaterConfigFile, updaterConfigFile.createNewFile(), true); - config.options().copyDefaults(true); - config.save(updaterConfigFile); - } else { - config.load(updaterConfigFile); - } - } catch (final Exception e) { - final String message; - if (createFile) { - message = "The updater could not create configuration at " + updaterFile.getAbsolutePath(); - } else { - message = "The updater could not load configuration at " + updaterFile.getAbsolutePath(); - } - this.plugin.getLogger().log(Level.SEVERE, message, e); - } + boolean createFile = !updaterConfigFile.exists(); + try { + if (createFile) { + this.fileIOOrError(updaterConfigFile, updaterConfigFile.createNewFile(), true); + config.options().copyDefaults(true); + config.save(updaterConfigFile); + } else { + config.load(updaterConfigFile); + } + } catch (final Exception e) { + final String message; + if (createFile) { + message = "The updater could not create configuration at " + updaterFile.getAbsolutePath(); + } else { + message = "The updater could not load configuration at " + updaterFile.getAbsolutePath(); + } + this.plugin.getLogger().log(Level.SEVERE, message, e); + } - if (config.getBoolean(DISABLE_CONFIG_KEY)) { - this.result = UpdateResult.DISABLED; - return; - } + if (config.getBoolean(DISABLE_CONFIG_KEY)) { + this.result = UpdateResult.DISABLED; + return; + } - String key = config.getString(API_KEY_CONFIG_KEY); - if (API_KEY_DEFAULT.equalsIgnoreCase(key) || "".equals(key)) { - key = null; - } + String key = config.getString(API_KEY_CONFIG_KEY); + if (API_KEY_DEFAULT.equalsIgnoreCase(key) || "".equals(key)) { + key = null; + } - this.apiKey = key; + this.apiKey = key; - try { - this.url = new URL(Updater.HOST + Updater.QUERY + this.id); - } catch (final MalformedURLException e) { - this.plugin.getLogger().log(Level.SEVERE, "The project ID provided for updating, " + this.id + " is invalid.", e); - this.result = UpdateResult.FAIL_BADID; - } + try { + this.url = new URL(Updater.HOST + Updater.QUERY + this.id); + } catch (final MalformedURLException e) { + this.plugin.getLogger().log(Level.SEVERE, "The project ID provided for updating, " + this.id + " is invalid.", e); + this.result = UpdateResult.FAIL_BADID; + } - if (this.result != UpdateResult.FAIL_BADID) { - this.thread = new Thread(new UpdateRunnable()); - this.thread.start(); - } else { - runUpdater(); - } - } + if (this.result != UpdateResult.FAIL_BADID) { + this.thread = new Thread(new UpdateRunnable()); + this.thread.start(); + } else { + runUpdater(); + } + } - /** - * Get the result of the update process. - * - * @return result of the update process. - * @see UpdateResult - */ - public Updater.UpdateResult getResult() { - this.waitForThread(); - return this.result; - } + /** + * Get the result of the update process. + * + * @return result of the update process. + * @see UpdateResult + */ + public Updater.UpdateResult getResult() { + this.waitForThread(); + return this.result; + } - /** - * Get the latest version's release type. - * - * @return latest version's release type. - * @see ReleaseType - */ - public ReleaseType getLatestType() { - this.waitForThread(); - if (this.versionType != null) { - for (ReleaseType type : ReleaseType.values()) { - if (this.versionType.equalsIgnoreCase(type.name())) { - return type; - } - } - } - return null; - } + /** + * Get the latest version's release type. + * + * @return latest version's release type. + * @see ReleaseType + */ + public ReleaseType getLatestType() { + this.waitForThread(); + if (this.versionType != null) { + for (ReleaseType type : ReleaseType.values()) { + if (this.versionType.equalsIgnoreCase(type.name())) { + return type; + } + } + } + return null; + } - /** - * Get the latest version's game version (such as "CB 1.2.5-R1.0"). - * - * @return latest version's game version. - */ - public String getLatestGameVersion() { - this.waitForThread(); - return this.versionGameVersion; - } + /** + * Get the latest version's game version (such as "CB 1.2.5-R1.0"). + * + * @return latest version's game version. + */ + public String getLatestGameVersion() { + this.waitForThread(); + return this.versionGameVersion; + } - /** - * Get the latest version's name (such as "Project v1.0"). - * - * @return latest version's name. - */ - public String getLatestName() { - this.waitForThread(); - return this.versionName; - } + /** + * Get the latest version's name (such as "Project v1.0"). + * + * @return latest version's name. + */ + public String getLatestName() { + this.waitForThread(); + return this.versionName; + } - /** - * Get the latest version's direct file link. - * - * @return latest version's file link. - */ - public String getLatestFileLink() { - this.waitForThread(); - return this.versionLink; - } + /** + * Get the latest version's direct file link. + * + * @return latest version's file link. + */ + public String getLatestFileLink() { + this.waitForThread(); + return this.versionLink; + } - /** - * As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish - * before allowing anyone to check the result. - */ - private void waitForThread() { - if ((this.thread != null) && this.thread.isAlive()) { - try { - this.thread.join(); - } catch (final InterruptedException e) { - this.plugin.getLogger().log(Level.SEVERE, null, e); - } - } - } + /** + * As the result of Updater output depends on the thread's completion, it is + * necessary to wait for the thread to finish before allowing anyone to + * check the result. + */ + private void waitForThread() { + if ((this.thread != null) && this.thread.isAlive()) { + try { + this.thread.join(); + } catch (final InterruptedException e) { + this.plugin.getLogger().log(Level.SEVERE, null, e); + } + } + } - /** - * Save an update from dev.bukkit.org into the server's update folder. - * - * @param file the name of the file to save it as. - */ - private void saveFile(String file) { - final File folder = this.updateFolder; + /** + * Save an update from dev.bukkit.org into the server's update folder. + * + * @param file the name of the file to save it as. + */ + private void saveFile(String file) { + final File folder = this.updateFolder; - deleteOldFiles(); - if (!folder.exists()) { - this.fileIOOrError(folder, folder.mkdir(), true); - } - downloadFile(); + deleteOldFiles(); + if (!folder.exists()) { + this.fileIOOrError(folder, folder.mkdir(), true); + } + downloadFile(); - // Check to see if it's a zip file, if it is, unzip it. - final File dFile = new File(folder.getAbsolutePath(), file); - if (dFile.getName().endsWith(".zip")) { - // Unzip - this.unzip(dFile.getAbsolutePath()); - } - if (this.announce) { - this.plugin.getLogger().info("Finished updating."); - } - } + // Check to see if it's a zip file, if it is, unzip it. + final File dFile = new File(folder.getAbsolutePath(), file); + if (dFile.getName().endsWith(".zip")) { + // Unzip + this.unzip(dFile.getAbsolutePath()); + } + if (this.announce) { + this.plugin.getLogger().info("Finished updating."); + } + } - /** - * Download a file and save it to the specified folder. - */ - private void downloadFile() { - BufferedInputStream in = null; - FileOutputStream fout = null; - try { - URL fileUrl = new URL(this.versionLink); - final int fileLength = fileUrl.openConnection().getContentLength(); - in = new BufferedInputStream(fileUrl.openStream()); - fout = new FileOutputStream(new File(this.updateFolder, file.getName())); + /** + * Download a file and save it to the specified folder. + */ + private void downloadFile() { + BufferedInputStream in = null; + FileOutputStream fout = null; + try { + URL fileUrl = new URL(this.versionLink); + final int fileLength = fileUrl.openConnection().getContentLength(); + in = new BufferedInputStream(fileUrl.openStream()); + fout = new FileOutputStream(new File(this.updateFolder, file.getName())); - final byte[] data = new byte[Updater.BYTE_SIZE]; - int count; - if (this.announce) { - this.plugin.getLogger().info("About to download a new update: " + this.versionName); - } - long downloaded = 0; - while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) { - downloaded += count; - fout.write(data, 0, count); - final int percent = (int) ((downloaded * 100) / fileLength); - if (this.announce && ((percent % 10) == 0)) { - this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes."); - } - } - } catch (Exception ex) { - this.plugin.getLogger().log(Level.WARNING, "The auto-updater tried to download a new update, but was unsuccessful.", ex); - this.result = Updater.UpdateResult.FAIL_DOWNLOAD; - } finally { - try { - if (in != null) { - in.close(); - } - } catch (final IOException ex) { - this.plugin.getLogger().log(Level.SEVERE, null, ex); - } - try { - if (fout != null) { - fout.close(); - } - } catch (final IOException ex) { - this.plugin.getLogger().log(Level.SEVERE, null, ex); - } - } - } + final byte[] data = new byte[Updater.BYTE_SIZE]; + int count; + if (this.announce) { + this.plugin.getLogger().info("About to download a new update: " + this.versionName); + } + long downloaded = 0; + while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) { + downloaded += count; + fout.write(data, 0, count); + final int percent = (int) ((downloaded * 100) / fileLength); + if (this.announce && ((percent % 10) == 0)) { + this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes."); + } + } + } catch (Exception ex) { + this.plugin.getLogger().log(Level.WARNING, "The auto-updater tried to download a new update, but was unsuccessful.", ex); + this.result = Updater.UpdateResult.FAIL_DOWNLOAD; + } finally { + try { + if (in != null) { + in.close(); + } + } catch (final IOException ex) { + this.plugin.getLogger().log(Level.SEVERE, null, ex); + } + try { + if (fout != null) { + fout.close(); + } + } catch (final IOException ex) { + this.plugin.getLogger().log(Level.SEVERE, null, ex); + } + } + } - /** - * Remove possibly leftover files from the update folder. - */ - private void deleteOldFiles() { - //Just a quick check to make sure we didn't leave any files from last time... - File[] list = listFilesOrError(this.updateFolder); - for (final File xFile : list) { - if (xFile.getName().endsWith(".zip")) { - this.fileIOOrError(xFile, xFile.mkdir(), true); - } - } - } + /** + * Remove possibly leftover files from the update folder. + */ + private void deleteOldFiles() { + // Just a quick check to make sure we didn't leave any files from last + // time... + File[] list = listFilesOrError(this.updateFolder); + for (final File xFile : list) { + if (xFile.getName().endsWith(".zip")) { + this.fileIOOrError(xFile, xFile.mkdir(), true); + } + } + } - /** - * Part of Zip-File-Extractor, modified by Gravity for use with Updater. - * - * @param file the location of the file to extract. - */ - private void unzip(String file) { - final File fSourceZip = new File(file); - try { - final String zipPath = file.substring(0, file.length() - 4); - ZipFile zipFile = new ZipFile(fSourceZip); - Enumeration e = zipFile.entries(); - while (e.hasMoreElements()) { - ZipEntry entry = e.nextElement(); - File destinationFilePath = new File(zipPath, entry.getName()); - this.fileIOOrError(destinationFilePath.getParentFile(), destinationFilePath.getParentFile().mkdirs(), true); - if (!entry.isDirectory()) { - final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); - int b; - final byte[] buffer = new byte[Updater.BYTE_SIZE]; - final FileOutputStream fos = new FileOutputStream(destinationFilePath); - final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE); - while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) { - bos.write(buffer, 0, b); - } - bos.flush(); - bos.close(); - bis.close(); - final String name = destinationFilePath.getName(); - if (name.endsWith(".jar") && this.pluginExists(name)) { - File output = new File(this.updateFolder, name); - this.fileIOOrError(output, destinationFilePath.renameTo(output), true); - } - } - } - zipFile.close(); + /** + * Part of Zip-File-Extractor, modified by Gravity for use with Updater. + * + * @param file the location of the file to extract. + */ + private void unzip(String file) { + final File fSourceZip = new File(file); + try { + final String zipPath = file.substring(0, file.length() - 4); + ZipFile zipFile = new ZipFile(fSourceZip); + Enumeration e = zipFile.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = e.nextElement(); + File destinationFilePath = new File(zipPath, entry.getName()); + this.fileIOOrError(destinationFilePath.getParentFile(), destinationFilePath.getParentFile().mkdirs(), true); + if (!entry.isDirectory()) { + final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); + int b; + final byte[] buffer = new byte[Updater.BYTE_SIZE]; + final FileOutputStream fos = new FileOutputStream(destinationFilePath); + final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE); + while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) { + bos.write(buffer, 0, b); + } + bos.flush(); + bos.close(); + bis.close(); + final String name = destinationFilePath.getName(); + if (name.endsWith(".jar") && this.pluginExists(name)) { + File output = new File(this.updateFolder, name); + this.fileIOOrError(output, destinationFilePath.renameTo(output), true); + } + } + } + zipFile.close(); - // Move any plugin data folders that were included to the right place, Bukkit won't do this for us. - moveNewZipFiles(zipPath); + // Move any plugin data folders that were included to the right + // place, Bukkit won't do this for us. + moveNewZipFiles(zipPath); - } catch (final IOException e) { - this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e); - this.result = Updater.UpdateResult.FAIL_DOWNLOAD; - } finally { - this.fileIOOrError(fSourceZip, fSourceZip.delete(), false); - } - } + } catch (final IOException e) { + this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e); + this.result = Updater.UpdateResult.FAIL_DOWNLOAD; + } finally { + this.fileIOOrError(fSourceZip, fSourceZip.delete(), false); + } + } - /** - * Find any new files extracted from an update into the plugin's data directory. - * @param zipPath path of extracted files. - */ - private void moveNewZipFiles(String zipPath) { - File[] list = listFilesOrError(new File(zipPath)); - for (final File dFile : list) { - if (dFile.isDirectory() && this.pluginExists(dFile.getName())) { - // Current dir - final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); - // List of existing files in the new dir - final File[] dList = listFilesOrError(dFile); - // List of existing files in the current dir - final File[] oList = listFilesOrError(oFile); - for (File cFile : dList) { - // Loop through all the files in the new dir - boolean found = false; - for (final File xFile : oList) { - // Loop through all the contents in the current dir to see if it exists - if (xFile.getName().equals(cFile.getName())) { - found = true; - break; - } - } - if (!found) { - // Move the new file into the current dir - File output = new File(oFile, cFile.getName()); - this.fileIOOrError(output, cFile.renameTo(output), true); - } else { - // This file already exists, so we don't need it anymore. - this.fileIOOrError(cFile, cFile.delete(), false); - } - } - } - this.fileIOOrError(dFile, dFile.delete(), false); - } - File zip = new File(zipPath); - this.fileIOOrError(zip, zip.delete(), false); - } + /** + * Find any new files extracted from an update into the plugin's data + * directory. + * + * @param zipPath path of extracted files. + */ + private void moveNewZipFiles(String zipPath) { + File[] list = listFilesOrError(new File(zipPath)); + for (final File dFile : list) { + if (dFile.isDirectory() && this.pluginExists(dFile.getName())) { + // Current dir + final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); + // List of existing files in the new dir + final File[] dList = listFilesOrError(dFile); + // List of existing files in the current dir + final File[] oList = listFilesOrError(oFile); + for (File cFile : dList) { + // Loop through all the files in the new dir + boolean found = false; + for (final File xFile : oList) { + // Loop through all the contents in the current dir to + // see if it exists + if (xFile.getName().equals(cFile.getName())) { + found = true; + break; + } + } + if (!found) { + // Move the new file into the current dir + File output = new File(oFile, cFile.getName()); + this.fileIOOrError(output, cFile.renameTo(output), true); + } else { + // This file already exists, so we don't need it + // anymore. + this.fileIOOrError(cFile, cFile.delete(), false); + } + } + } + this.fileIOOrError(dFile, dFile.delete(), false); + } + File zip = new File(zipPath); + this.fileIOOrError(zip, zip.delete(), false); + } - /** - * Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip. - * - * @param name a name to check for inside the plugins folder. - * @return true if a file inside the plugins folder is named this. - */ - private boolean pluginExists(String name) { - File[] plugins = listFilesOrError(new File("plugins")); - for (final File file : plugins) { - if (file.getName().equals(name)) { - return true; - } - } - return false; - } + /** + * Check if the name of a jar is one of the plugins currently installed, + * used for extracting the correct files out of a zip. + * + * @param name a name to check for inside the plugins folder. + * @return true if a file inside the plugins folder is named this. + */ + private boolean pluginExists(String name) { + File[] plugins = listFilesOrError(new File("plugins")); + for (final File file : plugins) { + if (file.getName().equals(name)) { + return true; + } + } + return false; + } - /** - * Check to see if the program should continue by evaluating whether the plugin is already updated, or shouldn't be updated. - * - * @return true if the version was located and is not the same as the remote's newest. - */ - private boolean versionCheck() { - final String title = this.versionName; - if (this.type != UpdateType.NO_VERSION_CHECK) { - final String localVersion = this.plugin.getDescription().getVersion(); - if (title.split(DELIMETER).length >= 2) { - // Get the newest file's version number - final String remoteVersion = title.split(DELIMETER)[title.split(DELIMETER).length - 1].split(" ")[0]; + /** + * Check to see if the program should continue by evaluating whether the + * plugin is already updated, or shouldn't be updated. + * + * @return true if the version was located and is not the same as the + * remote's newest. + */ + private boolean versionCheck() { + final String title = this.versionName; + if (this.type != UpdateType.NO_VERSION_CHECK) { + final String localVersion = this.plugin.getDescription().getVersion(); + if (title.split(DELIMETER).length >= 2) { + // Get the newest file's version number + final String remoteVersion = title.split(DELIMETER)[title.split(DELIMETER).length - 1].split(" ")[0]; - if (this.hasTag(localVersion) || !this.shouldUpdate(localVersion, remoteVersion)) { - // We already have the latest version, or this build is tagged for no-update - this.result = Updater.UpdateResult.NO_UPDATE; - return false; - } - } else { - // The file's name did not contain the string 'vVersion' - final String authorInfo = this.plugin.getDescription().getAuthors().isEmpty() ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")"; - this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system"); - this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'"); - this.plugin.getLogger().warning("Please notify the author of this error."); - this.result = Updater.UpdateResult.FAIL_NOVERSION; - return false; - } - } - return true; - } + if (this.hasTag(localVersion) || !this.shouldUpdate(localVersion, remoteVersion)) { + // We already have the latest version, or this build is + // tagged for no-update + this.result = Updater.UpdateResult.NO_UPDATE; + return false; + } + } else { + // The file's name did not contain the string 'vVersion' + final String authorInfo = this.plugin.getDescription().getAuthors().isEmpty() ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")"; + this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system"); + this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'"); + this.plugin.getLogger().warning("Please notify the author of this error."); + this.result = Updater.UpdateResult.FAIL_NOVERSION; + return false; + } + } + return true; + } - /** - * If you wish to run mathematical versioning checks, edit this method. - *

- * With default behavior, Updater will NOT verify that a remote version available on BukkitDev - * which is not this version is indeed an "update". - * If a version is present on BukkitDev that is not the version that is currently running, - * Updater will assume that it is a newer version. - * This is because there is no standard versioning scheme, and creating a calculation that can - * determine whether a new update is actually an update is sometimes extremely complicated. - *

- *

- * Updater will call this method from {@link #versionCheck()} before deciding whether - * the remote version is actually an update. - * If you have a specific versioning scheme with which a mathematical determination can - * be reliably made to decide whether one version is higher than another, you may - * revise this method, using the local and remote version parameters, to execute the - * appropriate check. - *

- *

- * Returning a value of false will tell the update process that this is NOT a new version. - * Without revision, this method will always consider a remote version at all different from - * that of the local version a new update. - *

- * @param localVersion the current version - * @param remoteVersion the remote version - * @return true if Updater should consider the remote version an update, false if not. - */ - public boolean shouldUpdate(String localVersion, String remoteVersion) { - return !localVersion.equalsIgnoreCase(remoteVersion); - } + /** + * If you wish to run mathematical versioning checks, edit this + * method. + *

+ * With default behavior, Updater will NOT verify that a remote version + * available on BukkitDev which is not this version is indeed an "update". + * If a version is present on BukkitDev that is not the version that is + * currently running, Updater will assume that it is a newer version. This + * is because there is no standard versioning scheme, and creating a + * calculation that can determine whether a new update is actually an update + * is sometimes extremely complicated. + *

+ *

+ * Updater will call this method from {@link #versionCheck()} before + * deciding whether the remote version is actually an update. If you have a + * specific versioning scheme with which a mathematical determination can be + * reliably made to decide whether one version is higher than another, you + * may revise this method, using the local and remote version parameters, to + * execute the appropriate check. + *

+ *

+ * Returning a value of false will tell the update process that this + * is NOT a new version. Without revision, this method will always consider + * a remote version at all different from that of the local version a new + * update. + *

+ * + * @param localVersion the current version + * @param remoteVersion the remote version + * @return true if Updater should consider the remote version an update, + * false if not. + */ + public boolean shouldUpdate(String localVersion, String remoteVersion) { + return !localVersion.equalsIgnoreCase(remoteVersion); + } - /** - * Evaluate whether the version number is marked showing that it should not be updated by this program. - * - * @param version a version number to check for tags in. - * @return true if updating should be disabled. - */ - private boolean hasTag(String version) { - for (final String string : Updater.NO_UPDATE_TAG) { - if (version.contains(string)) { - return true; - } - } - return false; - } + /** + * Evaluate whether the version number is marked showing that it should not + * be updated by this program. + * + * @param version a version number to check for tags in. + * @return true if updating should be disabled. + */ + private boolean hasTag(String version) { + for (final String string : Updater.NO_UPDATE_TAG) { + if (version.contains(string)) { + return true; + } + } + return false; + } - /** - * Make a connection to the BukkitDev API and request the newest file's details. - * - * @return true if successful. - */ - private boolean read() { - try { - final URLConnection conn = this.url.openConnection(); - conn.setConnectTimeout(5000); + /** + * Make a connection to the BukkitDev API and request the newest file's + * details. + * + * @return true if successful. + */ + private boolean read() { + try { + final URLConnection conn = this.url.openConnection(); + conn.setConnectTimeout(5000); - if (this.apiKey != null) { - conn.addRequestProperty("X-API-Key", this.apiKey); - } - conn.addRequestProperty("User-Agent", Updater.USER_AGENT); + if (this.apiKey != null) { + conn.addRequestProperty("X-API-Key", this.apiKey); + } + conn.addRequestProperty("User-Agent", Updater.USER_AGENT); - conn.setDoOutput(true); + conn.setDoOutput(true); - final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - final String response = reader.readLine(); + final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + final String response = reader.readLine(); - final JSONArray array = (JSONArray) JSONValue.parse(response); + final JSONArray array = (JSONArray) JSONValue.parse(response); - if (array.isEmpty()) { - this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id); - this.result = UpdateResult.FAIL_BADID; - return false; - } + if (array.isEmpty()) { + this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id); + this.result = UpdateResult.FAIL_BADID; + return false; + } - JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1); - this.versionName = (String) latestUpdate.get(Updater.TITLE_VALUE); - this.versionLink = (String) latestUpdate.get(Updater.LINK_VALUE); - this.versionType = (String) latestUpdate.get(Updater.TYPE_VALUE); - this.versionGameVersion = (String) latestUpdate.get(Updater.VERSION_VALUE); + JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1); + this.versionName = (String) latestUpdate.get(Updater.TITLE_VALUE); + this.versionLink = (String) latestUpdate.get(Updater.LINK_VALUE); + this.versionType = (String) latestUpdate.get(Updater.TYPE_VALUE); + this.versionGameVersion = (String) latestUpdate.get(Updater.VERSION_VALUE); - return true; - } catch (final IOException e) { - if (e.getMessage().contains("HTTP response code: 403")) { - this.plugin.getLogger().severe("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml"); - this.plugin.getLogger().severe("Please double-check your configuration to ensure it is correct."); - this.result = UpdateResult.FAIL_APIKEY; - } else { - this.plugin.getLogger().severe("The updater could not contact dev.bukkit.org for updating."); - this.plugin.getLogger().severe("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime."); - this.result = UpdateResult.FAIL_DBO; - } - this.plugin.getLogger().log(Level.SEVERE, null, e); - return false; - } - } + return true; + } catch (final IOException e) { + if (e.getMessage().contains("HTTP response code: 403")) { + this.plugin.getLogger().severe("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml"); + this.plugin.getLogger().severe("Please double-check your configuration to ensure it is correct."); + this.result = UpdateResult.FAIL_APIKEY; + } else { + this.plugin.getLogger().severe("The updater could not contact dev.bukkit.org for updating."); + this.plugin.getLogger().severe("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime."); + this.result = UpdateResult.FAIL_DBO; + } + this.plugin.getLogger().log(Level.SEVERE, null, e); + return false; + } + } - /** - * Perform a file operation and log any errors if it fails. - * @param file file operation is performed on. - * @param result result of file operation. - * @param create true if a file is being created, false if deleted. - */ - private void fileIOOrError(File file, boolean result, boolean create) { - if (!result) { - this.plugin.getLogger().severe("The updater could not " + (create ? "create" : "delete") + " file at: " + file.getAbsolutePath()); - } - } + /** + * Perform a file operation and log any errors if it fails. + * + * @param file file operation is performed on. + * @param result result of file operation. + * @param create true if a file is being created, false if deleted. + */ + private void fileIOOrError(File file, boolean result, boolean create) { + if (!result) { + this.plugin.getLogger().severe("The updater could not " + (create ? "create" : "delete") + " file at: " + file.getAbsolutePath()); + } + } - private File[] listFilesOrError(File folder) { - File[] contents = folder.listFiles(); - if (contents == null) { - this.plugin.getLogger().severe("The updater could not access files at: " + this.updateFolder.getAbsolutePath()); - return new File[0]; - } else { - return contents; - } - } + private File[] listFilesOrError(File folder) { + File[] contents = folder.listFiles(); + if (contents == null) { + this.plugin.getLogger().severe("The updater could not access files at: " + this.updateFolder.getAbsolutePath()); + return new File[0]; + } else { + return contents; + } + } - /** - * Called on main thread when the Updater has finished working, regardless - * of result. - */ - public interface UpdateCallback { - /** - * Called when the updater has finished working. - * @param updater The updater instance - */ - void onFinish(Updater updater); - } + /** + * Called on main thread when the Updater has finished working, regardless + * of result. + */ + public interface UpdateCallback { + /** + * Called when the updater has finished working. + * + * @param updater The updater instance + */ + void onFinish(Updater updater); + } - private class UpdateRunnable implements Runnable { - @Override - public void run() { - runUpdater(); - } - } + private class UpdateRunnable implements Runnable { + @Override + public void run() { + runUpdater(); + } + } - private void runUpdater() { - if (this.url != null && (this.read() && this.versionCheck())) { - // Obtain the results of the project's file feed - if ((this.versionLink != null) && (this.type != UpdateType.NO_DOWNLOAD)) { - String name = this.file.getName(); - // If it's a zip file, it shouldn't be downloaded as the plugin's name - if (this.versionLink.endsWith(".zip")) { - name = this.versionLink.substring(this.versionLink.lastIndexOf("/") + 1); - } - this.saveFile(name); - } else { - this.result = UpdateResult.UPDATE_AVAILABLE; - } - } + private void runUpdater() { + if (this.url != null && (this.read() && this.versionCheck())) { + // Obtain the results of the project's file feed + if ((this.versionLink != null) && (this.type != UpdateType.NO_DOWNLOAD)) { + String name = this.file.getName(); + // If it's a zip file, it shouldn't be downloaded as the + // plugin's name + if (this.versionLink.endsWith(".zip")) { + name = this.versionLink.substring(this.versionLink.lastIndexOf("/") + 1); + } + this.saveFile(name); + } else { + this.result = UpdateResult.UPDATE_AVAILABLE; + } + } - if (this.callback != null) { - new BukkitRunnable() { - @Override - public void run() { - runCallback(); - } - }.runTask(this.plugin); - } - } + if (this.callback != null) { + new BukkitRunnable() { + @Override + public void run() { + runCallback(); + } + }.runTask(this.plugin); + } + } - private void runCallback() { - this.callback.onFinish(this); - } -} \ No newline at end of file + private void runCallback() { + this.callback.onFinish(this); + } +} diff --git a/src/config.yml b/src/config.yml index edf68db..b68ae2c 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,26 +1,24 @@ -# __________.__ __________ __ .__ .__ ________ -# \______ \ | _____ ___.__. __________\______ \_____ ________/ |_|__| ____ | | ____ ______ ___ _\_____ \ -# | ___/ | \__ \< | |/ __ \_ __ \ ___/\__ \\_ __ \ __\ |/ ___\| | _/ __ \ / ___/ \ \/ / _(__ < -# | | | |__/ __ \\___ \ ___/| | \/ | / __ \| | \/| | | \ \___| |_\ ___/ \___ \ \ / / \ -# |____| |____(____ / ____|\___ >__| |____| (____ /__| |__| |__|\___ >____/\___ >____ > \_/ /______ / -# \/\/ \/ \/ \/ \/ \/ \/ +# __________.__ __________ __ .__ .__ _____ +# \______ \ | _____ ___.__. __________\______ \_____ ________/ |_|__| ____ | | ____ ______ ___ __/ | | +# | ___/ | \__ \< | |/ __ \_ __ \ ___/\__ \\_ __ \ __\ |/ ___\| | _/ __ \ / ___/ \ \/ / | |_ +# | | | |__/ __ \\___ \ ___/| | \/ | / __ \| | \/| | | \ \___| |_\ ___/ \___ \ \ / ^ / +# |____| |____(____ / ____|\___ >__| |____| (____ /__| |__| |__|\___ >____/\___ >____ > \_/\____ | +# \/\/ \/ \/ \/ \/ \/ |__| +# Please excuse the cheesy ASCII Art # ====================================================# # PlayerParticles Config # # DO NOT DELETE OR EDIT THE FIELD "version"! # # ====================================================# -# DO NOT CHANGE THIS UNDER ANY CIRCUMSTANCE (Will reset your config) -version: 3.9 +# Changing this value will reset your config on the next server reload/restart. +# I don't recommend changing it +version: 4 -# There are 20 minecraft ticks per second -# The default value of 1 means a particle will be displayed once every tick -# That means 20 particles will be displayed per second -# If ticks-per-particle was set to 5, then 4 particles would be displayed per second since 20/5 is 4 -# If your server is experiencing lag after installing this plugin, raising this value should help -# Setting this value to 0.5 will cause 40 particles to appear per second. Be warned this could cause strain on the server. -# Changing this 'may' cause style timing to get messed up -# Only use integer values, excluding 0.5 +# How many ticks to wait before spawning more particles +# Increasing this value may cause less lag, but will decrease prettiness +# The lowest possible value is 1 +# Going over 5 will likely look terrible # Default: 1 ticks-per-particle: 1 @@ -51,30 +49,29 @@ message-prefix: '&7[&3PlayerParticles&7]' # ================================================================ # # MESSAGE CONFIGURATION # # Important Notes: # -# * {PARTICLE} displays the particle argument used in the command # -# * {STYLE} displays the style argument used in the command # +# * {TYPE} Will be replaced with whatever that message requires # # * You can not use the apostrophe character! ( ' ) # # ================================================================ # -################# +# ------------- # # Particles # -################# +# ------------- # # No Particle Permission -# Default: 'You do not have permission to use type {PARTICLE} particles!' -message-no-permission: 'You do not have permission to use type {PARTICLE} particles!' +# Default: 'You do not have permission to use {TYPE} particles!' +message-no-permission: 'You do not have permission to use {TYPE} particles!' # /pp list No Particles # Default: 'You do not have permission to use any particles!' message-no-particles: 'You do not have permission to use any particles!' # Now Using Particles -# Default: 'Now using type {PARTICLE} particles!' -message-now-using: 'Now using type {PARTICLE} particles!' +# Default: 'Now using {TYPE} particles!' +message-now-using: 'Now using {TYPE} particles!' # Cleared Particles -# Default: 'Cleared your particles!' -message-cleared-particles: 'Cleared your particles!' +# Default: 'Your particles have been cleared!' +message-cleared-particles: 'Your particles have been cleared!' # You Can Use Particles # Default: 'You can use:' @@ -84,25 +81,25 @@ message-use: 'You can use:' # Default: 'Invalid particle type!' message-invalid-type: 'Invalid particle type!' -################## +# -------------- # # Styles # -################## +# -------------- # # No Style Permission -# Default: 'You do not have permission to use the style type {STYLE}!' -message-no-permission-style: 'You do not have permission to use the style type {STYLE}!' +# Default: 'You do not have permission to use the style type {TYPE}!' +message-no-permission-style: 'You do not have permission to use the style type {TYPE}!' # /pp styles No Styles # Default: 'You do not have permission to use any particles!' message-no-styles: 'You do not have permission to use any styles!' # Now Using Style -# Default: 'Now using style type {STYLE}!' -message-now-using-style: 'Now using style type {STYLE}!' +# Default: 'Now using the style type {TYPE}!' +message-now-using-style: 'Now using the style type {TYPE}!' # Cleared Style # Default: 'Cleared your particles!' -message-cleared-style: 'Cleared your style!' +message-cleared-style: 'Your style has been cleared!' # You Can Use Styles # Default: 'You can use:' @@ -112,25 +109,91 @@ message-use-style: 'You can use:' # Default: 'Invalid style type!' message-invalid-type-style: 'Invalid style type!' -################# +# ------------ # +# Data # +# ------------ # + +# Note Data Usage +# Default: 'Your current effect requires note data.' +message-note-data-usage: 'Your current effect requires note data.' + +# Color Data Usage +# Default: 'Your current effect requires color data.' +message-color-data-usage: 'Your current effect requires color data.' + +# Block Data Usage +# Default: 'Your current effect requires block data.' +message-block-data-usage: 'Your current effect requires block data.' + +# Item Data Usage +# Default: 'Your current effect requires item data.' +message-item-data-usage: 'Your current effect requires item data.' + +# No Data Required +# Default: 'Your current effect does not use any data.' +message-no-data-usage: 'Your current effect does not use any data.' + +# Note Data Applied +# Default: 'Your note data has been applied!' +message-note-data-applied: 'Your note data has been applied!' + +# Color Data Applied +# Default: 'Your color data has been applied!' +message-color-data-applied: 'Your color data has been applied!' + +# Block Data Applied +# Default: 'Your block data has been applied!' +message-block-data-applied: 'Your block data has been applied!' + +# Item Data Applied +# Default: 'Your item data has been applied!' +message-item-data-applied: 'Your item data has been applied!' + +# Invalid Note Data Arguments +# Default: 'Invalid note data arguments!' +message-note-data-invalid-arguments: 'Invalid note data arguments!' + +# Invalid Color Data Arguments +# Default: 'Invalid color data arguments!' +message-color-data-invalid-arguments: 'Invalid color data arguments!' + +# Invalid Block Data Arguments +# Default: 'Invalid block data arguments!' +message-block-data-invalid-arguments: 'Invalid block data arguments!' + +# Invalid Item Data Arguments +# Default: 'Invalid item data arguments!' +message-item-data-invalid-arguments: 'Invalid item data arguments!' + +# Unknown Block Material +# Default: 'The block name you supplied is invalid' +message-block-data-material-unknown: 'The block name you supplied is invalid' + +# Unknown Item Material +# Default: 'The item name you supplied is invalid' +message-item-data-material-unknown: 'The item name you supplied is invalid' + + + +# ------------- # # Other # -################# +# ------------- # # Usage # Default: 'Usage:' message-usage: 'Usage:' +# Reset +# Default: 'Your effect, style, and data have all been reset!' +message-reset: 'Your effect, style, and data have all been reset!' + # Invalid Arguments # Default: 'Invalid arguments!' -message-invalid-arguments: 'Invalid Arguments!' - -# Reload -# Default: 'Reloaded Config!' -message-reload: 'Reloaded Config!' +message-invalid-arguments: 'Invalid arguments!' # Available Commands -# Default: 'Available Commands:' -message-available-commands: 'Available Commands:' +# Default: 'Available commands:' +message-available-commands: 'Available commands:' # Disabled Worlds None # Default: 'Particles are not disabled in any worlds!' @@ -153,9 +216,9 @@ message-disabled-worlds: 'Particles are disabled in these worlds:' # Default: false database-enable: false -# =================================================================== # +# ------------------------------------------------------------------- # # The following are only required if database-enable is set to 'true' # -# =================================================================== # +# ------------------------------------------------------------------- # # Database Hostname # Default: '' diff --git a/src/plugin.yml b/src/plugin.yml index ae35245..23c3de9 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,9 +1,9 @@ name: PlayerParticles main: com.esophose.playerparticles.PlayerParticles -version: 3.9 +version: 4 description: Make particles around players. author: Esophose website: http://dev.bukkit.org/bukkit-plugins/playerparticles/ commands: pp: - description: Particles Command. \ No newline at end of file + description: The main PlayerParticles command. \ No newline at end of file From cf0040da185c5dbdc486bb87868d1abc2444c82c Mon Sep 17 00:00:00 2001 From: Esophose Date: Fri, 30 Sep 2016 22:03:51 -0600 Subject: [PATCH 2/3] Database works Make the database work Fix some data command bugs --- .../ParticleCommandExecutor.java | 8 +- .../playerparticles/PlayerParticles.java | 11 ++- .../playerparticles/library/Database.java | 19 +++- .../manager/ConfigManager.java | 93 +++++++++---------- src/config.yml | 7 +- 5 files changed, 77 insertions(+), 61 deletions(-) diff --git a/src/com/esophose/playerparticles/ParticleCommandExecutor.java b/src/com/esophose/playerparticles/ParticleCommandExecutor.java index 1a479e0..7ee99b5 100644 --- a/src/com/esophose/playerparticles/ParticleCommandExecutor.java +++ b/src/com/esophose/playerparticles/ParticleCommandExecutor.java @@ -129,7 +129,7 @@ public class ParticleCommandExecutor implements CommandExecutor { */ private void onData(Player p, String[] args) { ParticleEffect effect = ConfigManager.getInstance().getPPlayer(p.getUniqueId()).getParticleEffect(); - if (args.length == 1) { + if ((!effect.hasProperty(ParticleProperty.REQUIRES_DATA) && !effect.hasProperty(ParticleProperty.COLORABLE)) || args.length == 1) { if (effect.hasProperty(ParticleProperty.COLORABLE)) { if (effect == ParticleEffect.NOTE) { MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-usage", null), ChatColor.YELLOW); @@ -234,7 +234,7 @@ public class ParticleCommandExecutor implements CommandExecutor { } if (data < 0 || data > 15) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-invalid-arguments", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); return; } @@ -270,7 +270,7 @@ public class ParticleCommandExecutor implements CommandExecutor { } if (data < 0 || data > 15) { - MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-usage", null), ChatColor.RED); + MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-invalid-arguments", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); return; } @@ -288,7 +288,7 @@ public class ParticleCommandExecutor implements CommandExecutor { * @param args The arguments for the command */ private void onReset(Player p, String[] args) { - ConfigManager.getInstance().saveEntirePPlayer(PPlayer.getNewPPlayer(p.getUniqueId())); + ConfigManager.getInstance().resetPPlayer(p.getUniqueId()); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-reset", null), ChatColor.GREEN); } diff --git a/src/com/esophose/playerparticles/PlayerParticles.java b/src/com/esophose/playerparticles/PlayerParticles.java index a773fa5..9ab86b0 100644 --- a/src/com/esophose/playerparticles/PlayerParticles.java +++ b/src/com/esophose/playerparticles/PlayerParticles.java @@ -113,7 +113,7 @@ public class PlayerParticles extends JavaPlugin { String user = getConfig().getString("database-user-name"); String pass = getConfig().getString("database-user-password"); mySQL = new MySQL(hostname, port, database, user, pass); - try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'playerparticles'")) { + try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'playerparticles'")) { // Clean up the old mess if (res.next()) { mySQL.updateSQL("DROP TABLE playerparticles"); } @@ -125,15 +125,16 @@ public class PlayerParticles extends JavaPlugin { try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'pp_users'")) { if (!res.next()) { // @formatter:off mySQL.updateSQL("CREATE TABLE pp_users (player_uuid VARCHAR(36), effect VARCHAR(32), style VARCHAR(32));" + - "CREATE TABLE pp_data_item (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + - "CREATE TABLE pp_data_block (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + - "CREATE TABLE pp_data_color (player_uuid VARCHAR(36), r TINYINT, g TINYINT, b TINYINT)" + - "CREATE TABLE pp_data_note (player_uuid VARCHAR(36), note TINYINT)" + "CREATE TABLE pp_data_item (player_uuid VARCHAR(36), material VARCHAR(32), data SMALLINT);" + + "CREATE TABLE pp_data_block (player_uuid VARCHAR(36), material VARCHAR(32), data SMALLINT);" + + "CREATE TABLE pp_data_color (player_uuid VARCHAR(36), r SMALLINT, g SMALLINT, b SMALLINT);" + + "CREATE TABLE pp_data_note (player_uuid VARCHAR(36), note SMALLINT);" ); // @formatter:on } useMySQL = true; } catch (ClassNotFoundException | SQLException e) { getLogger().info("[PlayerParticles] Failed to connect to the MySQL Database! Check to see if your login information is correct!"); + getLogger().info("Additional information: " + e.getMessage()); useMySQL = false; } } else { diff --git a/src/com/esophose/playerparticles/library/Database.java b/src/com/esophose/playerparticles/library/Database.java index a0420c6..a11281a 100644 --- a/src/com/esophose/playerparticles/library/Database.java +++ b/src/com/esophose/playerparticles/library/Database.java @@ -82,6 +82,8 @@ public abstract class Database { openConnection(); } + System.out.println("Running Query: " + query); + Statement statement = connection.createStatement(); ResultSet result = statement.executeQuery(query); @@ -94,6 +96,8 @@ public abstract class Database { * See {@link java.sql.Statement#executeUpdate(String)}
* If the connection is closed, it will be opened * + * Executes multiple updates broken up by semi-colons + * * @param query Query to be run * @return Result Code, see {@link java.sql.Statement#executeUpdate(String)} * @throws SQLException If the query cannot be executed @@ -106,11 +110,22 @@ public abstract class Database { } Statement statement = connection.createStatement(); + int[] results; - int result = statement.executeUpdate(query); + if (query.indexOf(';') != -1) { + String[] queries = query.split(";"); + for (String q : queries) { + statement.addBatch(q); + System.out.println("Running query: " + q); + } + results = statement.executeBatch(); + } else { + System.out.println("Running query: " + query); + results = new int[] { statement.executeUpdate(query) }; + } statement.close(); - return result; + return results[0]; } } diff --git a/src/com/esophose/playerparticles/manager/ConfigManager.java b/src/com/esophose/playerparticles/manager/ConfigManager.java index 5cc9166..b2ba3f1 100644 --- a/src/com/esophose/playerparticles/manager/ConfigManager.java +++ b/src/com/esophose/playerparticles/manager/ConfigManager.java @@ -125,29 +125,30 @@ public class ConfigManager { return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); } else { PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); - saveEntirePPlayer(pplayer); + saveNewPPlayer(pplayer); return pplayer; } } else { String id = playerUUID.toString(); // @formatter:off try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT * FROM pp_users u " + "JOIN pp_data_item i ON u.player_uuid = i.player_uuid " + - "JOIN pp_data_block b ON u.player_uuid = b.player_uuid" + - "JOIN pp_data_color c ON u.player_uuid = c.player_uuid" + - "JOIN pp_data_note n ON u.player_uuid = n.player_uuid" + - "WHERE player_uuid = '" + id + "'")) { // @formatter:on + "JOIN pp_data_block b ON u.player_uuid = b.player_uuid " + + "JOIN pp_data_color c ON u.player_uuid = c.player_uuid " + + "JOIN pp_data_note n ON u.player_uuid = n.player_uuid " + + "WHERE u.player_uuid = '" + id + "'")) { // @formatter:on + if (res.next()) { ParticleEffect particleEffect = ParticleEffect.fromName(res.getString("u.effect")); ParticleStyle particleStyle = ParticleStyleManager.styleFromString(res.getString("u.style")); ItemData particleItemData = new ItemData(Material.matchMaterial(res.getString("i.material")), res.getByte("i.data")); BlockData particleBlockData = new BlockData(Material.matchMaterial(res.getString("b.material")), res.getByte("b.data")); - OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(res.getByte("c.r"), res.getByte("c.g"), res.getByte("c.b"))); + OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(res.getInt("c.r"), res.getInt("c.g"), res.getInt("c.b"))); NoteColor particleNoteColorData = new NoteColor(res.getByte("n.note")); return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); } else { PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); - saveEntirePPlayer(pplayer); + saveNewPPlayer(pplayer); return pplayer; } } catch (ClassNotFoundException | SQLException e) { @@ -155,18 +156,16 @@ public class ConfigManager { } } - return null; // This should never get called unless there is a database error + // This should only be returned if there is a database or config error + return null; } /** - * Saves an entire PPlayer to the database - * This is mainly used for when PPlayers are being created for the first time - * It can also be called when a player is getting reset with /pp reset - * Use the singular methods for updating individual parts of the PPlayer + * Saves a new PPlayer to the database or the file * * @param pplayer The PPlayer to save */ - public void saveEntirePPlayer(PPlayer pplayer) { + public void saveNewPPlayer(PPlayer pplayer) { if (!PlayerParticles.useMySQL) { if (!config.isConfigurationSection(pplayer.getUniqueId().toString())) { String id = pplayer.getUniqueId().toString(); @@ -200,49 +199,33 @@ public class ConfigManager { save(); } else { - try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT COUNT(*) FROM pp_users WHERE player_uuid = '" + pplayer.getUniqueId() + "'")) { - if (res.next()) { // @formatter:off - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET " + - "effect = '" + pplayer.getParticleEffect().getName() + "', " + - "style = '" + pplayer.getParticleStyle().getName() + "' " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_item SET " + - "material = '" + pplayer.getItemData().getMaterial().name() + "', " + - "data = " + pplayer.getItemData().getData() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_date_block SET " + - "material = '" + pplayer.getBlockData().getMaterial().name() + "', " + - "data = " + pplayer.getBlockData().getData() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_color SET " + - "r = " + pplayer.getColorData().getRed() + ", " + - "g = " + pplayer.getColorData().getGreen() + ", " + - "b = " + pplayer.getColorData().getBlue() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_note SET" + - "note = " + (byte) (pplayer.getNoteColorData().getValueX() * 24) + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + ";" - ); - } else { + try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT * FROM pp_users WHERE player_uuid = '" + pplayer.getUniqueId() + "'")) { + if (res.next()) { + throw new RuntimeException("The user " + pplayer.getUniqueId() + " is already in the database. They can not be added."); + } else { // @formatter:off PlayerParticles.mySQL.updateSQL("INSERT INTO pp_users (player_uuid, effect, style) VALUES (" + "'" + pplayer.getUniqueId().toString() + "', " + "'" + pplayer.getParticleEffect().getName() + "', " + "'" + pplayer.getParticleStyle().getName() + "'" + "); " + - "INSERT INTO pp_data_item (material, data) VALUES (" + + "INSERT INTO pp_data_item (player_uuid, material, data) VALUES (" + + "'" + pplayer.getUniqueId().toString() + "', " + "'" + pplayer.getItemData().getMaterial().name() + "', " + pplayer.getItemData().getData() + "); " + - "INSERT INTO pp_data_block (material, data) VALUES (" + + "INSERT INTO pp_data_block (player_uuid, material, data) VALUES (" + + "'" + pplayer.getUniqueId().toString() + "', " + "'" + pplayer.getBlockData().getMaterial().name() + "', " + pplayer.getBlockData().getData() + "); " + - "INSERT INTO pp_data_color (r, g, b) VALUES (" + + "INSERT INTO pp_data_color (player_uuid, r, g, b) VALUES (" + + "'" + pplayer.getUniqueId().toString() + "', " + pplayer.getColorData().getRed() + ", " + pplayer.getColorData().getGreen() + ", " + pplayer.getColorData().getBlue() + "); " + - "INSERT INTO pp_data_note (note) VALUES (" + + "INSERT INTO pp_data_note (player_uuid, note) VALUES (" + + "'" + pplayer.getUniqueId().toString() + "', " + (byte) (pplayer.getNoteColorData().getValueX() * 24) + ");" ); @@ -255,6 +238,22 @@ public class ConfigManager { ParticleCreator.updateIfContains(pplayer); // Update the player in case this is a /pp reset } + /** + * Resets all saved information about a PPlayer + * This should be made into a single batch query in the future + * + * @param playerUUID + */ + public void resetPPlayer(UUID playerUUID) { + PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); + savePPlayer(playerUUID, pplayer.getParticleEffect()); + savePPlayer(playerUUID, pplayer.getParticleStyle()); + savePPlayer(playerUUID, pplayer.getItemData()); + savePPlayer(playerUUID, pplayer.getBlockData()); + savePPlayer(playerUUID, pplayer.getColorData()); + savePPlayer(playerUUID, pplayer.getNoteColorData()); + } + /** * Saves the effect to the player's save file or database entry * @@ -268,7 +267,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET effect = '" + particleEffect.getName() + "' WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET effect = '" + particleEffect.getName() + "' WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -289,7 +288,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET style = '" + particleStyle.getName() + "' WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET style = '" + particleStyle.getName() + "' WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -311,7 +310,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_item SET material = '" + particleItemData.getMaterial().name() + "', data = '" + particleItemData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_item SET material = '" + particleItemData.getMaterial().name() + "', data = '" + particleItemData.getData() + "' WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -333,7 +332,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_block SET material = '" + particleBlockData.getMaterial().name() + "', data = '" + particleBlockData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_block SET material = '" + particleBlockData.getMaterial().name() + "', data = '" + particleBlockData.getData() + "' WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -356,7 +355,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET r = " + particleColorData.getRed() + ", g = " + particleColorData.getGreen() + ", b = " + particleColorData.getBlue() + " WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET r = " + particleColorData.getRed() + ", g = " + particleColorData.getGreen() + ", b = " + particleColorData.getBlue() + " WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -377,7 +376,7 @@ public class ConfigManager { save(); } else { try { - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET note = " + (byte) (particleNoteColorData.getValueX() * 24) + " WHERE player_uuid = " + playerUUID + ";"); + PlayerParticles.mySQL.updateSQL("UPDATE pp_data_note SET note = " + (byte) (particleNoteColorData.getValueX() * 24) + " WHERE player_uuid = '" + playerUUID + "';"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } diff --git a/src/config.yml b/src/config.yml index b68ae2c..787c29d 100644 --- a/src/config.yml +++ b/src/config.yml @@ -173,8 +173,6 @@ message-block-data-material-unknown: 'The block name you supplied is invalid' # Default: 'The item name you supplied is invalid' message-item-data-material-unknown: 'The item name you supplied is invalid' - - # ------------- # # Other # # ------------- # @@ -238,4 +236,7 @@ database-user-name: '' # Database User Password # Default: '' -database-user-password: '' \ No newline at end of file +database-user-password: '' + +# That's everything! You reached the end of the configuration +# Enjoy the plugin! \ No newline at end of file From dfc181ae58bef3787026113b72c50d6a37ffe9fd Mon Sep 17 00:00:00 2001 From: Esophose Date: Fri, 30 Sep 2016 22:16:02 -0600 Subject: [PATCH 3/3] Fix Commit Issues Fix them --- .../ParticleCommandExecutor.java | 45 ----- .../playerparticles/PlayerParticles.java | 14 -- .../playerparticles/library/Database.java | 9 - .../manager/ConfigManager.java | 189 ------------------ 4 files changed, 257 deletions(-) diff --git a/src/com/esophose/playerparticles/ParticleCommandExecutor.java b/src/com/esophose/playerparticles/ParticleCommandExecutor.java index de3a0f7..7ee99b5 100644 --- a/src/com/esophose/playerparticles/ParticleCommandExecutor.java +++ b/src/com/esophose/playerparticles/ParticleCommandExecutor.java @@ -129,11 +129,7 @@ public class ParticleCommandExecutor implements CommandExecutor { */ private void onData(Player p, String[] args) { ParticleEffect effect = ConfigManager.getInstance().getPPlayer(p.getUniqueId()).getParticleEffect(); -<<<<<<< HEAD if ((!effect.hasProperty(ParticleProperty.REQUIRES_DATA) && !effect.hasProperty(ParticleProperty.COLORABLE)) || args.length == 1) { -======= - if (args.length == 1) { ->>>>>>> refs/remotes/origin/master if (effect.hasProperty(ParticleProperty.COLORABLE)) { if (effect == ParticleEffect.NOTE) { MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-note-data-usage", null), ChatColor.YELLOW); @@ -214,50 +210,32 @@ public class ParticleCommandExecutor implements CommandExecutor { int data = -1; try { -<<<<<<< HEAD material = ParticlesUtil.closestMatch(args[1]); if (material == null) material = Material.matchMaterial(args[1]); if (material == null) throw new Exception(); } catch (Exception e) { MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-unknown", args[1]), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - material = Material.matchMaterial(args[1]); - } catch (Exception e) { - // Unknown item ->>>>>>> refs/remotes/origin/master return; } try { data = Integer.parseInt(args[2]); } catch (Exception e) { -<<<<<<< HEAD MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-usage", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - // Invalid data ->>>>>>> refs/remotes/origin/master return; } if (material.isBlock()) { -<<<<<<< HEAD MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-mismatch", material.name()), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - // Material must be an item ->>>>>>> refs/remotes/origin/master return; } if (data < 0 || data > 15) { -<<<<<<< HEAD MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-item-data-invalid-arguments", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - // Error data range must be between 0-15 ->>>>>>> refs/remotes/origin/master return; } @@ -268,25 +246,18 @@ public class ParticleCommandExecutor implements CommandExecutor { int data = -1; try { -<<<<<<< HEAD material = ParticlesUtil.closestMatch(args[1]); if (material == null) material = Material.matchMaterial(args[1]); if (material == null) throw new Exception(); } catch (Exception e) { MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-unknown", args[1]), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - material = Material.matchMaterial(args[1]); - } catch (Exception e) { - // Unknown block ->>>>>>> refs/remotes/origin/master return; } try { data = Integer.parseInt(args[2]); } catch (Exception e) { -<<<<<<< HEAD MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-usage", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); return; @@ -295,24 +266,12 @@ public class ParticleCommandExecutor implements CommandExecutor { if (!material.isBlock()) { MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-mismatch", material.name()), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - // Invalid data - return; - } - - if (material.isBlock()) { - // Material must be a block ->>>>>>> refs/remotes/origin/master return; } if (data < 0 || data > 15) { -<<<<<<< HEAD MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-block-data-invalid-arguments", null), ChatColor.RED); MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-usage", null) + ChatColor.AQUA + " /pp data <0-15>", ChatColor.YELLOW); -======= - // Error data range must be between 0-15 ->>>>>>> refs/remotes/origin/master return; } @@ -329,11 +288,7 @@ public class ParticleCommandExecutor implements CommandExecutor { * @param args The arguments for the command */ private void onReset(Player p, String[] args) { -<<<<<<< HEAD ConfigManager.getInstance().resetPPlayer(p.getUniqueId()); -======= - ConfigManager.getInstance().saveEntirePPlayer(PPlayer.getNewPPlayer(p.getUniqueId())); ->>>>>>> refs/remotes/origin/master MessageManager.getInstance().sendMessage(p, MessageManager.getMessageFromConfig("message-reset", null), ChatColor.GREEN); } diff --git a/src/com/esophose/playerparticles/PlayerParticles.java b/src/com/esophose/playerparticles/PlayerParticles.java index a9c150b..9ab86b0 100644 --- a/src/com/esophose/playerparticles/PlayerParticles.java +++ b/src/com/esophose/playerparticles/PlayerParticles.java @@ -113,11 +113,7 @@ public class PlayerParticles extends JavaPlugin { String user = getConfig().getString("database-user-name"); String pass = getConfig().getString("database-user-password"); mySQL = new MySQL(hostname, port, database, user, pass); -<<<<<<< HEAD try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'playerparticles'")) { // Clean up the old mess -======= - try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'playerparticles'")) { ->>>>>>> refs/remotes/origin/master if (res.next()) { mySQL.updateSQL("DROP TABLE playerparticles"); } @@ -129,26 +125,16 @@ public class PlayerParticles extends JavaPlugin { try (ResultSet res = mySQL.querySQL("SHOW TABLES LIKE 'pp_users'")) { if (!res.next()) { // @formatter:off mySQL.updateSQL("CREATE TABLE pp_users (player_uuid VARCHAR(36), effect VARCHAR(32), style VARCHAR(32));" + -<<<<<<< HEAD "CREATE TABLE pp_data_item (player_uuid VARCHAR(36), material VARCHAR(32), data SMALLINT);" + "CREATE TABLE pp_data_block (player_uuid VARCHAR(36), material VARCHAR(32), data SMALLINT);" + "CREATE TABLE pp_data_color (player_uuid VARCHAR(36), r SMALLINT, g SMALLINT, b SMALLINT);" + "CREATE TABLE pp_data_note (player_uuid VARCHAR(36), note SMALLINT);" -======= - "CREATE TABLE pp_data_item (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + - "CREATE TABLE pp_data_block (player_uuid VARCHAR(36), material VARCHAR(32), data TINYINT);" + - "CREATE TABLE pp_data_color (player_uuid VARCHAR(36), r TINYINT, g TINYINT, b TINYINT)" + - "CREATE TABLE pp_data_note (player_uuid VARCHAR(36), note TINYINT)" ->>>>>>> refs/remotes/origin/master ); // @formatter:on } useMySQL = true; } catch (ClassNotFoundException | SQLException e) { getLogger().info("[PlayerParticles] Failed to connect to the MySQL Database! Check to see if your login information is correct!"); -<<<<<<< HEAD getLogger().info("Additional information: " + e.getMessage()); -======= ->>>>>>> refs/remotes/origin/master useMySQL = false; } } else { diff --git a/src/com/esophose/playerparticles/library/Database.java b/src/com/esophose/playerparticles/library/Database.java index e0a2547..a11281a 100644 --- a/src/com/esophose/playerparticles/library/Database.java +++ b/src/com/esophose/playerparticles/library/Database.java @@ -96,11 +96,8 @@ public abstract class Database { * See {@link java.sql.Statement#executeUpdate(String)}
* If the connection is closed, it will be opened * -<<<<<<< HEAD:src/com/esophose/playerparticles/library/Database.java * Executes multiple updates broken up by semi-colons * -======= ->>>>>>> refs/remotes/origin/master:src/com/esophose/playerparticles/library/Database.java * @param query Query to be run * @return Result Code, see {@link java.sql.Statement#executeUpdate(String)} * @throws SQLException If the query cannot be executed @@ -129,12 +126,6 @@ public abstract class Database { statement.close(); -<<<<<<< HEAD:src/com/esophose/playerparticles/library/Database.java return results[0]; -======= - statement.close(); - - return result; ->>>>>>> refs/remotes/origin/master:src/com/esophose/playerparticles/library/Database.java } } diff --git a/src/com/esophose/playerparticles/manager/ConfigManager.java b/src/com/esophose/playerparticles/manager/ConfigManager.java index 08da52d..b2ba3f1 100644 --- a/src/com/esophose/playerparticles/manager/ConfigManager.java +++ b/src/com/esophose/playerparticles/manager/ConfigManager.java @@ -73,7 +73,6 @@ public class ConfigManager { config = YamlConfiguration.loadConfiguration(file); } -<<<<<<< HEAD /** * Saves the playerData.yml file to disk */ @@ -105,39 +104,6 @@ public class ConfigManager { * @param playerUUID The UUID to match the PPlayer to * @return */ -======= - /** - * Saves the playerData.yml file to disk - */ - private void save() { - try { - config.save(file); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Gets a player from the save data, creates one if it doesn't exist and adds it to the list - */ - public PPlayer getPPlayer(UUID playerUUID) { - for (PPlayer pp : ParticleCreator.particlePlayers) { - if (pp.getUniqueId() == playerUUID) return pp; - } - - PPlayer pplayer = buildPPlayer(playerUUID); - ParticleCreator.particlePlayers.add(pplayer); - return pplayer; - } - - /** - * Gets a PPlayer matching the UUID given - * One will be created if it doesn't exist - * - * @param playerUUID The UUID to match the PPlayer to - * @return - */ ->>>>>>> refs/remotes/origin/master private PPlayer buildPPlayer(UUID playerUUID) { if (!PlayerParticles.useMySQL) { if (config.getString(playerUUID.toString() + ".style.name") != null) { @@ -159,45 +125,29 @@ public class ConfigManager { return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); } else { PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); -<<<<<<< HEAD saveNewPPlayer(pplayer); -======= - saveEntirePPlayer(pplayer); ->>>>>>> refs/remotes/origin/master return pplayer; } } else { String id = playerUUID.toString(); // @formatter:off try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT * FROM pp_users u " + "JOIN pp_data_item i ON u.player_uuid = i.player_uuid " + -<<<<<<< HEAD "JOIN pp_data_block b ON u.player_uuid = b.player_uuid " + "JOIN pp_data_color c ON u.player_uuid = c.player_uuid " + "JOIN pp_data_note n ON u.player_uuid = n.player_uuid " + "WHERE u.player_uuid = '" + id + "'")) { // @formatter:on -======= - "JOIN pp_data_block b ON u.player_uuid = b.player_uuid" + - "JOIN pp_data_color c ON u.player_uuid = c.player_uuid" + - "JOIN pp_data_note n ON u.player_uuid = n.player_uuid" + - "WHERE player_uuid = '" + id + "'")) { // @formatter:on ->>>>>>> refs/remotes/origin/master if (res.next()) { ParticleEffect particleEffect = ParticleEffect.fromName(res.getString("u.effect")); ParticleStyle particleStyle = ParticleStyleManager.styleFromString(res.getString("u.style")); ItemData particleItemData = new ItemData(Material.matchMaterial(res.getString("i.material")), res.getByte("i.data")); BlockData particleBlockData = new BlockData(Material.matchMaterial(res.getString("b.material")), res.getByte("b.data")); -<<<<<<< HEAD OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(res.getInt("c.r"), res.getInt("c.g"), res.getInt("c.b"))); -======= - OrdinaryColor particleColorData = new OrdinaryColor(Color.fromRGB(res.getByte("c.r"), res.getByte("c.g"), res.getByte("c.b"))); ->>>>>>> refs/remotes/origin/master NoteColor particleNoteColorData = new NoteColor(res.getByte("n.note")); return new PPlayer(playerUUID, particleEffect, particleStyle, particleItemData, particleBlockData, particleColorData, particleNoteColorData); } else { PPlayer pplayer = PPlayer.getNewPPlayer(playerUUID); -<<<<<<< HEAD saveNewPPlayer(pplayer); return pplayer; } @@ -281,17 +231,10 @@ public class ConfigManager { ); } // @formatter:on } catch (ClassNotFoundException | SQLException e) { -======= - saveEntirePPlayer(pplayer); - return pplayer; - } - } catch (ClassNotFoundException | SQLException e) { ->>>>>>> refs/remotes/origin/master e.printStackTrace(); } } -<<<<<<< HEAD ParticleCreator.updateIfContains(pplayer); // Update the player in case this is a /pp reset } @@ -317,114 +260,6 @@ public class ConfigManager { * @param playerUUID The UUID of the player * @param particleStyle The effect that is being saved */ -======= - return null; // This should never get called unless there is a database error - } - - /** - * Saves an entire PPlayer to the database - * This is mainly used for when PPlayers are being created for the first time - * It can also be called when a player is getting reset with /pp reset - * Use the singular methods for updating individual parts of the PPlayer - * - * @param pplayer The PPlayer to save - */ - public void saveEntirePPlayer(PPlayer pplayer) { - if (!PlayerParticles.useMySQL) { - if (!config.isConfigurationSection(pplayer.getUniqueId().toString())) { - String id = pplayer.getUniqueId().toString(); - config.createSection(id); - config.createSection(id + ".effect"); - config.createSection(id + ".style"); - config.createSection(id + ".itemData"); - config.createSection(id + ".blockData"); - config.createSection(id + ".colorData"); - config.createSection(id + ".noteColorData"); - } - - ConfigurationSection section = config.getConfigurationSection(pplayer.getUniqueId().toString()); - ConfigurationSection effectSection = section.getConfigurationSection("effect"); - ConfigurationSection styleSection = section.getConfigurationSection("style"); - ConfigurationSection itemDataSection = section.getConfigurationSection("itemData"); - ConfigurationSection blockDataSection = section.getConfigurationSection("blockData"); - ConfigurationSection colorDataSection = section.getConfigurationSection("colorData"); - ConfigurationSection noteColorDataSection = section.getConfigurationSection("noteColorData"); - - effectSection.set("name", pplayer.getParticleEffect().getName()); - styleSection.set("name", pplayer.getParticleStyle().getName()); - itemDataSection.set("material", pplayer.getItemData().getMaterial().name()); - itemDataSection.set("data", pplayer.getItemData().getData()); - blockDataSection.set("material", pplayer.getBlockData().getMaterial().name()); - blockDataSection.set("data", pplayer.getBlockData().getData()); - colorDataSection.set("r", pplayer.getColorData().getRed()); - colorDataSection.set("g", pplayer.getColorData().getGreen()); - colorDataSection.set("b", pplayer.getColorData().getBlue()); - noteColorDataSection.set("note", (byte) (pplayer.getNoteColorData().getValueX() * 24)); - - save(); - } else { - try (ResultSet res = PlayerParticles.mySQL.querySQL("SELECT COUNT(*) FROM pp_users WHERE player_uuid = '" + pplayer.getUniqueId() + "'")) { - if (res.next()) { // @formatter:off - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET " + - "effect = '" + pplayer.getParticleEffect().getName() + "', " + - "style = '" + pplayer.getParticleStyle().getName() + "' " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_item SET " + - "material = '" + pplayer.getItemData().getMaterial().name() + "', " + - "data = " + pplayer.getItemData().getData() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_date_block SET " + - "material = '" + pplayer.getBlockData().getMaterial().name() + "', " + - "data = " + pplayer.getBlockData().getData() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_color SET " + - "r = " + pplayer.getColorData().getRed() + ", " + - "g = " + pplayer.getColorData().getGreen() + ", " + - "b = " + pplayer.getColorData().getBlue() + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + "; " + - "UPDATE pp_data_note SET" + - "note = " + (byte) (pplayer.getNoteColorData().getValueX() * 24) + " " + - "WHERE player_uuid = " + pplayer.getUniqueId().toString() + ";" - ); - } else { - PlayerParticles.mySQL.updateSQL("INSERT INTO pp_users (player_uuid, effect, style) VALUES (" + - "'" + pplayer.getUniqueId().toString() + "', " + - "'" + pplayer.getParticleEffect().getName() + "', " + - "'" + pplayer.getParticleStyle().getName() + "'" + - "); " + - "INSERT INTO pp_data_item (material, data) VALUES (" + - "'" + pplayer.getItemData().getMaterial().name() + "', " + - pplayer.getItemData().getData() + - "); " + - "INSERT INTO pp_data_block (material, data) VALUES (" + - "'" + pplayer.getBlockData().getMaterial().name() + "', " + - pplayer.getBlockData().getData() + - "); " + - "INSERT INTO pp_data_color (r, g, b) VALUES (" + - pplayer.getColorData().getRed() + ", " + - pplayer.getColorData().getGreen() + ", " + - pplayer.getColorData().getBlue() + - "); " + - "INSERT INTO pp_data_note (note) VALUES (" + - (byte) (pplayer.getNoteColorData().getValueX() * 24) + - ");" - ); - } // @formatter:on - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - } - } - - ParticleCreator.updateIfContains(pplayer); // Update the player in case this is a /pp reset - } - - /** - * Saves the effect to the player's save file or database entry - * - * @param playerUUID The UUID of the player - * @param particleStyle The effect that is being saved - */ ->>>>>>> refs/remotes/origin/master public void savePPlayer(UUID playerUUID, ParticleEffect particleEffect) { if (!PlayerParticles.useMySQL) { ConfigurationSection section = config.getConfigurationSection(playerUUID.toString() + ".effect"); @@ -432,11 +267,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET effect = '" + particleEffect.getName() + "' WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET effect = '" + particleEffect.getName() + "' WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -457,11 +288,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET style = '" + particleStyle.getName() + "' WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_users SET style = '" + particleStyle.getName() + "' WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -483,11 +310,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_data_item SET material = '" + particleItemData.getMaterial().name() + "', data = '" + particleItemData.getData() + "' WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_item SET material = '" + particleItemData.getMaterial().name() + "', data = '" + particleItemData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -509,11 +332,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_data_block SET material = '" + particleBlockData.getMaterial().name() + "', data = '" + particleBlockData.getData() + "' WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_block SET material = '" + particleBlockData.getMaterial().name() + "', data = '" + particleBlockData.getData() + "' WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -536,11 +355,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET r = " + particleColorData.getRed() + ", g = " + particleColorData.getGreen() + ", b = " + particleColorData.getBlue() + " WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET r = " + particleColorData.getRed() + ", g = " + particleColorData.getGreen() + ", b = " + particleColorData.getBlue() + " WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } @@ -561,11 +376,7 @@ public class ConfigManager { save(); } else { try { -<<<<<<< HEAD PlayerParticles.mySQL.updateSQL("UPDATE pp_data_note SET note = " + (byte) (particleNoteColorData.getValueX() * 24) + " WHERE player_uuid = '" + playerUUID + "';"); -======= - PlayerParticles.mySQL.updateSQL("UPDATE pp_data_color SET note = " + (byte) (particleNoteColorData.getValueX() * 24) + " WHERE player_uuid = " + playerUUID + ";"); ->>>>>>> refs/remotes/origin/master } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }