Hey, I am trying to make a kit plugin where you type the command and you get your items, but you also have a special ability. The giving yourself items part is easy, and I got that done, but I need to make it so that while they have that kit "enabled" so to say, they can do things like hit people and give them slowness. I would just make it so that in the if statement doing the command I make another if statement saying if they hit the person give them a potion effect, but I don't think that would work, plus I want it to stop after they pick another kit. The only thing I have now is HashMaps. I don't really know anything about them, accept for the fact that they can store boolean values per individual player. Is there an easier way to do this? If not, I'd like some help with HashMaps
I would create a KitType enum where you have all the different kit options and player kits into a HashMap<String, KitType>.
hmm, like I said, I don't really know anything about HashMaps....or enums (I know I sound nooby) chasechocolate mind explaining a bit?
A HashMap is a type of Map that can store value pairs. It holds one unique key that is attached to a value. "Unique" means there can only be one key of a certain type in any HashMap. Trying to attach another value to a key that already exists, will cause the HashMap to overwrite the existing value for that key. HashMaps also do not guarantee that the order of elements are preserved, which means that when you iterate through the map, the order of elements may not always be the same. HashMaps can use any object type as keys, and store any object type as values. Simple usage: Storing a boolean value for each player. Set up a HashMap: Code:java private Map<String, Boolean> yourHashMap = new HashMap<String, Boolean>(); This will create a new HashMap with no entries in it. When a player joins the game, run this method: Code:java yourHashMap.put(player.getName(), true); The HashMap called "yourHashMap" is instructed to store the players name as a key, and attach the value "true" to it. If the players name is already present in the map, the value will be overwritten. When a player disconnects, you would want to remove the player from the map, in order to save resources (RAM): Code:java yourHashMap.remove(player.getName()); The HashMap will delete the key and the value, if it is present in the map. If not, no action is taken. At any given time, you can check the value for a certain player. The HashMap will return "null" if the key is not present in the map. For boolean values, a simple if-statement can be used: Code:java if(yourHashMap.get(player.getName()) {// The player has the value "true" attached to him/her.} Advanced applications: Using custom objects as keys or values Note that a HashMap cannot use primitive data types as keys or values. If you want to use such types, you must use the non-primitive wrapper type for these data types, which just means that you type them with a capital letter. Primitive data types include integers, booleans and bytes. Notice in the previous example how "boolean" is spelled with a capital "B". This is why. For integers, which are normally declared with "int", you would type "Integer" in the HashMap declaration. You can set up a custom object or enum for use as a HashMap value (or key). For example: Code:java // Set up an enum for storing kit types:public enum Kit {SCOUT ("Fast runner, uses bow and arrow"); private String description; public Kit(String description) {this.description = description;} public String getDescription() {return description;}} // Now set up a HashMap using this enum:private Map<String, Kit> playerKits = new HashMap<String, Kit>(); In the same manner as before, use the put()-method to store each players name, and which kit they are using. At any time you can check which kit a certain player has, and even return their kit's description: Code:java if(playerKits.get(player.getName()) != null) {// This player is stored in the HashMap (not null)String description = playerKits.get(player.getName()).getDescription();// "description" now holds the string attached to the enum used for this player} In this way you can store a lot of data in the value section in your HashMap. Description, weapon types, special abilities - you name it. If you want scouts to run faster, just put a method into the the appropriate event where you check the players kit type. If it's a scout, perhaps you want to apply the swiftness potion effect?
kiwhen WOW that was soooo much help! Thank you so much! I would just do that, however the enum is kind of unnecessary with what I am doing. I am just making it so when they type a command it gives them all the items and potion effects with addItem() and addPotionEffect(). I am going to use this HashMap info in an if statement to see if they're string returns as let's say Scout, for example. If their string returns Scout, then make it so they do (Whatever). Would I be able to avoid the if statement if I make an enum and instead of storing the description in it, I can store their special abilities?
Yes and no. The advantage of using the enum-approach is that the enum can store multiple values and run methods at the same time. Let's say that you have a set of three classes; scout, medic and spy. Each one has a unique weapons kit, a special ability and some chat messages explaining to the player what the chosen kit can do. I would type this out like so: Code:java public class Main extends JavaPlugin implements Listener { // The player hashmap private Map<String, Kit> players = new HashMap<String, Kit>(); // Arrays containing the inventory items for each kit private static ItemStack[] kitScout = {new ItemStack(Material.BOW), new ItemStack(Material.ARROW, 32)}; private static ItemStack[] kitMedic = {new ItemStack(Material.DIAMOND_AXE)}; private static ItemStack[] kitSpy = {new ItemStack(Material.DIAMOND_SWORD)}; // The kit enumerator public enum Kit { // Constants SCOUT ("Scout", "Runs fast, uses bow and arrow.", PotionEffectType.SPEED, kitScout), MEDIC ("Medic", "Heals allies, uses axe.", PotionEffectType.REGENERATION, kitMedic), SPY ("Spy", "Turns invisible, uses sword.", PotionEffectType.INVISIBILITY, kitSpy); // Various settings private int abilityDuration = 20 * 10; // 10 seconds in ticks private int medicHealRadius = 5; // Cuboid radius where the medic's heal effect will be effective private int abilityStrength = 2; // The amplifier for the potion effects // Variables private String kitName; private String kitDesc; private PotionEffectType ability; private ItemStack[] gear; // Enum constructor Kit(String kitName, String kitDesc, PotionEffectType ability, ItemStack[] gear) { this.kitName = kitName; this.kitDesc = kitDesc; this.ability = ability; this.gear = gear; } // Methods public String getName() { // Returns the kit's name (properly formatted) return kitName; } public String getDesc() { // Returns the kit's description text return kitDesc; } public void loadKit(Player p) { // Loads the weapons into the players hotbar p.getInventory().clear(); // Delete inventory contents for(ItemStack i : gear) { p.getInventory().addItem(i); } } public void useAbility(Player p) { switch(kitName.toUpperCase()) { case "SCOUT": case "SPY": // Add potion effect to the player p.addPotionEffect(new PotionEffect(ability, abilityDuration, abilityStrength)); break; case "MEDIC": // Add potion effect to nearby players for(Entity e : p.getNearbyEntities(medicHealRadius, medicHealRadius, medicHealRadius)) { if(!(e instanceof Player)) continue; // This entity is not a player, next! // Add potion effect to the target Player t = (Player) e; t.addPotionEffect(new PotionEffect(ability, abilityDuration, abilityStrength)); // Create some kind of effect to indicate that the target is being healed t.getWorld().playEffect(t.getLocation(), Effect.MOBSPAWNER_FLAMES, 0); // Flames! } break; } } } // Below are the usual stuff for running this plugin out-of-the-box. onEnable, join listener and so on. public void onEnable() { getServer().getPluginManager().registerEvents(this, this); // To avoid NPE's, you should also make sure everyone is attached to a kit when the plugin enables. // If not, you have to do != null checks whenever you fetch data from the hashmap, as // some players may not exist in it for(Player p : getServer().getOnlinePlayers()) { Kit k = Kit.MEDIC; players.put(p.getName(), k); // Assign some kit k.loadKit(p); // Load the gear from the kit } } @EventHandler public void onPlayerJoin(PlayerJoinEvent e) { // Add a kit to players who join in Kit k = Kit.MEDIC; // Everyone who joins becomes a medic, because medics are awesome Player p = e.getPlayer(); players.put(p.getName(), k); // Save data to hashmap k.loadKit(p); // Load the gear from the kit // Send a message informing everyone e.setJoinMessage(ChatColor.DARK_GREEN + p.getName() + " joined the game as a " + k.getName().toLowerCase() + "!\nKit description: " + k.getDesc()); } @EventHandler public void onPlayerQuit(PlayerQuitEvent e) { // Remove players that disconnect players.remove(e.getPlayer().getName()); } public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) { if(!(sender instanceof Player)) return true; // This stuff only works for players Player p = (Player) sender; players.get(p.getName()).useAbility(p); // Use special ability! return true; }} There are tons of ways to do this, and this may not be the best one - but it does kind of gather all your eggs into one basket, which is always a good idea when working with plugins like this. The core methods here are the useAbility() and loadKit() methods. By putting them into to enum itself, you won't have to put the kit specific ability code into the onCommand, and the loadKit() method into - well, whatever, basically. If you ever need to update or change anything, all the good stuff is in the same place. I've added methods to make this class runnable out-of-the-box, all you need is a plugin.yml with any command in it. When players join (and when the plugin is enabled) they get assigned the medic kit, which will give them an axe in hand and the ability to heal nearby players using a powerful rejuvenation effect. You can easily replace the mechanics here with a command or whatever, to let players choose kit for themselves. This is just a quick example. The useAbility() in the Kit enum is the most important method here, as it controls the behavior of the kits special ability. It works in the same way for scouts and spies, as they only apply the effect to themselves. The medic's mechanics are slightly different. In here you can add stuff like conditions and cooldowns. I usually avoid statics at all cost, so if I were to use this for myself, I would probably alter the way the kit's gear are stored - but again, I'm just trying to show off as many different approaches as possible. Like I said, there is no "correct" way with this stuff. For example, you could use multiple constructors, and just add the ItemStacks directly into the enum constants (that's probably how I would do it).
kiwhen Wow...I love people on the forums like you, who explain everything in such detail. There's just so much to focus on, wow. Well, I really appreciate the help. Just one thing, how does it execute the useAbility() method? kiwhen Hey, so I am working on this plugin, and I need help. I haven't yet implemented the HashMap yet, and I am still doing a pretty inefficient method of storing the items for the kits. I am trying to make it so you click a sign with specific text on it to select your kit. Also, I tried to make it so that if you didn't have permissions, you can't create a kit sign. Neither of these things work... You've been a load of help so far, so do you think you could help me with this? Code: Code: package me.Zach_1919.Main; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; public class Main extends JavaPlugin implements Listener { public void onEnable() { getServer().getPluginManager().registerEvents(this, this); } //CREATING SIGNS public void onBlockPlace(BlockPlaceEvent event) { Player placer = event.getPlayer(); Block placedblock = event.getBlockPlaced(); if(placedblock.getType().equals(Material.SIGN_POST)) { Sign placedsign = (Sign) placedblock; String line1 = placedsign.getLine(1); if(line1.equals("[PvPKits]") && !(placer.hasPermission("pvpkits.createsign"))) { placedsign.setType(Material.AIR); } } } //KITS public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { Player send = (Player) sender; if(commandLabel.equalsIgnoreCase("hg")) { if(args[0].equalsIgnoreCase("kits")) { send.sendMessage(ChatColor.GOLD + "HG Training Kits:"); send.sendMessage(ChatColor.WHITE + "- Wood"); send.sendMessage(ChatColor.WHITE + "- Stone"); send.sendMessage(ChatColor.WHITE + "- Iron"); send.sendMessage(ChatColor.WHITE + "- Full Iron"); send.sendMessage(ChatColor.WHITE + "- Diamond"); } } if(commandLabel.equalsIgnoreCase("kp")) { if(args[0].equalsIgnoreCase("kits")) { send.sendMessage(ChatColor.GOLD + "Kit PvP Kits:"); send.sendMessage(ChatColor.WHITE + "- Legit"); send.sendMessage(ChatColor.WHITE + "- Tank"); send.sendMessage(ChatColor.WHITE + "- Fairy"); send.sendMessage(ChatColor.WHITE + "- Rabbit"); send.sendMessage(ChatColor.WHITE + "- Archer"); } } return true; } //SELECTING KIT public void onInteract(PlayerInteractEvent event) { Player player = event.getPlayer(); Block block = event.getClickedBlock(); Action action = event.getAction(); if(action.equals(Action.RIGHT_CLICK_BLOCK) && block.getType().equals(Material.SIGN_POST)) { Sign sign = (Sign) block; String line1 = sign.getLine(1); String line2 = sign.getLine(2); String line3 = sign.getLine(3); //WOOD if(line1.equals("[PvPKits]") && line2.equals("HG Training") && line3.equals("Wood")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.WOOD_SWORD)); } //STONE if(line1.equals("[PvPKits]") && line2.equals("HG Training") && line3.equals("Stone")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.STONE_SWORD)); player.getInventory().setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE, 1)); } //IRON if(line1.equals("[PvPKits]") && line2.equals("HG Training") && line3.equals("Iron")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.IRON_SWORD)); player.getInventory().addItem(new ItemStack(Material.MUSHROOM_SOUP, 1)); player.getInventory().setChestplate(new ItemStack(Material.IRON_CHESTPLATE, 1)); } //FULL IRON if(line1.equals("[PvPKits]") && line2.equals("HG Training") && line3.equals("Full Iron")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.IRON_SWORD)); player.getInventory().setHelmet(new ItemStack(Material.IRON_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.IRON_BOOTS)); } //DIAMOND if(line1.equals("[PvPKits]") && line2.equals("HG Training") && line3.equals("Diamond")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.DIAMOND_SWORD)); player.getInventory().setHelmet(new ItemStack(Material.DIAMOND_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.DIAMOND_BOOTS)); } //LEGIT if(line1.equals("[PvPKits]") && line2.equals("Kit PvP") && line3.equals("Legit")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.DIAMOND_SWORD)); player.getInventory().setHelmet(new ItemStack(Material.IRON_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.IRON_BOOTS)); } //TANK if(line1.equals("[PvPKits]") && line2.equals("Kit PvP") && line3.equals("Tank")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.IRON_SWORD)); player.getInventory().setHelmet(new ItemStack(Material.DIAMOND_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.DIAMOND_BOOTS)); player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 10000000, 0)); } //FAIRY if(line1.equals("[PvPKits]") && line2.equals("Kit PvP") && line3.equals("Fairy")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.STONE_SWORD)); player.getInventory().setHelmet(new ItemStack(Material.GOLD_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.GOLD_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.CHAINMAIL_BOOTS)); player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 1)); } //RABIT if(line1.equals("[PvPKits]") && line2.equals("Kit PvP") && line3.equals("Rabbit")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.IRON_AXE)); player.getInventory().setHelmet(new ItemStack(Material.IRON_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.LEATHER_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.IRON_BOOTS)); player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 0)); player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 10000000, 1)); } //ARCHER if(line1.equals("[PvPKits]") && line2.equals("Kit PvP") && line3.equals("Archer")) { for(PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } player.getInventory().clear(); player.getInventory().setHelmet(new ItemStack(Material.AIR)); player.getInventory().setChestplate(new ItemStack(Material.AIR)); player.getInventory().setLeggings(new ItemStack(Material.AIR)); player.getInventory().setBoots(new ItemStack(Material.AIR)); player.getInventory().addItem(new ItemStack(Material.BOW)); player.getInventory().addItem(new ItemStack(Material.ARROW, 64)); player.getInventory().addItem(new ItemStack(Material.ARROW, 64)); player.getInventory().addItem(new ItemStack(Material.ARROW, 64)); player.getInventory().setHelmet(new ItemStack(Material.LEATHER_HELMET)); player.getInventory().setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE)); player.getInventory().setLeggings(new ItemStack(Material.LEATHER_LEGGINGS)); player.getInventory().setBoots(new ItemStack(Material.LEATHER_BOOTS)); player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 0)); player.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 10000000, 0)); } } } } EDIT by Moderator: merged posts, please use the edit button instead of double posting.
The useAbility() method is triggered in the onCommand(). Check out the second to last statement in the code; it grabs the kit from the hashmap, and runs the useAbility() method directly, using the player object as the argument. Your code is a bit greasy, I'll admit. I've made a few adjustments to make for an easier read: Code:java package me.Zach_1919.Main; import org.bukkit.ChatColor;import org.bukkit.Material;import org.bukkit.block.Sign;import org.bukkit.command.Command;import org.bukkit.command.CommandSender;import org.bukkit.entity.Player;import org.bukkit.event.EventHandler;import org.bukkit.event.Listener;import org.bukkit.event.block.Action;import org.bukkit.event.block.SignChangeEvent;import org.bukkit.event.player.PlayerInteractEvent;import org.bukkit.inventory.ItemStack;import org.bukkit.inventory.PlayerInventory;import org.bukkit.plugin.java.JavaPlugin;import org.bukkit.potion.PotionEffect;import org.bukkit.potion.PotionEffectType; public class Main extends JavaPlugin implements Listener { public void onEnable() { getServer().getPluginManager().registerEvents(this, this); } // CREATING SIGNS @EventHandler public void onSignChange(SignChangeEvent e) { Player p = e.getPlayer(); if(e.getLine(0).equalsIgnoreCase("[PvPKits]")) { if(!p.hasPermission("pvpkits.createsign")) { // Player does not have permission to create a kit-sign // Break the sign with an error message e.getBlock().breakNaturally(); p.sendMessage(ChatColor.RED + "Sorry dude, that's not gonna work."); } } } // KITS public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) { if(!(sender instanceof Player)) { // The command didn't come from a player. Error message here? return true; } Player p = (Player) sender; if(args.length == 0) { // No arguments were passed. Error message here? return true; } if(cmd.getName().equalsIgnoreCase("hg")) { if(args[0].equalsIgnoreCase("kits")) { p.sendMessage(ChatColor.GOLD + "HG Training Kits:\n" + ChatColor.WHITE + "- Wood\n" + "- Stone\n" + "- Iron\n" + "- Full Iron\n" + "- Diamond"); } } else if (cmd.getName().equalsIgnoreCase("kp")) { if (args[0].equalsIgnoreCase("kits")) { p.sendMessage(ChatColor.GOLD + "Kit PvP Kits:\n" + ChatColor.WHITE + "- Legit\n" + "- Tank\n" + "- Fairy\n" + "- Rabbit\n" + "- Archer"); } } return true; } // SELECTING KIT @EventHandler public void onPlayerInteract(PlayerInteractEvent e) { Player p = e.getPlayer(); if(e.getAction() != Action.RIGHT_CLICK_BLOCK) return; // Not a right-click on a block if(e.getClickedBlock().getType() != Material.SIGN_POST) return; // Not a sign post Sign s = (Sign) e.getClickedBlock().getState(); if(!s.getLine(0).equalsIgnoreCase("[PvPKits]")) return; // Line 1 is not correct // Grab inventory PlayerInventory i = p.getInventory(); // Remove all potion effects for(PotionEffect eff : p.getActivePotionEffects()) { p.removePotionEffect(eff.getType()); } if(s.getLine(1).equalsIgnoreCase("HG Training")) { // Training kits i.clear(); switch(s.getLine(2).toLowerCase()) { default: // It's good practice to have a "default" case. If something is wrong, this next kit will be chosen case "wood": i.addItem(new ItemStack(Material.WOOD_SWORD)); break; case "stone": i.addItem(new ItemStack(Material.STONE_SWORD)); i.setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE)); break; case "iron": i.addItem(new ItemStack(Material.IRON_SWORD)); i.addItem(new ItemStack(Material.MUSHROOM_SOUP)); i.setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); break; case "full iron": i.addItem(new ItemStack(Material.IRON_SWORD)); i.setHelmet(new ItemStack(Material.IRON_HELMET)); i.setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); i.setLeggings(new ItemStack(Material.IRON_LEGGINGS)); i.setBoots(new ItemStack(Material.IRON_BOOTS)); break; case "diamond": i.addItem(new ItemStack(Material.DIAMOND_SWORD)); i.setHelmet(new ItemStack(Material.DIAMOND_HELMET)); i.setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); i.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); i.setBoots(new ItemStack(Material.DIAMOND_BOOTS)); break; } } else if(s.getLine(1).equalsIgnoreCase("Kit PvP")) { // PvP kits i.clear(); switch(s.getLine(2).toLowerCase()) { default: // If something is wrong, this next kit will be chosen case "legit": i.addItem(new ItemStack(Material.DIAMOND_SWORD)); i.setHelmet(new ItemStack(Material.IRON_HELMET)); i.setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); i.setLeggings(new ItemStack(Material.IRON_LEGGINGS)); i.setBoots(new ItemStack(Material.IRON_BOOTS)); break; case "tank": i.addItem(new ItemStack(Material.IRON_SWORD)); i.setHelmet(new ItemStack(Material.DIAMOND_HELMET)); i.setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); i.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); i.setBoots(new ItemStack(Material.DIAMOND_BOOTS)); p.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 10000000, 0)); break; case "fairy": i.addItem(new ItemStack(Material.STONE_SWORD)); i.setHelmet(new ItemStack(Material.GOLD_HELMET)); i.setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); i.setLeggings(new ItemStack(Material.GOLD_LEGGINGS)); i.setBoots(new ItemStack(Material.CHAINMAIL_BOOTS)); p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 1)); break; case "rabbit": i.addItem(new ItemStack(Material.IRON_AXE)); i.setHelmet(new ItemStack(Material.IRON_HELMET)); i.setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE)); i.setLeggings(new ItemStack(Material.LEATHER_LEGGINGS)); i.setBoots(new ItemStack(Material.IRON_BOOTS)); p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 0)); p.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 10000000, 1)); break; case "archer": i.addItem(new ItemStack(Material.BOW)); i.addItem(new ItemStack(Material.ARROW, 64)); i.addItem(new ItemStack(Material.ARROW, 64)); i.addItem(new ItemStack(Material.ARROW, 64)); i.setHelmet(new ItemStack(Material.LEATHER_HELMET)); i.setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE)); i.setLeggings(new ItemStack(Material.LEATHER_LEGGINGS)); i.setBoots(new ItemStack(Material.LEATHER_BOOTS)); p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 10000000, 0)); p.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 10000000, 0)); break; } } p.updateInventory(); }} The main problem is that you simply forgot about the @EventHandler annotation on your event listeners. These must be in place, even if the listener is located in your main class. When working with signs, you also want to use the SignChangeEvent, because the BlockPlaceEvent is triggered when you right click with the sign. Ingame this action will bring up the sign GUI, and the text is stored when you hit okay. This is the action that trigges SignChangeEvent, and you will have access to the sign's contents from there. Last but not least, a few very common bloopers: Remember to check object types before casting. A CommandSender does not always have to be a Player (use "instanceof" to verify). Don't use the command alias to verify command names. If a command is registered with aliases, this will cause only the specific alias you have provided to work. Let's say you have a command called "message" with "m" as an alias. If you check for a command called "m" using the alias, the command "/message" won't work. Using the actual command name, everything works fine. In your code, this is done by using "cmd.getName().equals..." When checking multiple conditions on the same object, use else/if instead of just if/if. If the first conditions are met, there is no need to check the others, as they will be false. Less code to run = faster plugin. See line 63 in the code above. Remember to check the length of an array before acting on it. You don't know if there are any elements in "args" in your code, so if anyone just types the command (like "/hg") they will get an internal error displayed in the chat. I've put in an example where I check args.length for the required number of elements. Lines sent to the chat can be broken by sending the "\n" character. Check out line 56 and 65 in the code above. Alarmbells should ring if you end up copy/pasting large portions of code. It's never a good idea to repeat yourself, mostly because it turns into a nightmare the day you have to change a piece of code that exists in 500 separate locations. For example, in the code above, I've rigged the if-statements so that you only need to do the line1.equals("[PvPKits]") once. Sometimes it can also be useful to create a custom method for running a certain piece of code multiple times. When dealing with strings, try to use the equalsIgnoreCase() method over equals(), unless case-sensitivity really matters.
kiwhen Wow again thank you so much for the amazing detail. I really appreciate the time you put into fixing my code. One last thing though, in the enum code, you put the useAbility() method in the onCommand spot, but you didn't identify a cmd.getName() for the useAbility() method to go along with. Also, I know that my code was a but greasy, but is there anything in it that wouldn't work for sure?
No, I didn't. onCommand() is a pretty cool method. It adapts to it's environment, so to speak. If the onCommand is placed into your main class (which extends JavaPlugin), it will automatically handle all commands that you have registered in your plugin.yml file, that has not been assigned to a specific command executor. This means that if you do not use the getCommand() method to assign a specific command to an executor, it will be executed by the onCommand() method in your main class. If you don't have such a method, the command will simply not be executed at all. If you are using a separate executor (an onCommand() method that is not in your main class), the method will only trigger by commands that have been assigned to this specific executor via the getCommand() method. This means that if a command executor is only assigned to handle one single command, you do not have to check what command this is (using cmd.getName()). You will already know what command it is, because there can only be one. In my example, you can register any command you want into your plugin.yml file. My code does not assign any executors, which means that all the commands registered in the plugin.yml will be executed by the onCommand() method provided in the bottom of my code (because it's in the main class). This executor is only designed to do one task, which is to use the special ability. It doesn't really care what the command is, it just does it's thing when any command is issued. Sorry for doubleposting; but in answer to your last edit there, a few things must be addressed before your code will be runnable. By "runnable", I mean that it will compile, it will work - in its own way - but it will still cause some hiccups like NullPointerException-errors and the like. Must be fixed: In the PlayerInteractEvent, you are casting a block to a sign, which will cause a ClassCastException. You need to grab the sign state instead of the actual block. Just add the getState() method at the end of line 84. You need to add the @EventHandler annotation to the event listeners. The BlockPlaceEvent will not work for disabling signs with a certain content. (Use SignChangeEvent instead.) Warnings: You're using the wrong index numbers for the sign's text lines. Indexes starts a 0, which means that getLine(1) actually retrieves line number 2. This error will cause the if-statements to return false if your sign codes starts at the first line. When fixed, it should run the way it was designed to, but like I said; some exceptions will occur, like when a player types in "/hg" with no arguments. EDIT by Moderator: merged posts, please use the edit button instead of double posting.
kiwhen Alright, thanks! I realized the wring sign line thing when I saw your updated code for it, and that was a pretty big facepalm, but other than that I had no idea what to do. You have been so much help for me. You have taught me about HashMaps, enums, and you fixed my code! Thank you so much!
One last thing that I think I've forgot to mention, is that if you compile with a newer version of Bukkit, you'll probably get a deprecation warning for updateInventory(). This is not really a method that one is "supposed" to use, especially now that it is deprecated, but when you're throwing in a bunch of inventory editing like this, the client may sometimes loose track of all the changes, resulting in invisible items and invisible armor. The method just "refreshes" the client side to make sure that it can see all the items the server has placed there. I'm currently not aware of a better way of doing this.
kiwhen Oh and one thing, in the enum code, you use p as player in the loadKit() method. Where does the variable p come from? Do you have to set the commandSender to p in your other class if you want that to work?
The player is actually passed as an argument to the method. If you look at the code for loadKit(), you will see that it takes a Player (called "p") as an argument, and modifies this players inventory. Enums can have methods just like a class can. Bukkit uses this technique from time to time as well. For example, the Material-enum has a method called getMaterial(), which will return a Material enum based on the name of a material. You can do Code:java Material m = Material.getMaterial("log"); ... and so on. loadKit works in the same way. Instead of using a code that pulls the kit's inventory list and adds it to the player, I just send the player to the enum, and let that place the kit's inventory instead. This is just a matter of tidyness; it's much easier to have all the kit-codes in the same place. The loadKit() method fires in PlayerJoinEvent, which grabs the joining player and passes it to loadKit. Here is the section of code: Code:java @EventHandlerpublic void onPlayerJoin(PlayerJoinEvent e) { // Create a kit (medic in this case) Kit k = Kit.MEDIC; // Grab the player Player p = e.getPlayer(); // Pass the player to the loadKit() method, to add stuff to his/her's inventory k.loadKit(p);}
kiwhen Okay, so let me tell you what my specific case is. I am running a Factions server but we are using Multiverse to make a new world that we are going to use for a Kit PvP arena place and this is what I am using the plugin for. I would just load the items in their inventories as I have been doing, but I want them to have the special abilities like hitting people and giving them slowness. That is why I want the HashMap and the enum. Since I have a factions side of things going on in another world, I don't want to load a kit right away because it will clear the stuff that they have gotten from the factions part of things. Could I just make it so that it doesn't add the player to the HahMap until they click the sign?
Zach_1919 Use the PlayerInteractEvent and listen for a right-click of a sign with the text you want on it, and then add that player to the HashMap.
devilquak I get that part, but since I am also running a factions thing in another world, I want to remove them from the HashMap when they're not in KitPvP. I am not sure what I would do for this. kiwhen Well, it's not complete, because I want it to remove their name from the HashMap on death, but it still isn't working. I don't know if it's the PlayerInteractEvent or the enum that I'm messing up on... Main: Code: package me.Zach_1919.Main; import java.util.HashMap; import java.util.Map; import me.Zach_1919.Main.Enumerator.Kit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Sign; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.plugin.java.JavaPlugin; public class Main extends JavaPlugin implements Listener { public Map<String, Kit> playerkit = new HashMap<String, Kit>(); public void onEnable() { getServer().getPluginManager().registerEvents(this, this); } @EventHandler public void onPlayerQuit(PlayerJoinEvent event) { playerkit.remove(event.getPlayer().getName()); } @EventHandler public void onSignChange(SignChangeEvent event) { Player placer = event.getPlayer(); String line0 = event.getLine(0); if(line0.equals("[PvPKits]") && !(placer.hasPermission("pvpkits.createsign"))) { event.getBlock().breakNaturally(); } } public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { Player send = (Player) sender; if(commandLabel.equalsIgnoreCase("hg")) { if(args[0].equalsIgnoreCase("kits")) { send.sendMessage(ChatColor.GOLD + "HG Training Kits:"); send.sendMessage(ChatColor.WHITE + "- Wood"); send.sendMessage(ChatColor.WHITE + "- Stone"); send.sendMessage(ChatColor.WHITE + "- Iron"); send.sendMessage(ChatColor.WHITE + "- Full Iron"); send.sendMessage(ChatColor.WHITE + "- Diamond"); } } if(commandLabel.equalsIgnoreCase("kp")) { if(args[0].equalsIgnoreCase("kits")) { send.sendMessage(ChatColor.GOLD + "Kit PvP Kits:"); send.sendMessage(ChatColor.WHITE + "- Legit"); send.sendMessage(ChatColor.WHITE + "- Tank"); send.sendMessage(ChatColor.WHITE + "- Fairy"); send.sendMessage(ChatColor.WHITE + "- Rabbit"); send.sendMessage(ChatColor.WHITE + "- Archer"); } } if(commandLabel.equalsIgnoreCase("kitinfo")) { if(playerkit.containsKey(send.getName())) { send.sendMessage(ChatColor.BLUE + "Current Kit Information"); send.sendMessage(ChatColor.GOLD + "Kit Name: " + ChatColor.WHITE + playerkit.get(send.getName()).getKitName()); send.sendMessage(ChatColor.GOLD + "Kit Description: " + ChatColor.WHITE + playerkit.get(send.getName()).getKitDesc()); } else { send.sendMessage(ChatColor.RED + "You do not currently have any kit selected."); } } return true; } @EventHandler public void onInteract(PlayerInteractEvent event) { if(event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { if(event.getClickedBlock().getType().equals(Material.SIGN_POST)) { Sign sign = (Sign) event.getClickedBlock().getState(); if(sign.getLine(0).equalsIgnoreCase("[PvPKits]")) { switch(sign.getLine(2).toUpperCase()) { case "WOOD": playerkit.put(event.getPlayer().getName(), Kit.WOOD); Kit.WOOD.loadKit(event.getPlayer()); break; case "STONE": playerkit.put(event.getPlayer().getName(), Kit.STONE); Kit.STONE.loadKit(event.getPlayer()); break; case "IRON": playerkit.put(event.getPlayer().getName(), Kit.IRON); Kit.IRON.loadKit(event.getPlayer()); break; case "FULLIRON": playerkit.put(event.getPlayer().getName(), Kit.FULLIRON); Kit.FULLIRON.loadKit(event.getPlayer()); break; case "DIAMOND": playerkit.put(event.getPlayer().getName(), Kit.DIAMOND); Kit.DIAMOND.loadKit(event.getPlayer()); break; case "LEGIT": playerkit.put(event.getPlayer().getName(), Kit.LEGIT); Kit.LEGIT.loadKit(event.getPlayer()); break; case "TANK": playerkit.put(event.getPlayer().getName(), Kit.TANK); Kit.TANK.useAbility(event.getPlayer()); Kit.TANK.loadKit(event.getPlayer()); break; case "FAIRY": playerkit.put(event.getPlayer().getName(), Kit.FAIRY); Kit.FAIRY.useAbility(event.getPlayer()); Kit.FAIRY.loadKit(event.getPlayer()); break; case "RABBIT": playerkit.put(event.getPlayer().getName(), Kit.RABBIT); Kit.RABBIT.useAbility(event.getPlayer()); Kit.RABBIT.loadKit(event.getPlayer()); break; case "ARCHER": playerkit.put(event.getPlayer().getName(), Kit.ARCHER); Kit.ARCHER.useAbility(event.getPlayer()); Kit.ARCHER.loadKit(event.getPlayer()); break; } } } } } } Enum: Code: package me.Zach_1919.Main; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; public class Enumerator { private static ItemStack[] hgWood = {new ItemStack(Material.WOOD_SWORD)}; private static ItemStack[] hgStone = {new ItemStack(Material.STONE_SWORD)}; private static ItemStack[] hgIron = {new ItemStack(Material.IRON_SWORD)}; private static ItemStack[] hgFullIron = {new ItemStack(Material.IRON_SWORD)}; private static ItemStack[] hgDiamond = {new ItemStack(Material.DIAMOND_SWORD)}; private static ItemStack[] kpLegit = {new ItemStack(Material.DIAMOND_SWORD)}; private static ItemStack[] kpTank = {new ItemStack(Material.IRON_SWORD)}; private static ItemStack[] kpFairy = {new ItemStack(Material.STONE_SWORD)}; private static ItemStack[] kpRabbit = {new ItemStack(Material.STONE_SWORD)}; private static ItemStack[] kpArcher = {new ItemStack(Material.BOW), new ItemStack(Material.ARROW, 192)}; private static PotionEffectType kpeTank = PotionEffectType.SLOW; private static PotionEffectType kpeFairy = PotionEffectType.SPEED; private static PotionEffectType kpeRabbit1 = PotionEffectType.SPEED; private static PotionEffectType kpeRabbit2 = PotionEffectType.JUMP; private static PotionEffectType kpeArcher = PotionEffectType.SPEED; public enum Kit { WOOD ("Wood", "Wood sword and no armor", hgWood, null, null), STONE ("Stone", "Wood sword and a leather chestplate", hgStone, null, null), IRON ("Iron", "Wood sword and an iron chestplate", hgIron, null, null), FULLIRON ("Full Iron", "Wood sword and a full iron armor", hgFullIron, null, null), DIAMOND ("Diamond", "Diamond sword and full diamond armor", hgDiamond, null, null), LEGIT ("Legit", "Diamond sword and full iron armor", kpLegit, null, null), TANK ("Tank", "Iron sword and full diamond armor", kpTank, kpeTank, null), FAIRY ("Fairy", "Stone sword, gold helmet and leggings, and chain chestplate and boots", kpFairy, kpeFairy, null), RABBIT ("Rabbit", "Iron axe, iron helmet and boots, and leather chestplate and leggings", kpRabbit, kpeRabbit1, kpeRabbit2), ARCHER ("Archer", "Bow and full leather armor", kpArcher, kpeArcher, null); private String kitName; private String kitDesc; private ItemStack[] gear; private PotionEffectType peffect1; private PotionEffectType peffect2; Kit(String kitName, String kitDesc, ItemStack[] gear, PotionEffectType peffect1, PotionEffectType peffect2) { this.kitName = kitName; this.kitDesc = kitDesc; this.gear = gear; this.peffect1 = peffect1; this.peffect2 = peffect2; } public String getKitName() { return kitName; } public String getKitDesc() { return kitDesc; } public void loadKit(Player player) { player.getInventory().clear(); for(ItemStack i : gear) { player.getInventory().addItem(i); } } public void useAbility(Player player) { switch(kitName.toUpperCase()) { case "TANK": case "ARCHER": player.addPotionEffect(new PotionEffect(peffect1, 10000000, 0)); break; case "FAIRY": player.addPotionEffect(new PotionEffect(peffect1, 10000000, 1)); break; case "RABBIT": player.addPotionEffect(new PotionEffect(peffect1, 10000000, 0)); player.addPotionEffect(new PotionEffect(peffect2, 10000000, 1)); break; } } } } EDIT by Moderator: merged posts, please use the edit button instead of double posting.
It's probably because you are using the PlayerJoinEvent instead of the PlayerQuitEvent. You've only changed the name of the method to onPlayerQuit, and that doesn't change the event it actually listens for. I see you've put the enum into a seperate class now. This being the case it would probably be less messy if you just use the class itself to hold the kit information, and just drop enums all together. In this case there is nothing the enum can do that a class can't, so it's just not necessary to wrap the kit-methods into an enum that's also wrapped in a class. Performance-wise it won't make much difference, it's just a more common way of doing things. Also, your code still have all of the issues I addressed earlier on: