From 406a4fc6a38fa599b7e721963500ba463cf12cc5 Mon Sep 17 00:00:00 2001 From: Esophose Date: Sun, 25 Feb 2018 20:55:34 -0700 Subject: [PATCH] Add GUI, other changes Added GUI, updated copyright to 2018, added styles sphere and wings, reduced number of particles that spawn with the cube style, made some minor documentation changes --- .../playerparticles/FixedParticleEffect.java | 2 +- src/com/esophose/playerparticles/PPlayer.java | 53 +- .../ParticleCommandCompleter.java | 6 +- .../ParticleCommandExecutor.java | 43 +- .../playerparticles/PlayerParticles.java | 72 +- .../playerparticles/gui/GuiInventory.java | 61 ++ .../gui/PlayerParticlesGui.java | 812 ++++++++++++++++++ .../library/ParticleEffect.java | 8 +- .../manager/ConfigManager.java | 6 +- .../manager/MessageManager.java | 71 +- .../manager/ParticleManager.java | 33 +- .../manager/PermissionManager.java | 15 +- .../playerparticles/styles/DefaultStyles.java | 4 + .../styles/ParticleStyleCube.java | 73 +- .../styles/ParticleStyleQuadhelix.java | 2 +- .../styles/ParticleStyleSphere.java | 46 + .../styles/ParticleStyleWings.java | 45 + .../playerparticles/styles/api/PParticle.java | 4 +- .../styles/api/ParticleStyle.java | 2 +- .../styles/api/ParticleStyleManager.java | 8 +- .../updater/PluginUpdateListener.java | 2 +- .../playerparticles/util/ParticleUtils.java | 26 +- src/config.yml | 179 +++- src/plugin.yml | 2 +- 24 files changed, 1418 insertions(+), 157 deletions(-) create mode 100644 src/com/esophose/playerparticles/gui/GuiInventory.java create mode 100644 src/com/esophose/playerparticles/gui/PlayerParticlesGui.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleSphere.java create mode 100644 src/com/esophose/playerparticles/styles/ParticleStyleWings.java diff --git a/src/com/esophose/playerparticles/FixedParticleEffect.java b/src/com/esophose/playerparticles/FixedParticleEffect.java index 596984f..6528d64 100644 --- a/src/com/esophose/playerparticles/FixedParticleEffect.java +++ b/src/com/esophose/playerparticles/FixedParticleEffect.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 diff --git a/src/com/esophose/playerparticles/PPlayer.java b/src/com/esophose/playerparticles/PPlayer.java index 08c47a4..a6d3f8f 100644 --- a/src/com/esophose/playerparticles/PPlayer.java +++ b/src/com/esophose/playerparticles/PPlayer.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -11,9 +11,11 @@ package com.esophose.playerparticles; import java.util.UUID; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; +import com.esophose.playerparticles.gui.PlayerParticlesGui; import com.esophose.playerparticles.library.ParticleEffect; import com.esophose.playerparticles.library.ParticleEffect.BlockData; import com.esophose.playerparticles.library.ParticleEffect.ItemData; @@ -48,7 +50,7 @@ public class PPlayer { private NoteColor particleNoteColorData; /** - * Constructs a new PPlayer + * Constructs a new PPlayer * * @param uuid The player UUID * @param effect The player's effect @@ -67,7 +69,7 @@ public class PPlayer { this.setColorData(colorData); this.setNoteColorData(noteColorData); } - + /** * Gets the player's UUID * @@ -76,7 +78,7 @@ public class PPlayer { public UUID getUniqueId() { return this.playerUUID; } - + /** * Gets the Player from their UUID * @@ -160,7 +162,7 @@ public class PPlayer { if (style == null) style = DefaultStyles.NONE; this.particleStyle = style; } - + /** * Sets the player's item data * @@ -170,9 +172,9 @@ public class PPlayer { if (itemData == null) itemData = new ItemData(Material.IRON_SPADE, (byte) 0); this.particleItemData = itemData; } - + /** - * Sets the player's block data + * Sets the player's block data * * @param blockData The player's new block data */ @@ -180,7 +182,7 @@ public class PPlayer { if (blockData == null) blockData = new BlockData(Material.STONE, (byte) 0); this.particleBlockData = blockData; } - + /** * Sets the player's color data * @@ -190,7 +192,7 @@ public class PPlayer { if (colorData == null) colorData = new OrdinaryColor(0, 0, 0); this.particleColorData = colorData; } - + /** * Sets the player's note color data * @@ -208,10 +210,10 @@ public class PPlayer { */ public ParticleData getParticleSpawnData() { if (this.particleEffect.hasProperty(ParticleProperty.REQUIRES_DATA)) { - if (this.particleEffect == ParticleEffect.BLOCK_CRACK || this.particleEffect == ParticleEffect.BLOCK_DUST || this.particleEffect == ParticleEffect.FALLING_DUST) { - return particleBlockData; - } else if (this.particleEffect == ParticleEffect.ITEM_CRACK) { + if (this.particleEffect == ParticleEffect.ITEM_CRACK) { return this.particleItemData; + } else { + return particleBlockData; } } return null; @@ -240,6 +242,33 @@ public class PPlayer { return null; } + /** + * Gets the current particle data as a string + * + * @return The particle data in a human-readable string + */ + public String getParticleDataString() { + if (this.particleEffect == ParticleEffect.BLOCK_CRACK || this.particleEffect == ParticleEffect.BLOCK_DUST || this.particleEffect == ParticleEffect.FALLING_DUST) { + return particleBlockData.getMaterial().toString().toLowerCase() + ":" + particleBlockData.getData(); + } else if (this.particleEffect == ParticleEffect.ITEM_CRACK) { + return particleItemData.getMaterial().toString().toLowerCase() + ":" + particleItemData.getData(); + } else if (this.particleEffect.hasProperty(ParticleProperty.COLORABLE)) { + if (this.particleEffect == ParticleEffect.NOTE) { + if (this.particleNoteColorData.getValueX() * 24 == 99) { + return PlayerParticlesGui.rainbowName; + } + return "note #" + (int)(this.particleNoteColorData.getValueX() * 24); + } else { + if (this.particleColorData.getRed() == 999 && this.particleColorData.getGreen() == 999 && this.particleColorData.getBlue() == 999) { + return PlayerParticlesGui.rainbowName; + } else { + return ChatColor.RED + "" + this.particleColorData.getRed() + " " + ChatColor.GREEN + this.particleColorData.getGreen() + " " + ChatColor.AQUA + this.particleColorData.getBlue(); + } + } + } + return "None"; + } + /** * Gets a default PPlayer * Used for when a new PPlayer is being created diff --git a/src/com/esophose/playerparticles/ParticleCommandCompleter.java b/src/com/esophose/playerparticles/ParticleCommandCompleter.java index 7f9423b..9635c9c 100644 --- a/src/com/esophose/playerparticles/ParticleCommandCompleter.java +++ b/src/com/esophose/playerparticles/ParticleCommandCompleter.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -22,7 +22,7 @@ import com.esophose.playerparticles.manager.PermissionManager; public class ParticleCommandCompleter implements TabCompleter { - private final String[] COMMANDS = { "help", "effect", "effects", "style", "styles", "worlds", "version", "fixed", "reset" }; + private final String[] COMMANDS = { "help", "gui", "effect", "effects", "style", "styles", "worlds", "version", "fixed", "reset" }; private final String[] FIXED_COMMANDS = { "create", "remove", "list", "info" }; /** @@ -39,7 +39,7 @@ public class ParticleCommandCompleter implements TabCompleter { if (cmd.getName().equalsIgnoreCase("pp")) { if (args.length > 1) { if (args[0].equalsIgnoreCase("effect")) { - List commands = PermissionManager.getParticlesUserHasPermissionFor((Player) sender); + List commands = PermissionManager.getEffectsUserHasPermissionFor((Player) sender); StringUtil.copyPartialMatches(args[1], commands, completions); return completions; } else if (args[0].equalsIgnoreCase("style")) { diff --git a/src/com/esophose/playerparticles/ParticleCommandExecutor.java b/src/com/esophose/playerparticles/ParticleCommandExecutor.java index 6bdb831..3c052f9 100644 --- a/src/com/esophose/playerparticles/ParticleCommandExecutor.java +++ b/src/com/esophose/playerparticles/ParticleCommandExecutor.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -23,6 +23,8 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import com.esophose.playerparticles.gui.PlayerParticlesGui; +import com.esophose.playerparticles.gui.PlayerParticlesGui.GuiState; import com.esophose.playerparticles.library.ParticleEffect; import com.esophose.playerparticles.library.ParticleEffect.BlockData; import com.esophose.playerparticles.library.ParticleEffect.ItemData; @@ -56,7 +58,7 @@ public class ParticleCommandExecutor implements CommandExecutor { Player p = (Player) sender; if (args.length == 0) { - MessageManager.sendMessage(p, MessageType.INVALID_ARGUMENTS); + onGUI(p, true); return true; } else { String[] cmdArgs = new String[0]; @@ -93,6 +95,9 @@ public class ParticleCommandExecutor implements CommandExecutor { case "reset": onReset(p, cmdArgs); break; + case "gui": + onGUI(p, false); + break; default: MessageManager.sendMessage(p, MessageType.INVALID_ARGUMENTS); } @@ -159,7 +164,7 @@ public class ParticleCommandExecutor implements CommandExecutor { * @param args The arguments for the command */ private void onData(Player p, String[] args) { - ParticleEffect effect = ConfigManager.getInstance().getPPlayer(p.getUniqueId(), false).getParticleEffect(); + ParticleEffect effect = ConfigManager.getInstance().getPPlayer(p.getUniqueId(), true).getParticleEffect(); if ((!effect.hasProperty(ParticleProperty.REQUIRES_DATA) && !effect.hasProperty(ParticleProperty.COLORABLE)) || args.length == 0) { if (effect.hasProperty(ParticleProperty.COLORABLE)) { if (effect == ParticleEffect.NOTE) { @@ -357,8 +362,8 @@ public class ParticleCommandExecutor implements CommandExecutor { return; } String argument = args[0].replace("_", ""); - if (ParticleManager.particleFromString(argument) != null) { - ParticleEffect effect = ParticleManager.particleFromString(argument); + if (ParticleManager.effectFromString(argument) != null) { + ParticleEffect effect = ParticleManager.effectFromString(argument); if (!PermissionManager.hasEffectPermission(p, effect)) { MessageManager.sendMessage(p, MessageType.NO_PERMISSION, effect.getName().toLowerCase()); return; @@ -526,7 +531,7 @@ public class ParticleCommandExecutor implements CommandExecutor { return; } - ParticleEffect effect = ParticleManager.particleFromString(args[3]); + ParticleEffect effect = ParticleManager.effectFromString(args[3]); if (effect == null) { MessageManager.sendMessage(p, MessageType.CREATE_FIXED_INVALID_EFFECT, args[3]); return; @@ -774,5 +779,31 @@ public class ParticleCommandExecutor implements CommandExecutor { if (p.hasPermission("playerparticles.fixed.clear")) MessageManager.sendMessage(p, MessageType.FIXED_COMMAND_DESC_CLEAR); } } + + private void onGUI(Player p, boolean byDefault) { + if (PlayerParticlesGui.isGuiDisabled()) { + if (byDefault) { + onHelp(p); + } else { + MessageManager.sendMessage(p, MessageType.GUI_DISABLED); + } + return; + } + + if (PermissionManager.getEffectsUserHasPermissionFor(p).size() == 1) { + if (byDefault) { + onHelp(p); + } else { + MessageManager.sendMessage(p, MessageType.NO_PARTICLES); + } + return; + } + + if (byDefault) { + MessageManager.sendMessage(p, MessageType.GUI_BY_DEFAULT); + } + + PlayerParticlesGui.changeState(ConfigManager.getInstance().getPPlayer(p.getUniqueId(), true), GuiState.DEFAULT); + } } diff --git a/src/com/esophose/playerparticles/PlayerParticles.java b/src/com/esophose/playerparticles/PlayerParticles.java index 1bf93a0..beffee1 100644 --- a/src/com/esophose/playerparticles/PlayerParticles.java +++ b/src/com/esophose/playerparticles/PlayerParticles.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -7,17 +7,37 @@ */ /* - TODO: v4.4 + TODO: v5 + Add new style 'tornado' + + Add new style 'fairy' + Add new style 'atom' - + Add new style 'wings' - + GUI for styles and effects - Requires no additional permissions - /pp gui - Shows GUI that tells you your current effect, style, and data and lets you choose new ones - /pp gui effect - Shows GUI that lets you select a new effect, also shows your current one - /pp gui style - Shows GUI that lets you select a new style, also shows your current one - /pp gui data - Shows GUI that lets you choose from preset data based on your current effect, also shows your current data + + Add new style 'rings' + + Add new style 'jump' + + Add new style 'blockbreak' + + Add new style 'blockplace' + + Add new style 'hurt' + + Add new style 'swords' + + Switch over to Spigot Particle API + + Switch database management system, make async + + Command to force set an effect/style for a player */ +/* + Changelog v5: + + Added GUI. Opens with /pp or /pp gui. Icons and messages are completely customizable from the config. + + Added a way to disable the GUI, because I know somebody will ask + + Added new style 'wings' + + Added new style 'sphere' + - Minecraft 1.7 and 1.8 are no longer supported. There is no reason to still be on a version that old. + * Fixed a bug where typing /pp data when you haven't been added to the playerData.yml/database yet threw an error + * Switched over to the Spigot Particle API + * Plugin is now built against Java 1.8.0_161 and Spigot 1.9.4 + * Servers running Java 7 are no longer supported. Please upgrade to Java 8 if you haven't yet. + * Rewrote database connection system, should fix any memory leaks from before + * Reduced particle render distance from 512 to 150, you won't notice a difference + * Performance improvements with database loading + */ + package com.esophose.playerparticles; import java.io.File; @@ -29,6 +49,7 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; +import com.esophose.playerparticles.gui.PlayerParticlesGui; import com.esophose.playerparticles.library.MySQL; import com.esophose.playerparticles.manager.MessageManager; import com.esophose.playerparticles.manager.ParticleManager; @@ -68,12 +89,14 @@ public class PlayerParticles extends JavaPlugin { public void onEnable() { DefaultStyles.registerStyles(); MessageManager.setup(); + PlayerParticlesGui.setup(); saveDefaultConfig(); getCommand("pp").setTabCompleter(new ParticleCommandCompleter()); getCommand("pp").setExecutor(new ParticleCommandExecutor()); Bukkit.getPluginManager().registerEvents(new ParticleManager(), this); Bukkit.getPluginManager().registerEvents(new PluginUpdateListener(), this); - if (getConfig().getDouble("version") < Double.parseDouble(getDescription().getVersion().substring(0, 3))) { + Bukkit.getPluginManager().registerEvents(new PlayerParticlesGui(), this); + if (getConfig().getDouble("version") < Double.parseDouble(getDescription().getVersion())) { File configFile = new File(getDataFolder(), "config.yml"); configFile.delete(); saveDefaultConfig(); @@ -86,12 +109,27 @@ public class PlayerParticles extends JavaPlugin { if (shouldCheckUpdates()) { try { // For some reason this can throw an exception sometimes. I suppose it happens when you run the server without an internet connection? Updater updater = new Updater(this, 82823, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false); - if (Double.parseDouble(updater.getLatestName().replaceAll("PlayerParticles v", "").replaceAll("\\.", "")) > Double.parseDouble(getPlugin().getDescription().getVersion().replaceAll("\\.", ""))) { + 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()); + getLogger().info("An update (v" + updateVersion + ") is available! You are running v" + getPlugin().getDescription().getVersion()); } } catch (Exception e) { - getLogger().warning("[PlayerParticles] An error occurred checking for an update. There is either no established internet connection or the Curse API is down."); + getLogger().warning("An error occurred checking for an update. There is either no established internet connection or the Curse API is down."); + } + } + } + + /** + * Clean up MySQL connection if it's open + */ + public void onDisable() { + if (useMySQL) { + try { + if (mySQL.checkConnection()) { + mySQL.closeConnection(); + } + } catch (SQLException ex) { + getLogger().warning("An error occurred while cleaning up the mySQL database connection."); } } } @@ -129,7 +167,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); - + useMySQL = true; // If something goes wrong this will be set to false // @formatter:off @@ -156,7 +194,7 @@ public class PlayerParticles extends JavaPlugin { ); } } 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("Failed to connect to the MySQL Database! Check to see if your login information is correct!"); getLogger().info("Additional information: " + e.getMessage()); useMySQL = false; return; @@ -176,9 +214,9 @@ public class PlayerParticles extends JavaPlugin { public void run() { ParticleManager.refreshPPlayers(); // Add any online players who have particles ParticleManager.addAllFixedEffects(); // Add all fixed effects - - double ticks = getConfig().getInt("ticks-per-particle"); - new ParticleManager().runTaskTimer(playerParticles, 20, (long) ticks); + + long ticks = getConfig().getLong("ticks-per-particle"); + new ParticleManager().runTaskTimer(playerParticles, 20, ticks); } }.runTaskLater(playerParticles, 20); } diff --git a/src/com/esophose/playerparticles/gui/GuiInventory.java b/src/com/esophose/playerparticles/gui/GuiInventory.java new file mode 100644 index 0000000..0dd89e7 --- /dev/null +++ b/src/com/esophose/playerparticles/gui/GuiInventory.java @@ -0,0 +1,61 @@ +/** + * Copyright Esophose 2018 + * 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.gui; + +import org.bukkit.inventory.Inventory; + +import com.esophose.playerparticles.gui.PlayerParticlesGui.GuiState; + +public class GuiInventory { + + private Inventory inventory; + private GuiState guiState; + + public GuiInventory(Inventory inventory, GuiState guiState) { + this.inventory = inventory; + this.guiState = guiState; + } + + /** + * Replaces the current inventory with a new inventory + * + * @param inventory The inventory this GuiInventory now manages + */ + public void setInventory(Inventory inventory) { + this.inventory = inventory; + } + + /** + * Updates the current GuiState + * + * @param guiState The new GuiState + */ + public void setGuiState(GuiState guiState) { + this.guiState = guiState; + } + + /** + * Gets the Inventory + * + * @return The Inventory + */ + public Inventory getInventory() { + return this.inventory; + } + + /** + * Gets the GuiState + * + * @return The GuiState + */ + public GuiState getGuiState() { + return this.guiState; + } + +} diff --git a/src/com/esophose/playerparticles/gui/PlayerParticlesGui.java b/src/com/esophose/playerparticles/gui/PlayerParticlesGui.java new file mode 100644 index 0000000..d7ee98a --- /dev/null +++ b/src/com/esophose/playerparticles/gui/PlayerParticlesGui.java @@ -0,0 +1,812 @@ +/** + * Copyright Esophose 2018 + * 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.gui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.SkullType; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.material.Dye; +import org.bukkit.material.Wool; +import org.bukkit.scheduler.BukkitRunnable; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.PlayerParticles; +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.MessageType; +import com.esophose.playerparticles.manager.ParticleManager; +import com.esophose.playerparticles.manager.PermissionManager; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.styles.api.ParticleStyleManager; +import com.esophose.playerparticles.util.ParticleUtils; + +/** + * This class provides a collection of static methods for modifying your + * particle/style/data through the use of a GUI + */ +public class PlayerParticlesGui extends BukkitRunnable implements Listener { + + /** + * The possible states that the GUI can be in + * Used to figure out what the InventoryClickEvent should do + */ + public enum GuiState { // @formatter:off + DEFAULT, + EFFECT, + STYLE, + DATA + } // @formatter:on + + public static final String rainbowName = ChatColor.RED + "r" + ChatColor.GOLD + "a" + ChatColor.YELLOW + "i" + ChatColor.GREEN + "n" + ChatColor.AQUA + "b" + ChatColor.BLUE + "o" + ChatColor.LIGHT_PURPLE + "w"; + + private static final int INVENTORY_SIZE = 54; + private static HashMap playerGuiInventories; + private static boolean guiEnabled; + + /** + * Cached icons to prevent calling config over and over + */ + private static Material[] defaultMenuIcons = new Material[3]; + private static HashMap effectIcons; + private static HashMap styleIcons; + + /** + * Maps to convert from clicked materials to particle colors + */ + private static LinkedHashMap colorMapping; + private static String[] colorMappingNames; + + /** + * DyeColor array in the order of the rainbow + * Color index for the wool color to display next + */ + private static DyeColor[] rainbowColors; + private static int rainbowColorsIndex = 0; + + /** + * 28 of each block/item Materials for block/item data + */ + private static Material[] blockMaterials; + private static Material[] itemMaterials; + + static { // @formatter:off + colorMapping = new LinkedHashMap(); + + colorMapping.put(DyeColor.RED, new OrdinaryColor(255, 0, 0)); + colorMapping.put(DyeColor.ORANGE, new OrdinaryColor(255, 140, 0)); + colorMapping.put(DyeColor.YELLOW, new OrdinaryColor(255, 255, 0)); + colorMapping.put(DyeColor.LIME, new OrdinaryColor(50, 205, 50)); + colorMapping.put(DyeColor.GREEN, new OrdinaryColor(0, 128, 0)); + colorMapping.put(DyeColor.BLUE, new OrdinaryColor(0, 0, 255)); + colorMapping.put(DyeColor.CYAN, new OrdinaryColor(0, 139, 139)); + colorMapping.put(DyeColor.LIGHT_BLUE, new OrdinaryColor(173, 216, 230)); + colorMapping.put(DyeColor.PURPLE, new OrdinaryColor(138, 43, 226)); + colorMapping.put(DyeColor.MAGENTA, new OrdinaryColor(202, 31, 123)); + colorMapping.put(DyeColor.PINK, new OrdinaryColor(255, 182, 193)); + colorMapping.put(DyeColor.BROWN, new OrdinaryColor(139, 69, 19)); + colorMapping.put(DyeColor.BLACK, new OrdinaryColor(0, 0, 0)); + colorMapping.put(DyeColor.GRAY, new OrdinaryColor(128, 128, 128)); + colorMapping.put(DyeColor.SILVER, new OrdinaryColor(192, 192, 192)); + colorMapping.put(DyeColor.WHITE, new OrdinaryColor(255, 255, 255)); + + colorMappingNames = new String[] { + ChatColor.RED + "red", + ChatColor.GOLD + "orange", + ChatColor.YELLOW + "yellow", + ChatColor.GREEN + "lime green", + ChatColor.DARK_GREEN + "green", + ChatColor.DARK_BLUE + "blue", + ChatColor.DARK_AQUA + "cyan", + ChatColor.AQUA + "light blue", + ChatColor.DARK_PURPLE + "purple", + ChatColor.LIGHT_PURPLE + "magenta", + ChatColor.LIGHT_PURPLE + "pink", + ChatColor.GOLD + "brown", + ChatColor.DARK_GRAY + "black", + ChatColor.DARK_GRAY + "gray", + ChatColor.GRAY + "light gray", + ChatColor.WHITE + "white" + }; + + rainbowColors = new DyeColor[] { DyeColor.RED, DyeColor.ORANGE, DyeColor.YELLOW, DyeColor.LIME, DyeColor.LIGHT_BLUE, DyeColor.BLUE, DyeColor.PURPLE }; + + blockMaterials = new Material[] { + Material.STONE, + Material.GRASS, + Material.TNT, + Material.COBBLESTONE, + Material.WOOD, + Material.BEDROCK, + Material.SAND, + Material.LOG, + Material.SPONGE, + Material.GLASS, + Material.WOOL, + Material.IRON_BLOCK, + Material.GOLD_BLOCK, + Material.DIAMOND_BLOCK, + Material.EMERALD_BLOCK, + Material.COAL_BLOCK, + Material.REDSTONE_BLOCK, + Material.BOOKSHELF, + Material.ICE, + Material.CLAY, + Material.PUMPKIN, + Material.MELON_BLOCK, + Material.NETHERRACK, + Material.SOUL_SAND, + Material.GLOWSTONE, + Material.NETHER_BRICK, + Material.ENDER_STONE, + Material.PRISMARINE + }; + + itemMaterials = new Material[] { + Material.COAL, + Material.IRON_INGOT, + Material.GOLD_INGOT, + Material.REDSTONE, + Material.EMERALD, + Material.QUARTZ, + Material.CLAY_BRICK, + Material.GLOWSTONE_DUST, + Material.SUGAR_CANE, + Material.FLINT, + Material.POTATO_ITEM, + Material.CARROT_ITEM, + Material.SNOW_BALL, + Material.BONE, + Material.ENDER_PEARL, + Material.BLAZE_POWDER, + Material.NETHER_STALK, + Material.FIREBALL, + Material.CHORUS_FRUIT, + Material.PRISMARINE_CRYSTALS, + Material.SULPHUR, + Material.APPLE, + Material.MELON, + Material.COOKIE, + Material.IRON_SPADE, + Material.COMPASS, + Material.WATCH, + Material.NAME_TAG + }; + } // @formatter:on + + /** + * Initializes all the static values for this class + */ + public static void setup() { + FileConfiguration config = PlayerParticles.getPlugin().getConfig(); + + guiEnabled = config.getBoolean("gui-enabled"); + if (!guiEnabled) return; + + playerGuiInventories = new HashMap(); + effectIcons = new HashMap(); + styleIcons = new HashMap(); + + defaultMenuIcons[0] = ParticleUtils.closestMatch(config.getString("gui-icon.main-menu.EFFECT")); + defaultMenuIcons[1] = ParticleUtils.closestMatch(config.getString("gui-icon.main-menu.STYLE")); + defaultMenuIcons[2] = ParticleUtils.closestMatch(config.getString("gui-icon.main-menu.DATA")); + for (int i = 0; i < defaultMenuIcons.length; i++) + if (defaultMenuIcons[i] == null) defaultMenuIcons[i] = Material.BARRIER; + + for (ParticleEffect effect : ParticleEffect.values()) { + String effectName = effect.name(); + Material iconMaterial = ParticleUtils.closestMatch(config.getString("gui-icon.effect." + effectName)); + if (iconMaterial == null) iconMaterial = Material.BARRIER; // Missing icon or invalid? Replace it with a barrier instead to fail safety. + effectIcons.put(effectName, iconMaterial); + } + + for (ParticleStyle style : ParticleStyleManager.getStyles()) { + String styleName = style.getName().toUpperCase(); + Material iconMaterial = ParticleUtils.closestMatch(config.getString("gui-icon.style." + styleName)); + if (iconMaterial == null) iconMaterial = Material.BARRIER; // Missing icon or invalid? Replace it with a barrier instead to fail safety. + styleIcons.put(styleName, iconMaterial); + } + + new PlayerParticlesGui().runTaskTimer(PlayerParticles.getPlugin(), 0, 10); + } + + /** + * Updates all color/note data inventories to display the rainbow icon + * Removes any players who are no longer online from playerGuiInventories + */ + public void run() { + List toRemoveList = new ArrayList(); + + for (Map.Entry entry : playerGuiInventories.entrySet()) { + PPlayer pplayer = ConfigManager.getInstance().getPPlayer(entry.getKey(), false); + Player player = Bukkit.getPlayer(pplayer.getUniqueId()); + + if (player == null) { + toRemoveList.add(pplayer.getUniqueId()); + continue; + } + + GuiInventory guiInventory = entry.getValue(); + Inventory inventory = guiInventory.getInventory(); + + if (player.getOpenInventory().getTopInventory().equals(inventory) && guiInventory.getGuiState() == GuiState.DATA && pplayer.getParticleEffect().hasProperty(ParticleProperty.COLORABLE)) { + ItemStack rainbowIcon; + if (pplayer.getParticleEffect() != ParticleEffect.NOTE) { + rainbowIcon = getItemForRainbowColorData(pplayer.getColorData(), rainbowColors[rainbowColorsIndex]); + } else { + rainbowIcon = getItemForRainbowNoteData(pplayer.getNoteColorData(), rainbowColors[rainbowColorsIndex]); + } + inventory.setItem(40, rainbowIcon); + } + } + + for (UUID uuid : toRemoveList) + playerGuiInventories.remove(uuid); + + rainbowColorsIndex++; + rainbowColorsIndex %= rainbowColors.length; + } + + /** + * Gets if the GUI is disabled by the server owner or not + * + * @return True if the GUI is disabled + */ + public static boolean isGuiDisabled() { + return !guiEnabled; + } + + /** + * Changes the GUI to the indicated state + * If the GUI isn't open yet, it gets opened + * + * @param p The pplayer + * @param state The new state + */ + public static void changeState(PPlayer p, GuiState state) { + Player player = p.getPlayer(); + + if (PermissionManager.getEffectsUserHasPermissionFor(player).size() == 1 || PermissionManager.getStylesUserHasPermissionFor(player).size() == 1 || (state == GuiState.DATA && p.getParticleSpawnData() == null && p.getParticleSpawnColor() == null)) return; + + // Update the state and create an inventory for the player if one isn't already open for them + // If they have the wrong inventory open for some reason, create a new one and open it for them + if (playerGuiInventories.containsKey(p.getUniqueId())) { + GuiInventory guiInventory = playerGuiInventories.get(p.getUniqueId()); + guiInventory.setGuiState(state); + if (player.getOpenInventory().getTopInventory() != guiInventory.getInventory()) { + Inventory ppInventory = Bukkit.createInventory(null, INVENTORY_SIZE, "PlayerParticles"); + player.openInventory(ppInventory); + guiInventory.setInventory(ppInventory); + } + } else { + Inventory ppInventory = Bukkit.createInventory(null, INVENTORY_SIZE, "PlayerParticles"); + player.openInventory(ppInventory); + playerGuiInventories.put(p.getUniqueId(), new GuiInventory(ppInventory, state)); + } + + switch (state) { + case DEFAULT: + populateDefault(p); + break; + case EFFECT: + populateEffect(p); + break; + case STYLE: + populateStyle(p); + break; + case DATA: + populateData(p); + break; + } + } + + /** + * Opens the menu to go to other menus: effect, style, data + * + * @param p The PPlayer + */ + private static void populateDefault(PPlayer p) { + Player player = p.getPlayer(); + Inventory inventory = player.getOpenInventory().getTopInventory(); + + inventory.clear(); // Make sure the inventory is always empty before we start adding items + + ItemStack currentIcon = new ItemStack(Material.SKULL_ITEM, 1, (short) SkullType.PLAYER.ordinal()); + SkullMeta currentIconMeta = (SkullMeta) currentIcon.getItemMeta(); + currentIconMeta.setDisplayName(ChatColor.GREEN + player.getName()); + String[] currentIconLore = new String[3]; + currentIconLore[0] = ChatColor.YELLOW + "Effect: " + ChatColor.AQUA + p.getParticleEffect().getName(); + currentIconLore[1] = ChatColor.YELLOW + "Style: " + ChatColor.AQUA + p.getParticleStyle().getName(); + currentIconLore[2] = ChatColor.YELLOW + "Active Data: " + ChatColor.AQUA + p.getParticleDataString(); + currentIconMeta.setLore(Arrays.asList(currentIconLore)); + currentIconMeta.setOwner(player.getName()); + currentIcon.setItemMeta(currentIconMeta); + + ItemStack effectIcon = new ItemStack(defaultMenuIcons[0], 1); + ItemMeta effectIconMeta = effectIcon.getItemMeta(); + effectIconMeta.setDisplayName(ChatColor.GREEN + "Effect"); + effectIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SET_YOUR.getMessageReplaced("effect"))); + if (PermissionManager.getEffectsUserHasPermissionFor(player).size() == 1) { // Always has access to NONE + effectIconMeta.setLore(Arrays.asList(MessageType.GUI_NO_ACCESS_TO.getMessageReplaced("effects"))); + } + effectIcon.setItemMeta(effectIconMeta); + + ItemStack styleIcon = new ItemStack(defaultMenuIcons[1], 1); + ItemMeta styleIconMeta = styleIcon.getItemMeta(); + styleIconMeta.setDisplayName(ChatColor.GREEN + "Style"); + styleIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SET_YOUR.getMessageReplaced("style"))); + if (PermissionManager.getStylesUserHasPermissionFor(player).size() == 1) { // Always has access to NONE + styleIconMeta.setLore(Arrays.asList(MessageType.GUI_NO_ACCESS_TO.getMessageReplaced("styles"))); + } + styleIcon.setItemMeta(styleIconMeta); + + ItemStack dataIcon = new ItemStack(defaultMenuIcons[2], 1); + ItemMeta dataIconMeta = dataIcon.getItemMeta(); + dataIconMeta.setDisplayName(ChatColor.GREEN + "Data"); + ParticleEffect pe = p.getParticleEffect(); + String dataType = "data"; + if (pe.hasProperty(ParticleProperty.COLORABLE)) if (pe == ParticleEffect.NOTE) dataType = "note " + dataType; + else dataType = "color " + dataType; + else if (pe.hasProperty(ParticleProperty.REQUIRES_DATA)) if (pe == ParticleEffect.ITEM_CRACK) dataType = "item " + dataType; + else dataType = "block " + dataType; + dataIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SET_YOUR.getMessageReplaced(dataType))); + if (p.getParticleSpawnData() == null && p.getParticleSpawnColor() == null) { + dataIconMeta.setLore(Arrays.asList(MessageType.GUI_NO_DATA.getMessage())); + } + dataIcon.setItemMeta(dataIconMeta); + + inventory.setItem(13, currentIcon); + inventory.setItem(38, effectIcon); + inventory.setItem(40, styleIcon); + inventory.setItem(42, dataIcon); + } + + /** + * Opens the menu that allows you to select an effect you have permission for + * + * @param p The PPlayer + */ + private static void populateEffect(PPlayer p) { + Player player = p.getPlayer(); + Inventory inventory = player.getOpenInventory().getTopInventory(); + + inventory.clear(); // Make sure the inventory is always empty before we start adding items + + List effectsUserHasPermissionFor = PermissionManager.getEffectsUserHasPermissionFor(player); + for (int i = 0; i < effectsUserHasPermissionFor.size(); i++) { + String s = effectsUserHasPermissionFor.get(i); + ParticleEffect effect = ParticleManager.effectFromString(s); + inventory.setItem(i, getItemForEffect(effect, effect == p.getParticleEffect())); + } + + inventory.setItem(INVENTORY_SIZE - 1, getItemForBack()); + } + + /** + * Opens the menu that allows you to select a style you have permission for + * + * @param p The PPlayer + */ + private static void populateStyle(PPlayer p) { + Player player = p.getPlayer(); + Inventory inventory = player.getOpenInventory().getTopInventory(); + + inventory.clear(); // Make sure the inventory is always empty before we start adding items + + List stylesUserHasPermissionFor = PermissionManager.getStylesUserHasPermissionFor(player); + for (int i = 0; i < stylesUserHasPermissionFor.size(); i++) { + String s = stylesUserHasPermissionFor.get(i); + ParticleStyle style = ParticleStyleManager.styleFromString(s); + inventory.setItem(i, getItemForStyle(style, style == p.getParticleStyle())); + } + + inventory.setItem(INVENTORY_SIZE - 1, getItemForBack()); + } + + /** + * Opens the menu that allows you to select some preset data + * + * @param p The PPlayer + */ + private static void populateData(PPlayer p) { + Player player = p.getPlayer(); + Inventory inventory = player.getOpenInventory().getTopInventory(); + + inventory.clear(); // Make sure the inventory is always empty before we start adding items + + // There are a lot of for loops here, somebody submit a pull request if you have a better way of doing this + ParticleEffect pe = p.getParticleEffect(); + if (pe.hasProperty(ParticleProperty.COLORABLE)) { + if (pe == ParticleEffect.NOTE) { // Note data + NoteColor currentNote = p.getNoteColorData(); + int noteIndex = 0; + for (int i = 1; i <= 7; i++) { // Top row + inventory.setItem(i, getItemForNoteData(currentNote, noteIndex)); + noteIndex++; + } + for (int i = 10; i <= 16; i++) { // Middle 1 row + inventory.setItem(i, getItemForNoteData(currentNote, noteIndex)); + noteIndex++; + } + for (int i = 19; i <= 25; i++) { // Middle 2 row + inventory.setItem(i, getItemForNoteData(currentNote, noteIndex)); + noteIndex++; + } + for (int i = 28; i <= 30; i++) { // Bottom row + inventory.setItem(i, getItemForNoteData(currentNote, noteIndex)); + noteIndex++; + } + + inventory.setItem(40, getItemForRainbowNoteData(p.getNoteColorData(), rainbowColors[rainbowColorsIndex])); + } else { // Color data + OrdinaryColor currentColor = p.getColorData(); + int colorIndex = 0; + for (int i = 10; i <= 16; i++) { // Top row + inventory.setItem(i, getItemForColorData(currentColor, colorIndex)); + colorIndex++; + } + for (int i = 19; i <= 25; i++) { // Middle row + inventory.setItem(i, getItemForColorData(currentColor, colorIndex)); + colorIndex++; + } + for (int i = 28; i <= 29; i++) { // Bottom row + inventory.setItem(i, getItemForColorData(currentColor, colorIndex)); + colorIndex++; + } + + inventory.setItem(40, getItemForRainbowColorData(p.getColorData(), rainbowColors[rainbowColorsIndex])); + } + } else if (pe.hasProperty(ParticleProperty.REQUIRES_DATA)) { + if (pe == ParticleEffect.ITEM_CRACK) { // Item data + Material currentItemMaterial = p.getItemData().getMaterial(); + int itemMaterialIndex = 0; + for (int i = 10; i <= 16; i++) { // Top row + inventory.setItem(i, getItemForMaterialData(currentItemMaterial, "item", itemMaterials[itemMaterialIndex])); + itemMaterialIndex++; + } + for (int i = 19; i <= 25; i++) { // Middle 1 row + inventory.setItem(i, getItemForMaterialData(currentItemMaterial, "item", itemMaterials[itemMaterialIndex])); + itemMaterialIndex++; + } + for (int i = 28; i <= 34; i++) { // Middle 2 row + inventory.setItem(i, getItemForMaterialData(currentItemMaterial, "item", itemMaterials[itemMaterialIndex])); + itemMaterialIndex++; + } + for (int i = 37; i <= 43; i++) { // Bottom row + inventory.setItem(i, getItemForMaterialData(currentItemMaterial, "item", itemMaterials[itemMaterialIndex])); + itemMaterialIndex++; + } + } else { // Block data + Material currentBlockMaterial = p.getBlockData().getMaterial(); + int blockMaterialIndex = 0; + for (int i = 10; i <= 16; i++) { // Top row + inventory.setItem(i, getItemForMaterialData(currentBlockMaterial, "block", blockMaterials[blockMaterialIndex])); + blockMaterialIndex++; + } + for (int i = 19; i <= 25; i++) { // Middle 1 row + inventory.setItem(i, getItemForMaterialData(currentBlockMaterial, "block", blockMaterials[blockMaterialIndex])); + blockMaterialIndex++; + } + for (int i = 28; i <= 34; i++) { // Middle 2 row + inventory.setItem(i, getItemForMaterialData(currentBlockMaterial, "block", blockMaterials[blockMaterialIndex])); + blockMaterialIndex++; + } + for (int i = 37; i <= 43; i++) { // Bottom row + inventory.setItem(i, getItemForMaterialData(currentBlockMaterial, "block", blockMaterials[blockMaterialIndex])); + blockMaterialIndex++; + } + } + } + + inventory.setItem(INVENTORY_SIZE - 1, getItemForBack()); + } + + /** + * Called whenever something is clicked in an inventory + * Will return immediately if not the particlesInventory + * + * @param e The InventoryClickEvent fired from this event + */ + @EventHandler + public void onInventoryInteract(InventoryClickEvent e) { + if (!(e.getWhoClicked() instanceof Player)) return; // Not sure if I actually have to check this + + Player player = (Player) e.getWhoClicked(); + GuiInventory guiInventory = playerGuiInventories.get(player.getUniqueId()); + + if (guiInventory == null || !guiInventory.getInventory().equals(e.getView().getTopInventory())) return; // Make sure it is the right inventory + + PPlayer pplayer = ConfigManager.getInstance().getPPlayer(player.getUniqueId(), false); + + e.setCancelled(true); + + ItemStack clicked = e.getCurrentItem(); + if (clicked == null || clicked.getType() == Material.AIR) return; // Clicked on an empty slot, do nothing + + // Check back button. This is common for most menus + if (clicked.getItemMeta().getDisplayName().equals(MessageType.GUI_BACK_BUTTON.getMessage())) { + changeState(pplayer, GuiState.DEFAULT); + return; + } + + String name = ChatColor.stripColor(clicked.getItemMeta().getDisplayName()); + switch (guiInventory.getGuiState()) { + case DEFAULT: + if (name.equals("Effect")) { + changeState(pplayer, GuiState.EFFECT); + } else if (name.equals("Style")) { + changeState(pplayer, GuiState.STYLE); + } else if (name.equals("Data")) { + changeState(pplayer, GuiState.DATA); + } + break; + case EFFECT: + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), ParticleManager.effectFromString(name)); + changeState(pplayer, GuiState.DEFAULT); + break; + case STYLE: + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), ParticleStyleManager.styleFromString(name)); + changeState(pplayer, GuiState.DEFAULT); + break; + case DATA: + ParticleEffect pe = pplayer.getParticleEffect(); + if (pe.hasProperty(ParticleProperty.COLORABLE)) { + if (pe == ParticleEffect.NOTE) { + if (clicked.getItemMeta().getDisplayName().equals(rainbowName)) { + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), new NoteColor(99)); + } else { + int note = Integer.parseInt(ChatColor.stripColor(clicked.getItemMeta().getDisplayName()).substring(6)); + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), new NoteColor(note)); + } + } else { + if (clicked.getItemMeta().getDisplayName().equals(rainbowName)) { + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), new OrdinaryColor(999, 999, 999)); + } else { + for (int i = 0; i < colorMappingNames.length; i++) { + if (clicked.getItemMeta().getDisplayName().equals(colorMappingNames[i])) { + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), getColorMappingEntry(i).getValue()); + } + } + } + } + } else if (pe.hasProperty(ParticleProperty.REQUIRES_DATA)) { + Material clickedMaterial = clicked.getType(); // All preset materials have a data value of 0 + if (pe == ParticleEffect.ITEM_CRACK) { + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), new ItemData(clickedMaterial, (byte)0)); + } else { + ConfigManager.getInstance().savePPlayer(pplayer.getUniqueId(), new BlockData(clickedMaterial, (byte)0)); + } + } + + changeState(pplayer, GuiState.DEFAULT); + break; + } + } + + /** + * Gets a DyeColor, OrdinaryColor pair from the colorMapping LinkedHashSet + * + * @param colorIndex The index to get the pair from + * @return A DyeColor, OrdinaryColor pair + */ + @SuppressWarnings("unchecked") + private static Map.Entry getColorMappingEntry(int colorIndex) { + Set> mapSet = colorMapping.entrySet(); + return (Map.Entry) mapSet.toArray()[colorIndex]; + } + + /** + * Gets the icon for a given particle effect from the config + * + * @param effect The effect + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForEffect(ParticleEffect effect, boolean isActive) { + ItemStack icon = new ItemStack(effectIcons.get(effect.name()), 1); + ItemMeta iconMeta = icon.getItemMeta(); + + iconMeta.setDisplayName(MessageType.GUI_ICON_NAME_COLOR.getMessage() + effect.getName()); + if (!isActive) { + iconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("effect") + effect.getName())); + } else { + iconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("effect") + effect.getName(), MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("effect"))); + iconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + iconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + icon.setItemMeta(iconMeta); + + return icon; + } + + /** + * Gets the icon for a given particle style from the config + * + * @param style The style + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForStyle(ParticleStyle style, boolean isActive) { + ItemStack icon = new ItemStack(styleIcons.get(style.getName().toUpperCase()), 1); + ItemMeta iconMeta = icon.getItemMeta(); + + iconMeta.setDisplayName(MessageType.GUI_ICON_NAME_COLOR.getMessage() + style.getName()); + if (!isActive) { + iconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("style") + style.getName())); + } else { + iconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("style") + style.getName(), MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("style"))); + iconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + iconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + icon.setItemMeta(iconMeta); + + return icon; + } + + /** + * Gets the icon for a given material to be used for data + * + * @param currentMaterial What material the player is currently using + * @param dataType What type of data this is (block/item) + * @param material The material to use for the icon + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForMaterialData(Material currentMaterial, String dataType, Material material) { + ItemStack materialIcon = new ItemStack(material, 1); + ItemMeta materialIconMeta = materialIcon.getItemMeta(); + + materialIconMeta.setDisplayName(MessageType.GUI_ICON_NAME_COLOR.getMessage() + material.name().toLowerCase()); + if (currentMaterial != material) { + materialIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced(dataType + " data") + material.name().toLowerCase())); + } else { + materialIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced(dataType + " data") + material.name().toLowerCase(), MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced(dataType + " data"))); + materialIconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + materialIconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + materialIcon.setItemMeta(materialIconMeta); + + return materialIcon; + } + + /** + * Gets the icon for a color to be used for data + * + * @param currentColor What color the player is currently using + * @param colorIndex What color to use + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForColorData(OrdinaryColor currentColor, int colorIndex) { + Map.Entry colorMappingEntry = getColorMappingEntry(colorIndex); + DyeColor dyeColor = colorMappingEntry.getKey(); + OrdinaryColor displayColor = colorMappingEntry.getValue(); + String formattedDisplayColor = ChatColor.RED.toString() + displayColor.getRed() + " " + ChatColor.GREEN + displayColor.getGreen() + " " + ChatColor.AQUA + displayColor.getBlue(); + + ItemStack colorIcon = new Dye(dyeColor).toItemStack(1); + ItemMeta colorIconMeta = colorIcon.getItemMeta(); + + colorIconMeta.setDisplayName(colorMappingNames[colorIndex]); + if (!currentColor.equals(displayColor)) { + colorIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("color data") + formattedDisplayColor)); + } else { + colorIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("color data") + formattedDisplayColor, MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("color data"))); + colorIconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + colorIconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + colorIcon.setItemMeta(colorIconMeta); + + return colorIcon; + } + + /** + * Gets the icon for a note to be used for data + * + * @param currentNote What note the player is currently using + * @param noteIndex What note to use + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForNoteData(NoteColor currentNote, int noteIndex) { + ItemStack noteIcon = new ItemStack(Material.NOTE_BLOCK, noteIndex + 1); + ItemMeta noteIconMeta = noteIcon.getItemMeta(); + + noteIconMeta.setDisplayName(MessageType.GUI_ICON_NAME_COLOR.getMessage() + "note #" + noteIndex); + if (currentNote.getValueX() * 24 != noteIndex) { + noteIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("note data") + "note #" + noteIndex)); + } else { + noteIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("note data") + "note #" + noteIndex, MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("note data"))); + noteIconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + noteIconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + noteIcon.setItemMeta(noteIconMeta); + + return noteIcon; + } + + /** + * Gets the icon for rainbow color/note data + * + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForRainbowColorData(OrdinaryColor currentColor, DyeColor dyeColor) { + ItemStack rainbowIcon = new Wool(dyeColor).toItemStack(1); + ItemMeta rainbowIconMeta = rainbowIcon.getItemMeta(); + + rainbowIconMeta.setDisplayName(rainbowName); + if (currentColor.getRed() == 999 && currentColor.getGreen() == 999 && currentColor.getBlue() == 999) { + rainbowIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("color data") + rainbowName, MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("color data"))); + rainbowIconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + rainbowIconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } else { + rainbowIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("color data") + rainbowName)); + } + rainbowIcon.setItemMeta(rainbowIconMeta); + + return rainbowIcon; + } + + /** + * Gets the icon for rainbow color/note data + * + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForRainbowNoteData(NoteColor currentColor, DyeColor dyeColor) { + ItemStack rainbowIcon = new Wool(dyeColor).toItemStack(1); + ItemMeta rainbowIconMeta = rainbowIcon.getItemMeta(); + + rainbowIconMeta.setDisplayName(rainbowName); + if (currentColor.getValueX() * 24 == 99) { + rainbowIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("note data") + rainbowName, MessageType.GUI_ICON_CURRENT_ACTIVE.getMessageReplaced("note data"))); + rainbowIconMeta.addEnchant(Enchantment.ARROW_INFINITE, -1, true); + rainbowIconMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } else { + rainbowIconMeta.setLore(Arrays.asList(MessageType.GUI_ICON_SETS_TO.getMessageReplaced("note data") + rainbowName)); + } + rainbowIcon.setItemMeta(rainbowIconMeta); + + return rainbowIcon; + } + + /** + * Gets the icon used to return to the previous menu + * + * @return An ItemStack formatted to be displayed in the GUI + */ + private static ItemStack getItemForBack() { + ItemStack icon = new ItemStack(Material.ARROW, 1); + ItemMeta iconMeta = icon.getItemMeta(); + iconMeta.setDisplayName(MessageType.GUI_BACK_BUTTON.getMessage()); + icon.setItemMeta(iconMeta); + + return icon; + } + +} diff --git a/src/com/esophose/playerparticles/library/ParticleEffect.java b/src/com/esophose/playerparticles/library/ParticleEffect.java index 108b9e2..0acced7 100644 --- a/src/com/esophose/playerparticles/library/ParticleEffect.java +++ b/src/com/esophose/playerparticles/library/ParticleEffect.java @@ -46,9 +46,7 @@ import com.esophose.playerparticles.library.ReflectionUtils.PackageType; /** * Modified a couple things for the plugin - * - * Updated to 1.11 - * + * Updated to 1.12 * @author (of changes) Esophose */ public enum ParticleEffect { @@ -738,8 +736,8 @@ public enum ParticleEffect { /** * Represents the particle data for effects like - * {@link ParticleEffect#ITEM_CRACK}, {@link ParticleEffect#BLOCK_CRACK} and - * {@link ParticleEffect#BLOCK_DUST} + * {@link ParticleEffect#ITEM_CRACK}, {@link ParticleEffect#BLOCK_CRACK}, + * {@link ParticleEffect#BLOCK_DUST}, and {@link ParticleEffect#FALLING_DUST} *

* This class is part of the ParticleEffect Library and follows the * same usage conditions diff --git a/src/com/esophose/playerparticles/manager/ConfigManager.java b/src/com/esophose/playerparticles/manager/ConfigManager.java index 7697ed2..0529751 100644 --- a/src/com/esophose/playerparticles/manager/ConfigManager.java +++ b/src/com/esophose/playerparticles/manager/ConfigManager.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -640,7 +640,7 @@ public class ConfigManager { double xPos = res.getDouble("f.xPos"); double yPos = res.getDouble("f.yPos"); double zPos = res.getDouble("f.zPos"); - ParticleEffect particleEffect = ParticleManager.particleFromString(res.getString("f.effect")); + ParticleEffect particleEffect = ParticleManager.effectFromString(res.getString("f.effect")); ParticleStyle particleStyle = ParticleStyleManager.styleFromString(res.getString("f.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")); @@ -701,7 +701,7 @@ public class ConfigManager { double xPos = res.getDouble("f.xPos"); double yPos = res.getDouble("f.yPos"); double zPos = res.getDouble("f.zPos"); - ParticleEffect particleEffect = ParticleManager.particleFromString(res.getString("f.effect")); + ParticleEffect particleEffect = ParticleManager.effectFromString(res.getString("f.effect")); ParticleStyle particleStyle = ParticleStyleManager.styleFromString(res.getString("f.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")); diff --git a/src/com/esophose/playerparticles/manager/MessageManager.java b/src/com/esophose/playerparticles/manager/MessageManager.java index a58de9a..3150da2 100644 --- a/src/com/esophose/playerparticles/manager/MessageManager.java +++ b/src/com/esophose/playerparticles/manager/MessageManager.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -34,7 +34,6 @@ public class MessageManager { NO_STYLES("message-no-styles"), NOW_USING_STYLE("message-now-using-style"), CLEARED_STYLE("message-cleared-style"), - USE_STYLE("message-use-style"), INVALID_TYPE_STYLE("message-invalid-type-style"), STYLE_USAGE("message-style-usage"), @@ -84,6 +83,17 @@ public class MessageManager { MAX_FIXED_EFFECTS_REACHED("message-max-fixed-effects-reached"), INVALID_FIXED_COMMAND("message-invalid-fixed-command"), + // GUI + GUI_DISABLED("message-gui-disabled"), + GUI_BY_DEFAULT("message-gui-by-default"), + GUI_BACK_BUTTON("message-gui-back-button"), + GUI_ICON_NAME_COLOR("message-gui-icon-name-color"), + GUI_ICON_CURRENT_ACTIVE("message-gui-icon-current-active"), + GUI_ICON_SETS_TO("message-gui-icon-sets-to"), + GUI_ICON_SET_YOUR("message-gui-icon-set-your"), + GUI_NO_ACCESS_TO("message-gui-no-access-to"), + GUI_NO_DATA("message-gui-no-data"), + // Prefixes USE("message-use"), USAGE("message-usage"), @@ -99,19 +109,48 @@ public class MessageManager { FAILED_EXECUTE_NOT_FOUND("message-failed-execute-not-found"), FAILED_EXECUTE_NO_PERMISSION("message-failed-execute-no-permission"); - public String configLocation; + private String configLocation; + private String message; MessageType(String configLocation) { this.configLocation = configLocation; } + + /** + * Sets the message from the config + * + * @param config The config to pull the message from + */ + protected void setMessage(FileConfiguration config) { + try { + String messageFromConfig = config.getString(configLocation); + if (messageFromConfig == null || messageFromConfig.length() == 0) { + messageFromConfig = "&cMissing message in config.yml. Contact a server administrator."; + PlayerParticles.getPlugin().getLogger().warning("Missing message in config.yml: " + this.configLocation); + } + this.message = ChatColor.translateAlternateColorCodes('&', messageFromConfig); + } catch (Exception ex) { + System.out.println(this.name()); + } + } /** - * Gets the message with the given config path + * Gets the message this enum represents * - * @return The message from the config + * @return The message */ public String getMessage() { - return ChatColor.translateAlternateColorCodes('&', config.getString(this.configLocation)); + return this.message; + } + + /** + * Gets the message this enum represents and replace {TYPE} with a replacement value + * + * @param replacement The text to replace {TYPE} with + * @return The message with {TYPE} replaced with the replacement value + */ + public String getMessageReplaced(String replacement) { + return this.message.replaceAll("\\{TYPE\\}", replacement); } } @@ -138,6 +177,10 @@ public class MessageManager { messagesEnabled = config.getBoolean("messages-enabled"); prefixEnabled = config.getBoolean("use-message-prefix"); messagePrefix = parseColors(config.getString("message-prefix")); + + for (MessageType messageType : MessageType.values()) { + messageType.setMessage(config); + } } /** @@ -153,11 +196,15 @@ public class MessageManager { if (prefixEnabled) { message = messagePrefix + " " + message; } + + if (message.trim().equals("")) return; + player.sendMessage(message); } /** * Sends a message to the given player and allows for replacing {TYPE} + * * @param player The player to send the message to * @param messageType The message to send to the player * @param typeReplacement What {TYPE} should be replaced with @@ -165,10 +212,13 @@ public class MessageManager { public static void sendMessage(Player player, MessageType messageType, String typeReplacement) { if (!messagesEnabled) return; - String message = messageType.getMessage().replaceAll("\\{TYPE\\}", typeReplacement); + String message = messageType.getMessageReplaced(typeReplacement); if (prefixEnabled) { message = messagePrefix + " " + message; } + + if (message.trim().equals("")) return; + player.sendMessage(message); } @@ -185,14 +235,17 @@ public class MessageManager { if (prefixEnabled) { message = messagePrefix + " " + message; } + + if (message.trim().equals("")) return; + player.sendMessage(message); } /** * Translates all ampersand symbols into the Minecraft chat color symbol * - * @param message The input - * @return The output, parsed + * @param message The input string + * @return The output string, parsed */ public static String parseColors(String message) { return ChatColor.translateAlternateColorCodes('&', message); diff --git a/src/com/esophose/playerparticles/manager/ParticleManager.java b/src/com/esophose/playerparticles/manager/ParticleManager.java index d6d2f98..f0a4412 100644 --- a/src/com/esophose/playerparticles/manager/ParticleManager.java +++ b/src/com/esophose/playerparticles/manager/ParticleManager.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -36,7 +36,8 @@ public class ParticleManager extends BukkitRunnable implements Listener { /** * How far away particles will spawn from players */ - public static final int PARTICLE_RANGE = 512; + public static final int PLAYER_PARTICLE_RANGE = 128; + public static final int FIXED_EFFECT_PARTICLE_RANGE = 256; /** * The list containing all the player effect info @@ -141,14 +142,14 @@ public class ParticleManager extends BukkitRunnable implements Listener { } /** - * Gets a particle type from a string, used for getting ParticleType's from the saved data + * Gets an effect type from a string, used for getting ParticleEffects 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 + * @param effectName The name of the particle to check for + * @return The ParticleEffect with the given name, will be null if name was not found */ - public static ParticleEffect particleFromString(String particle) { + public static ParticleEffect effectFromString(String effectName) { for (ParticleEffect effect : ParticleEffect.getSupportedEffects()) { - if (effect.getName().toLowerCase().replace("_", "").equals(particle.toLowerCase())) return effect; + if (effect.getName().toLowerCase().replace("_", "").equals(effectName.toLowerCase())) return effect; } return null; } @@ -237,11 +238,11 @@ public class ParticleManager extends BukkitRunnable implements Listener { 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)), PARTICLE_RANGE); + effect.display(pplayer.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } else if (effect.hasProperty(ParticleProperty.COLORABLE)) { - effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } else { - effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } } } @@ -258,11 +259,11 @@ public class ParticleManager extends BukkitRunnable implements Listener { 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)), PARTICLE_RANGE); + effect.display(pplayer.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } else if (effect.hasProperty(ParticleProperty.COLORABLE)) { - effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(pplayer.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } else { - effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PLAYER_PARTICLE_RANGE); } } } @@ -277,11 +278,11 @@ public class ParticleManager extends BukkitRunnable implements Listener { ParticleEffect effect = fixedEffect.getParticleEffect(); for (PParticle particle : fixedEffect.getParticleStyle().getParticles(fakePPlayer, fixedEffect.getLocation())) { if (effect.hasProperty(ParticleProperty.REQUIRES_DATA)) { - effect.display(fixedEffect.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(fixedEffect.getParticleSpawnData(), particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), FIXED_EFFECT_PARTICLE_RANGE); } else if (effect.hasProperty(ParticleProperty.COLORABLE)) { - effect.display(fixedEffect.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(fixedEffect.getParticleSpawnColor(), particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), FIXED_EFFECT_PARTICLE_RANGE); } else { - effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), PARTICLE_RANGE); + effect.display(particle.getXOff(), particle.getYOff(), particle.getZOff(), particle.getSpeed(), 1, particle.getLocation(effect.hasProperty(ParticleProperty.COLORABLE)), FIXED_EFFECT_PARTICLE_RANGE); } } } diff --git a/src/com/esophose/playerparticles/manager/PermissionManager.java b/src/com/esophose/playerparticles/manager/PermissionManager.java index 115188d..49117a5 100644 --- a/src/com/esophose/playerparticles/manager/PermissionManager.java +++ b/src/com/esophose/playerparticles/manager/PermissionManager.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -56,7 +56,7 @@ public class PermissionManager { * @param p The player to get effect names for * @return A String List of all effect names the given player has permission for */ - public static List getParticlesUserHasPermissionFor(Player p) { + public static List getEffectsUserHasPermissionFor(Player p) { List list = new ArrayList(); for (ParticleEffect pe : ParticleEffect.getSupportedEffects()) { if (hasEffectPermission(p, pe)) list.add(pe.getName().toLowerCase().replace("_", "")); @@ -97,5 +97,16 @@ public class PermissionManager { public static boolean canUseFixedEffects(Player player) { return player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.fixed"); } + + /** + * Checks if a player has permission to open the GUI + * Access is restricted if they have the following permission + * + * @param player The player to check the permission for + * @return False if the player's access to the GUI is revoked + */ + public static boolean canUseGui(Player player) { + return !player.hasPermission("playerparticles.gui.revoke"); + } } diff --git a/src/com/esophose/playerparticles/styles/DefaultStyles.java b/src/com/esophose/playerparticles/styles/DefaultStyles.java index 6e08ecf..f884925 100644 --- a/src/com/esophose/playerparticles/styles/DefaultStyles.java +++ b/src/com/esophose/playerparticles/styles/DefaultStyles.java @@ -25,6 +25,8 @@ public class DefaultStyles { public static final ParticleStyle ARROWS = new ParticleStyleArrows(); public static final ParticleStyle SPIRAL = new ParticleStyleSpiral(); public static final ParticleStyle THICK = new ParticleStyleThick(); + public static final ParticleStyle WINGS = new ParticleStyleWings(); + public static final ParticleStyle SPHERE = new ParticleStyleSphere(); /** * Registers all the default styles to the ParticleStyleManager @@ -43,6 +45,8 @@ public class DefaultStyles { ParticleStyleManager.registerStyle(ARROWS); ParticleStyleManager.registerStyle(SPIRAL); ParticleStyleManager.registerStyle(THICK); + ParticleStyleManager.registerStyle(WINGS); + ParticleStyleManager.registerStyle(SPHERE); Bukkit.getPluginManager().registerEvents((Listener) MOVE, PlayerParticles.getPlugin()); Bukkit.getPluginManager().registerEvents((Listener) ARROWS, PlayerParticles.getPlugin()); diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleCube.java b/src/com/esophose/playerparticles/styles/ParticleStyleCube.java index 2590df2..4c11b5a 100644 --- a/src/com/esophose/playerparticles/styles/ParticleStyleCube.java +++ b/src/com/esophose/playerparticles/styles/ParticleStyleCube.java @@ -36,60 +36,65 @@ import com.esophose.playerparticles.util.VectorUtils; /** * Credit goes to Slikey who made all this logic for drawing a cube out of particles - * The project this is from is called EffectLib and can be found here: + * The project this is from is called EffectLib and can be found here: * https://github.com/Slikey/EffectLib */ public class ParticleStyleCube implements ParticleStyle { - + private float edgeLength = 2; private double angularVelocityX = (Math.PI / 200) / 5; private double angularVelocityY = (Math.PI / 170) / 5; private double angularVelocityZ = (Math.PI / 155) / 5; - private int particles = 8; + private int particles = 7; private int step = 0; - + private boolean skipNextStep = false; // Only spawn every 2 ticks + public PParticle[] getParticles(PPlayer pplayer, Location location) { List pparticles = new ArrayList(); - - double xRotation = 0, yRotation = 0, zRotation = 0; - xRotation = step * angularVelocityX; - yRotation = step * angularVelocityY; - zRotation = step * angularVelocityZ; - float a = edgeLength / 2; - double angleX, angleY; - Vector v = new Vector(); - for (int i = 0; i < 4; i++) { - angleY = i * Math.PI / 2; - for (int j = 0; j < 2; j++) { - angleX = j * Math.PI; - for (int p = 0; p <= particles; p++) { - v.setX(a).setY(a); - v.setZ(edgeLength * p / particles - a); - VectorUtils.rotateAroundAxisX(v, angleX); - VectorUtils.rotateAroundAxisY(v, angleY); - VectorUtils.rotateVector(v, xRotation, yRotation, zRotation); - pparticles.add(new PParticle(location.clone().add(v))); - } - } - for (int p = 0; p <= particles; p++) { - v.setX(a).setZ(a); - v.setY(edgeLength * p / particles - a); - VectorUtils.rotateAroundAxisY(v, angleY); - VectorUtils.rotateVector(v, xRotation, yRotation, zRotation); - pparticles.add(new PParticle(location.clone().add(v))); - } - } + + if (!skipNextStep) { + double xRotation = 0, yRotation = 0, zRotation = 0; + xRotation = step * angularVelocityX; + yRotation = step * angularVelocityY; + zRotation = step * angularVelocityZ; + float a = edgeLength / 2; + double angleX, angleY; + Vector v = new Vector(); + for (int i = 0; i < 4; i++) { + angleY = i * Math.PI / 2; + for (int j = 0; j < 2; j++) { + angleX = j * Math.PI; + for (int p = 0; p <= particles; p++) { + v.setX(a).setY(a); + v.setZ(edgeLength * p / particles - a); + VectorUtils.rotateAroundAxisX(v, angleX); + VectorUtils.rotateAroundAxisY(v, angleY); + VectorUtils.rotateVector(v, xRotation, yRotation, zRotation); + pparticles.add(new PParticle(location.clone().add(v))); + } + } + for (int p = 0; p <= particles; p++) { + v.setX(a).setZ(a); + v.setY(edgeLength * p / particles - a); + VectorUtils.rotateAroundAxisY(v, angleY); + VectorUtils.rotateVector(v, xRotation, yRotation, zRotation); + pparticles.add(new PParticle(location.clone().add(v))); + } + } + } + return pparticles.toArray(new PParticle[pparticles.size()]); } public void updateTimers() { + skipNextStep = !skipNextStep; step++; } public String getName() { return "cube"; } - + public boolean canBeFixed() { return true; } diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java b/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java index 7f59ecc..6e9e85b 100644 --- a/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java +++ b/src/com/esophose/playerparticles/styles/ParticleStyleQuadhelix.java @@ -16,7 +16,7 @@ public class ParticleStyleQuadhelix implements ParticleStyle { 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 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)); } diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleSphere.java b/src/com/esophose/playerparticles/styles/ParticleStyleSphere.java new file mode 100644 index 0000000..0fe0567 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleSphere.java @@ -0,0 +1,46 @@ +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 ParticleStyleSphere implements ParticleStyle { + + @Override + public PParticle[] getParticles(PPlayer pplayer, Location location) { + int particleCount = 15; + float radius = 1.5f; + PParticle[] particles = new PParticle[particleCount]; + + for (int i = 0; i < particleCount; i++) { + double u = Math.random(); + double v = Math.random(); + double theta = 2 * Math.PI * u; + double phi = Math.acos(2 * v - 1); + double x = location.getX() + (radius * Math.sin(phi) * Math.cos(theta)); + double y = location.getY() + (radius * Math.sin(phi) * Math.sin(theta)); + double z = location.getZ() + (radius * Math.cos(phi)); + particles[i] = new PParticle(new Location(location.getWorld(), x, y, z)); + } + + return particles; + } + + @Override + public void updateTimers() { + + } + + @Override + public String getName() { + return "sphere"; + } + + @Override + public boolean canBeFixed() { + return true; + } + +} diff --git a/src/com/esophose/playerparticles/styles/ParticleStyleWings.java b/src/com/esophose/playerparticles/styles/ParticleStyleWings.java new file mode 100644 index 0000000..af51562 --- /dev/null +++ b/src/com/esophose/playerparticles/styles/ParticleStyleWings.java @@ -0,0 +1,45 @@ +package com.esophose.playerparticles.styles; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.util.Vector; + +import com.esophose.playerparticles.PPlayer; +import com.esophose.playerparticles.styles.api.PParticle; +import com.esophose.playerparticles.styles.api.ParticleStyle; +import com.esophose.playerparticles.util.VectorUtils; + +public class ParticleStyleWings implements ParticleStyle { + + int spawnTimer = 0; // Spawn particles every 3 ticks + + public PParticle[] getParticles(PPlayer pplayer, Location location) { + List particles = new ArrayList(); + if (spawnTimer == 0) { + for (double t = 0; t < Math.PI * 2; t += Math.PI / 64) { + double x = Math.sin(t) * (Math.pow(Math.E, Math.cos(t)) - 2 * Math.cos(t * 4) - Math.pow(Math.sin(t / 12), 5)) / 2; + double y = Math.cos(t) * (Math.pow(Math.E, Math.cos(t)) - 2 * Math.cos(t * 4) - Math.pow(Math.sin(t / 12), 5)) / 2; + Vector v = VectorUtils.rotateAroundAxisY(new Vector(x, y, -0.3), -Math.toRadians(location.getYaw())); + Location loc = new Location(location.getWorld(), location.getX() + v.getX(), location.getY() + v.getY(), location.getZ() + v.getZ()); + particles.add(new PParticle(loc)); + } + } + return particles.toArray(new PParticle[particles.size()]); + } + + public void updateTimers() { + spawnTimer++; + spawnTimer %= 3; + } + + public String getName() { + return "wings"; + } + + public boolean canBeFixed() { + return false; + } + +} diff --git a/src/com/esophose/playerparticles/styles/api/PParticle.java b/src/com/esophose/playerparticles/styles/api/PParticle.java index fe40756..8eb8d23 100644 --- a/src/com/esophose/playerparticles/styles/api/PParticle.java +++ b/src/com/esophose/playerparticles/styles/api/PParticle.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -80,7 +80,7 @@ public class PParticle { } /** - * Gets the offset on the x axis for the particle + * Gets the offset on the x-axis for the particle * * @return The x-axis offset */ diff --git a/src/com/esophose/playerparticles/styles/api/ParticleStyle.java b/src/com/esophose/playerparticles/styles/api/ParticleStyle.java index 2905908..99d3d3c 100644 --- a/src/com/esophose/playerparticles/styles/api/ParticleStyle.java +++ b/src/com/esophose/playerparticles/styles/api/ParticleStyle.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 diff --git a/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java b/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java index 866d0c6..f00bea0 100644 --- a/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java +++ b/src/com/esophose/playerparticles/styles/api/ParticleStyleManager.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -69,9 +69,8 @@ public class ParticleStyleManager { * @return The ParticleStyle with the name requested */ public static ParticleStyle styleFromString(String styleName) { - for (ParticleStyle style : styles) { + for (ParticleStyle style : styles) if (style.getName().toLowerCase().replace("_", "").equals(styleName)) return style; - } return null; } @@ -81,9 +80,8 @@ public class ParticleStyleManager { * Do not call this in your plugin, it will mess with other styles */ public static void updateTimers() { - for (ParticleStyle style : styles) { + for (ParticleStyle style : styles) style.updateTimers(); - } } /** diff --git a/src/com/esophose/playerparticles/updater/PluginUpdateListener.java b/src/com/esophose/playerparticles/updater/PluginUpdateListener.java index 6d71f2c..6acaac3 100644 --- a/src/com/esophose/playerparticles/updater/PluginUpdateListener.java +++ b/src/com/esophose/playerparticles/updater/PluginUpdateListener.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 diff --git a/src/com/esophose/playerparticles/util/ParticleUtils.java b/src/com/esophose/playerparticles/util/ParticleUtils.java index 1d50b44..7941207 100644 --- a/src/com/esophose/playerparticles/util/ParticleUtils.java +++ b/src/com/esophose/playerparticles/util/ParticleUtils.java @@ -1,5 +1,5 @@ /** - * Copyright Esophose 2017 + * Copyright Esophose 2018 * 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 @@ -8,30 +8,28 @@ package com.esophose.playerparticles.util; -import java.util.ArrayList; - import org.bukkit.Material; public class ParticleUtils { /** * Finds a block/item as a material from a string - * There must be some better way to do this that reliably gets the correct material * * @param input The material name as a string * @return The material from the string */ - @SuppressWarnings("deprecation") public static Material closestMatch(String input) { - ArrayList matchList = new ArrayList(); - for (Material material : Material.values()) - if (material.name().replaceAll("_", " ").toLowerCase().equals(input.toLowerCase()) || String.valueOf(material.getId()).equals(input)) - return material; - else if (material.name().replaceAll("_", " ").toLowerCase().contains(input.toLowerCase())) - matchList.add(material); - - if (matchList.size() == 1) return matchList.get(0); - else return null; + if (input == null) return null; + for (Material material : Material.values()) // First check for exact matches + if (material.name().equalsIgnoreCase(input) || + material.toString().equalsIgnoreCase(input)) return material; + for (Material material : Material.values()) // Then check for partial matches + if (material.name().toLowerCase().contains(input.toLowerCase()) || + material.toString().toLowerCase().contains(input.toLowerCase()) || + material.name().replaceAll("_", "").toLowerCase().contains(input.toLowerCase()) || + material.toString().replaceAll("_", "").toLowerCase().contains(input.toLowerCase())) + return material; + return null; } /** diff --git a/src/config.yml b/src/config.yml index aba70e6..886bd38 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,11 +1,9 @@ -# ____________ __________ __ __ __ _____ -# \______ \ | _____ ___ __ __________\______ \_____ ________/ |_|__| ____ | | ____ ______ ___ __/ | | -# | ___/ | \__ \< | |/ __ \_ __ \ ___/\__ \\_ __ \ __\ |/ ___\| | _/ __ \ / ___/ \ \/ / | |_ -# | | | |__/ __ \\___ \ ___/| | \/ | / __ \| | \/| | | \ \___| |_\ ___/ \___ \ \ / ^ / -# |____| |____(____ / ____|\___ >__| |____| (____ /__| |__| |__|\___ >____/\___ >____ > \_/\____ | -# \/\/ \/ \/ \/ \/ \/ |__| - -# Please excuse the cheesy ASCII Art +# __________ __ __________ __ __ __ ________ +# \______ \ | _____ ___ __ __________\______ \_____ ________/ |_|__| ____ | | ____ ______ ___ _| ____/ +# | ___/ | \__ \< | |/ __ \_ __ \ ___/\__ \\_ __ \ __\ |/ ___\| | _/ __ \ / ___/ \ \/ /____ \ +# | | | |__/ __ \\___ \ ___/| | \/ | / __ \| | \/| | | \ \___| |_\ ___/ \___ \ \ // \ +# |____| |____(____ / ____|\___ >__| |____| (____ /__| |__| |__|\___ >____/\___ >____ > \_//______ / +# \/\/ \/ \/ \/ \/ \/ \/ # ==================================================== # # PlayerParticles Config # @@ -14,19 +12,19 @@ # Changing this value will reset your config on the next server reload / restart. # I don't recommend changing it -version: 4.5 - -# How many ticks to wait before spawning more particles -# Increasing this value may cause less lag (if there was any), but will decrease prettiness -# The lowest possible value is 1 -# Going over 5 will likely look terrible -# Default: 1 -ticks-per-particle: 1 +# NOTE: Updating to a new version of the plugin will change this number and delete your config. +# Make sure you create a backup each time before you update! +version: 5.0 # Check for new versions of the plugin # Default: true check-updates: true +# If the command /pp gui is enabled +# Disable this if you have your own custom GUI through another plugin +# Default: true +gui-enabled: true + # The worlds which this plugin is disabled in # Remove the [] before you enter world names # Default: [] @@ -42,15 +40,22 @@ max-fixed-effects: 5 # Determines how far away a player may create a fixed effect from themselves # This measurement is in blocks # Set to 0 for infinite distance -# Default: 256 -max-fixed-effect-creation-distance: 256 +# Default: 128 +max-fixed-effect-creation-distance: 128 + +# How many ticks to wait before spawning more particles +# Increasing this value may cause less lag (if there was any), but will decrease prettiness +# Only use whole numbers greater than or equal to 1 +# Going over 3 will likely look terrible +# Default: 1 +ticks-per-particle: 1 # ================================================================ # # MESSAGE CONFIGURATION # # Important Notes: # # * You can use the & symbol to color the messages # # * {TYPE} Will be replaced with whatever that message requires # -# * You can not use the apostrophe character! ( ' ) # +# * You cannot use the apostrophe character! ( ' ) # # ================================================================ # # If you're using other plugins to execute commands you may wish to turn off messages @@ -164,12 +169,12 @@ message-color-data-usage: '&b/pp data [<0-255> <0-255> <0-255>]|[rainbow]' # Item Data Usage # You should not change the text here, only the coloring -# Default: '&b/pp data <0-15>' +# Default: '&b/pp data <0-15>' message-item-data-usage: '&b/pp data <0-15>' # Block Data Usage # You should not change the text here, only the coloring -# Default: '&b/pp data <0-15>' +# Default: '&b/pp data <0-15>' message-block-data-usage: '&b/pp data <0-15>' # ---------------- # @@ -185,8 +190,8 @@ message-use: '&eYou can use:&b' message-usage: '&eUsage:' # Available Commands -# Default: '&eAvailable commands: &beffect, effects, style, styles, data, reset, worlds, version, help' -message-available-commands: '&eAvailable commands: &beffect, effects, style, styles, data, reset, worlds, version, help' +# Default: '&eAvailable commands: &beffect, effects, style, styles, data, reset, gui, worlds, version, help' +message-available-commands: '&eAvailable commands: &beffect, effects, style, styles, data, reset, gui, worlds, version, help' # Disabled Worlds # Default: '&eParticles are disabled in these worlds:&b' @@ -366,6 +371,47 @@ message-fixed-command-desc-info: '&e/pp fixed info - Gets info on one of yo # Default: '&e/pp fixed clear - Clears all fixed effects of all players within the given radius' message-fixed-command-desc-clear: '&e/pp fixed clear - Clears all fixed effects of all players within the given radius' +# ------------- # +# GUI # +# ------------- # + +# Disabled +# Default: '&cThe server administrator has disabled the GUI.' +message-gui-disabled: '&cThe server administrator has disabled the GUI.' + +# Opened By Default +# Default: '&eWe opened the GUI for you because you did not specify a command. If you are looking to use a specific command, view them with &b/pp help' +message-gui-by-default: '&eWe opened the GUI for you because you did not specify a command. If you are looking to use a specific command, view them with &b/pp help' + +# Back Button +# Default: '&eGo Back' +message-gui-back-button: '&eGo Back' + +# Icon Name Color +# Default: '&a' +message-gui-icon-name-color: '&a' + +# Currently Active Effect/Style +# Default: '&d- Your current {TYPE} -' +message-gui-icon-current-active: '&d- Your current {TYPE} -' + +# Sets your style/effect to {effect name} +# The effect/style name will be added to the end +# Default: '&eSets your {TYPE} to ' +message-gui-icon-sets-to: '&eSets your {TYPE} to &b' + +# Select Your +# Default: '&eSelect your {TYPE}' +message-gui-icon-set-your: '&eSelect your {TYPE}' + +# No Access To +# Default: '&cYou have no access to any {TYPE}!' +message-gui-no-access-to: '&cYou have no access to any {TYPE}!' + +# No Data +# Default: '&cYour effect does not use any data!' +message-gui-no-data: '&cYour effect does not use any data!' + # ------------- # # Other # # ------------- # @@ -423,5 +469,90 @@ database-user-name: '' # Default: '' database-user-password: '' -# That's everything! You reached the end of the configuration +# =================================================================== # +# GUI ICON SETTINGS # +# This configuration option allows you to change any of the GUI # +# icons to whatever block/item you want. # +# # +# Important Notes: # +# * If any of the block/item names are invalid it will notify you # +# in console and the icon in the GUI will be the barrier icon to # +# show that it failed to load. # +# * Do NOT change the particle/style name # +# * You MUST use the Spigot-given name for it to work. You can see # +# all the Spigot-given names at the link below: # +# https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html # +# =================================================================== # + +gui-icon: + main-menu: + EFFECT: BLAZE_POWDER + STYLE: NETHER_STAR + DATA: BOOK + effect: + NONE: THIN_GLASS + EXPLODE: SULPHUR + LARGE_EXPLODE: FIREBALL + HUGE_EXPLOSION: TNT + FIREWORKS_SPARK: FIREWORK + BUBBLE: GLASS + WAKE: WATER_LILY + SUSPENDED: RAW_FISH + DEPTH_SUSPEND: BEDROCK + CRIT: IRON_SWORD + MAGIC_CRIT: NETHER_STALK + SMOKE: TORCH + LARGE_SMOKE: WEB + SPELL: GLASS_BOTTLE + INSTANT_SPELL: POTION + MOB_SPELL: GLOWSTONE_DUST + MOB_SPELL_AMBIENT: BEACON + WITCH_MAGIC: CAULDRON_ITEM + DRIP_WATER: WATER_BUCKET + DRIP_LAVA: LAVA_BUCKET + ANGRY_VILLAGER: IRON_DOOR + HAPPY_VILLAGER: WOOD_DOOR + NOTE: NOTE_BLOCK + PORTAL: OBSIDIAN + ENCHANTMENT_TABLE: ENCHANTMENT_TABLE + FLAME: BLAZE_POWDER + LAVA: NETHER_BRICK + FOOTSTEP: GRASS + CLOUD: WOOL + RED_DUST: REDSTONE + SNOWBALL_POOF: SNOW_BALL + SNOW_SHOVEL: SNOW + SLIME: SLIME_BALL + HEART: RED_ROSE + BARRIER: BARRIER + ITEM_CRACK: STICK + BLOCK_CRACK: DEAD_BUSH + BLOCK_DUST: SOUL_SAND + DROPLET: LAPIS_ORE + DRAGON_BREATH: DRAGONS_BREATH + END_ROD: END_ROD + DAMAGE_INDICATOR: BOW + SWEEP_ATTACK: GOLD_SWORD + FALLING_DUST: SAND + TOTEM: TOTEM + SPIT: PUMPKIN_SEEDS + style: + NONE: THIN_GLASS + BEAM: POWERED_RAIL + HALO: ENDER_PORTAL_FRAME + POINT: STONE_BUTTON + MOVE: PISTON_BASE + SPIN: BEACON + QUADHELIX: ACTIVATOR_RAIL + ORBIT: ENCHANTMENT_TABLE + FEET: GRASS + CUBE: STONE + ARROWS: BOW + SPIRAL: HOPPER + THICK: VINE + WINGS: ELYTRA + SPHERE: SNOW_BALL + + +# That's everything! You reached the end of the configuration. # Enjoy the plugin! \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index f4b7c17..e91dcec 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,6 +1,6 @@ name: PlayerParticles main: com.esophose.playerparticles.PlayerParticles -version: 4.5 +version: 5.0 description: Make particles around players in fancy ways. author: Esophose website: http://dev.bukkit.org/bukkit-plugins/playerparticles/