canEnchantItem

Discussion in 'Plugin Development' started by mydeblob, Apr 2, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    mydeblob

    Hi,
    For some reason I keep getting an NPE on line 42 in my code which is using the bukkit method canEnchantItem(ItemStack)
    Here is my code
    Code:java
    1. public void enchant(Enchantment ench, int power, PlayerInventory pi, int price, Player p){
    2. for(ItemStack is:pi.getContents()){
    3. if(is == null) continue; //If the itemstack is null it's going to keep looping
    4. if(ench.canEnchantItem(is)){
    5. if(power > ench.getMaxLevel()){
    6. p.sendMessage(prefix + ChatColor.RED + "You've already enchanted your items with " + ench.toString().toLowerCase().replaceAll("_", " ") + " to the max!");
    7. return;
    8. }else{
    9. for(ItemStack i:pi.getContents()){
    10. i.addEnchantment(ench, power);
    11. }
    12. plugin.econ.withdrawPlayer(p.getName(), price);
    13. p.sendMessage(prefix + ChatColor.GREEN + "Succesfully enchanted your items with " + ench.toString().toLowerCase().replaceAll("_", " ") + " for " + price + "!");
    14. return;
    15. }
    16. }
    17.  
    18. }
    19. for(ItemStack is:pi.getArmorContents()){
    20. if(is == null) continue;
    21. if(ench.canEnchantItem(is)){ //NPE ON THIS LINE
    22. if(power > ench.getMaxLevel()){
    23. p.sendMessage(prefix + ChatColor.RED + "You've already enchanted your items with " + ench.toString().toLowerCase().replaceAll("_", " ") + " to the max!");
    24. return;
    25. }else{
    26. for(ItemStack i:pi.getContents()){
    27. i.addEnchantment(ench, power);
    28. }
    29. plugin.econ.withdrawPlayer(p.getName(), price);
    30. p.sendMessage(prefix + ChatColor.GREEN + "Succesfully enchanted your items with " + ench.toString().toLowerCase().replaceAll("_", " ") + " for " + price + "!");
    31. return;
    32. }
    33. }
    34. }
    35. p.sendMessage(prefix + ChatColor.RED + "You have nothing in your inventory that can be enchanted with " + ench.toString().toLowerCase().replaceAll("_", " ") + "!");
    36. }


    Stacktrace:
    Code:
    Caused by: java.lang.NullPointerException
        at net.minecraft.server.v1_7_R2.EnchantmentWeaponDamage.canEnchant(SourceFile:78) 
        at org.bukkit.craftbukkit.v1_7_R2.enchantments.CraftEnchantment.canEnchantItem(CraftEnchantment.java:57) 
        at org.bukkit.enchantments.EnchantmentWrapper.canEnchantItem(EnchantmentWrapper.java:46)
        at com.mydeblob.commands.CommandHandler.enchant(CommandHandler.java:42) 
        at com.mydeblob.commands.CommandHandler.onCommand(CommandHandler.java:87)
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:50)
        ... 13 more
    I'm calling the method in a command.
     
  2. Offline

    PogoStick29

    Can I see the line where you call this method?
     
  3. Offline

    mydeblob

    PogoStick29
    Sure.
    Command that uses enchant();
    Code:java
    1. if(cmd.getName().equalsIgnoreCase("sharpness")){
    2. enchant(Enchantment.DAMAGE_ALL, this.getEnchLevel(p, Enchantment.DAMAGE_ALL) + 1, p.getInventory(), this.getEnchPrice(p, Enchantment.DAMAGE_ALL, "sharpness"), p);
    3. return true;
    4. }

    This command uses 2 other methods, getEnchLevel and getEnchPrice. The getEnchLevel is simply returning the next possible enchantment level of the item. It can be seen here
    getEnchLevel method:
    Code:java
    1. public int getEnchLevel(Player p, Enchantment ench){
    2. PlayerInventory pi = p.getInventory();
    3. for(ItemStack is:pi.getContents()){
    4. if(is != null && is.containsEnchantment(ench)){
    5. return is.getEnchantmentLevel(ench);
    6. }
    7. }
    8. for(ItemStack is:pi.getArmorContents()){
    9. if(is != null && is.containsEnchantment(ench)){
    10. return is.getEnchantmentLevel(ench);
    11. }
    12. }
    13. return 0;
    14. }

    The getEnchPrice just fetches the config.yml for a configurable price for the enchantment.
    Code:java
    1. public int getEnchPrice(Player p, Enchantment ench, String s){
    2. String path;
    3. if(getEnchLevel(p, ench) == 0){
    4. path = s + 1;
    5. return plugin.getConfig().getInt(path);
    6. }else{
    7. return plugin.getConfig().getInt(s + getEnchLevel(p, ench));
    8. }
    9. }


    Keep in mind everything is one up. For example, if I have sharpness 1 on a sword getEnchLevel is going to return sharpness 2. And getEnchPrice is going to return the price for sharpness 2.
     
  4. Offline

    PogoStick29

    Seems like the only thing that could possibly be null is the return for getEnchPrice(). Print out the result of that before you call the enchant() method and tell me if it's null.
     
  5. Offline

    mydeblob

    PogoStick29
    Ok. So I added this line of code
    Code:
            p.sendMessage("Enchant price" + this.getEnchPrice(p, Enchantment.DAMAGE_ALL, "sharpness"));
    It did indeed return the correct price, which is 10.
    This is the config.yml
    Code:
    #This is the config for the amount of money each enchantment upgrade costs
    sharpness1: 10
    sharpness2: 10
    sharpness3: 10
    sharpness4: 10
    sharpness5: 10
    protection1: 10
    protection2: 10
    protection3: 10
    protection4: 10
    power1: 10
    power2: 10
    power3: 10
    power4: 10
    power5: 10
    speed1: 10
    speed2: 10
    strength1: 10
    strength2: 10
     
  6. Offline

    PogoStick29

    Strange. I can't really tell what's null. You do have null checks in the loop.
     
  7. Offline

    itzrobotix

    I'm pretty sure my stacktraces aren't that small, is that all of it? There should be somewhere stating the class and line that caused it.
     
  8. Offline

    PogoStick29

    itzrobotix at com.mydeblob.commands.CommandHandler.enchant(CommandHandler.java:42) = CommandHandler line 42. I know what you mean about stack traces from Bukkit being longer, but this is the important part.
     
    itzrobotix and mydeblob like this.
  9. Offline

    mydeblob

    I didn't post the full stacktrace. Just the relevant part. I'll just perform some more bug testing and try and fine the specific problem. Thanks for the help so far.
     
  10. Offline

    Garris0n

    Sometimes the entire thing is relevant.

    It might be the fact that, for no apparent reason, getArmorContents returns air ItemStacks instead of null for empty slots. Try returning(er...continuing) if the type of the item is air.
     
    PogoStick29 and mydeblob like this.
  11. Offline

    mydeblob

    I suppose the entire stacktrace is relevant. That's a bad habit of mine, (Only focusing on a small portion of the stacktrace) so I will work on improving this.

    Anyhow, that happened to work! For some reason, getArmorConetents returns the type of AIR if the slot is empty. I guess I just assumed it would be null, since getContents is null. Thanks for the help!
     
  12. Offline

    Garris0n

    Yeah, I have no idea why it does that. Noticed it like last week, actually :p
     
Thread Status:
Not open for further replies.

Share This Page