NullPointerException help

Discussion in 'Plugin Development' started by wesley27, Aug 23, 2014.

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

    wesley27

    Hello, I'm working on a plugin that hooks into Acrobot's ChestShop, and I'm getting this NPE that I cannot for the life of me figure out why.. I think I'm missing something simple or there's some other error.

    The plugin basically lightly tracks every item in the game with a set of lores, for staffing and maintenance reasons. The way for it to be compatible while having a plugin like ChestShop, I need to remove the lore from the item when a player tries to use a ChestShop, then re-add the lore after the transaction is complete. Below is the code that should remove the lore. I'm not sure why this NPE is occurring, it is marked in the code below:

    Code:java
    1. @EventHandler(priority = EventPriority.LOWEST)
    2. public void onPreChestShopUse(PreTransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = Odd.getFromString(shopitem);
    6. if(event.isCancelled()) return;
    7.  
    8. if(event.getTransactionType() == TransactionType.SELL){
    9. if (item.getItemMeta() == null) { //NPE is occurring on this line
    10. item.setItemMeta(Main.getItemMeta(player, true));
    11.  
    12. if(player.getInventory().contains(item)){
    13. item.getItemMeta().setLore(null);
    14. }
    15. }
    16. }
    17. }

    Any help is appreciated, although I'd assume that this would be best answered by Acrobot because it hooks into various parts of his plugin.

    Thanks!
     
  2. Offline

    mine-care

    Item.hasitemmeta befor dat
     
  3. Offline

    wesley27

    mine-care I thought of that, but didn't think it would make much of a difference. Turns out, that doesn't do anything, just the NPE occurs on that line instead of the line it did in my code above. I mean, that makes sense considering the NPE stops the event before it gets to the line in the above code, but that's besides the point :p

    Anyhow, here's the new code, I commented where the NPE is.
    Code:java
    1. @EventHandler(priority = EventPriority.LOWEST)
    2. public void onPreChestShopUse(PreTransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = Odd.getFromString(shopitem);
    6. if(event.isCancelled()) return;
    7.  
    8. if(event.getTransactionType() == TransactionType.SELL){
    9. if(!item.hasItemMeta()){ //NPE is here
    10. if (item.getItemMeta() == null) {
    11. item.setItemMeta(Main.getItemMeta(player, true));
    12.  
    13. if(player.getInventory().contains(item)){
    14. item.getItemMeta().setLore(null);
    15. }
    16. }
    17. }
    18. }
    19. }
     
  4. Offline

    excusemyluck

    wesley27 To me it looks like the item is null. Throw in a check to see if the item is null before you interact with the item variable
     
  5. Offline

    Acrobot

    mine-care likes this.
  6. Offline

    mine-care

    Acrobot is right...
    Just realized that, I was pointed only on the line of the npe
     
  7. Offline

    wesley27

    Acrobot mine-care I was formerly using MaterialUtil.getItem(), however that didn't work for me because of what I'm trying to/need to do(or it just didn't work?). I tried at least 10 different ways of doing the same thing with the code using MaterialUtil.getItem(), trying to add the itemmeta from my main class, checking if the players inventory has that item, and removing the lore if they do so that it sells to the shop. Nothing worked, so I hunted through ChestShop's code for another way to get the item off the sign. Here's that code:
    Code:java
    1. @EventHandler(priority = EventPriority.LOWEST)
    2. public void onPreChestShopUse(PreTransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = MaterialUtil.getItem(shopitem);
    6. if(event.isCancelled()) return;
    7.  
    8. if(event.getTransactionType() == TransactionType.SELL){
    9. System.out.println("[ItemTracker] It's getting to after the if type.sell");//code doesn't go any farther than this
    10. if (item.getItemMeta() == null) {
    11. System.out.println("[ItemTracker] It's getting to after the if itemmeta is null");
    12. item.setItemMeta(Main.getItemMeta(player, true));
    13.  
    14. if(player.getInventory().contains(item)){
    15. System.out.println("[ItemTracker] It's getting to after the if player inv contains item");
    16. item.getItemMeta().setLore(null);
    17. }
    18. }
    19. }
    20. }

    As you can see, I have had debug messages in there just so I can see where it is stopping. The only message I get in the console is the "It's getting to after the if type.sell" like I've marked above. I tried many ways of doing this, and nothing worked. I'm sure it's because the next if statement is returning false, but I don't know why it is returning false. Since a plain item pulled off a sign should not have any meta data. Any ideas?
     
  8. Offline

    Acrobot

    wesley27
    This probably means that the item has metadata after all - have you tried debugging in a way other than println's? There are two possibilities, and I'm unsure at the moment if one is true:
    - maybe a valid ItemStack always contains item metadata, although it might just be an empty map (I haven't tested it)
    - or the item you are trying to get from the sign indeed has metadata encoded. ChestShop automatically reads metadata from item codes that have a pound sign (#) and a base-62 encoded string afterwards (for example, Diamond Sword#a5).
     
  9. Offline

    wesley27

    Acrobot Well since the first possibility sort of fits in to the second, the second seems like it would be the issue. So in order fix that, instead of checking if the item.getitemmeta is null, I would have to check if it isn't null, then remove it, then add my metadata?

    I will try this, thanks

    Okay sweet, thanks! Working around that idea fixed it, and it's now working, removing the lore and selling an item. I also thought of(after all this time) the simple, much easier way to check if the item is in the inventory. So it's working, however I'm still getting an NPE. I'm glad it works, but obviously as would anyone, I'd prefer to not have the NPE coming up. Can anyone think of/help with a simple way to fix that?
    Code:java
    1. @EventHandler(priority = EventPriority.LOWEST)
    2. public void onPreChestShopUse(PreTransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = MaterialUtil.getItem(shopitem);
    6. if(event.isCancelled()) return;
    7.  
    8. if(event.getTransactionType() == TransactionType.SELL){
    9. if(player.getInventory().contains(item.getType())){
    10. for(ItemStack invitem : player.getInventory().getContents()){
    11. if(invitem.getType().equals(item.getType())){ //NPE is here
    12. if(!invitem.getItemMeta().getLore().get(0).contains("Spawned")){
    13. invitem.setItemMeta(null);
    14. }
    15. }
    16. }
    17. }
    18. }
    19. }

    That's the event now, after I've fixed it and it works. The NPE is on line 11, as commented. I could fix it by using the getItemMeta() to check and change the item in the players inventory, like I had been in the code I posted earlier. This would work and it'd be error free, but it is a lot and not really convenient.

    Can anyone help with a more convenient/simple way to rid of the NPE?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 9, 2016
  10. Offline

    Acrobot

    wesley27
    Well, IIRC, player.getInventory().getContents() returns nulls for empty item slots.
     
  11. Offline

    wesley27

    Acrobot So then there isn't a way to stop the NPE at all? I tried checking if(invitem != null) but that didn't do anything.

    And sadly, I have another NPE in the new code using your post transaction event(TransactionEvent).

    Like I said earlier, the plugin has to remove the lores to enable using the chestshop, and then once the transaction is complete it needs to re-add the lores to the items in the chest and/or player inventory.
    Code:java
    1. @EventHandler(priority = EventPriority.HIGHEST)
    2. public void onPostChestShopUse(TransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = MaterialUtil.getItem(shopitem);
    6.  
    7. if(event.getTransactionType() == TransactionType.SELL){
    8. if(player.getInventory().contains(item.getType())){
    9. for(ItemStack invitem : player.getInventory().getContents()){
    10. if(invitem.getType().equals(item.getType())){
    11. if(!invitem.getItemMeta().getLore().get(0).contains("Spawned")){ //NPE is here
    12. invitem.setItemMeta(Main.getItemMeta(player, true));
    13. }
    14. }
    15. }
    16. }
    17. if(event.getOwnerInventory().contains(item.getType())){
    18. for(ItemStack chestitem : event.getOwnerInventory().getContents()){
    19. if(chestitem.getType().equals(item.getType())){
    20. if(!chestitem.getItemMeta().getLore().get(0).contains("Spawned")){
    21. chestitem.setItemMeta(Main.getItemMeta(player, true));
    22. }
    23. }
    24. }
    25. }
    26. }
    27. }

    The NPE is occurring on line 11 of that. It's the same code as used in the earlier method that works fine.. any ideas?
     
  12. Offline

    Acrobot

  13. Offline

    Gater12

    wesley27
    Lore can be null. Check hasLore first
     
  14. Offline

    wesley27

    Acrobot thanks, that helps! And thank you Gater12 doing that now adds the lore back onto one of the stacks leftover in my inventory. However, if there is more than one stack of the item leftover in my inventory, it's only re-adding the lore back to one stack. This leaves some without the lore, which is a problem, any idea why?
    Code:java
    1. @EventHandler(priority = EventPriority.HIGHEST)
    2. public void onPostChestShopUse(TransactionEvent event){
    3. Player player = event.getClient();
    4. String shopitem = event.getSign().getLine(3);
    5. ItemStack item = MaterialUtil.getItem(shopitem);
    6.  
    7. if(event.getTransactionType() == TransactionType.SELL){
    8. if(player.getInventory().contains(item.getType())){ //re-adds legit lore to leftover of same item in player inventory
    9. for(ItemStack invitem : player.getInventory().getContents()){
    10. if(invitem.getType().equals(item.getType())){
    11. if(!invitem.getItemMeta().hasLore() || !invitem.getItemMeta().getLore().get(0).contains("Spawned")) {
    12. invitem.setItemMeta(Main.getItemMeta(player, true));
    13. }
    14. }
    15. }
    16. }
    17. if(event.getOwnerInventory().contains(item.getType())){ //re-adds legit lore to items now inside chestshop
    18. for(ItemStack chestitem : event.getOwnerInventory().getContents()){
    19. if(chestitem.getType().equals(item.getType())){
    20. if(!chestitem.getItemMeta().getLore().get(0).contains("Spawned")){
    21. chestitem.setItemMeta(Main.getItemMeta(player, true));
    22. }
    23. }
    24. }
    25. }
    26. }
    27. }


    And another quick q for Acrobot (I am sorry to keep bothering you :/): The second part of my event above is supposed to re-add the lores to the items that were just put into the chest during the sell event. It isn't doing anything at all. Is getOwnerInventory() the correct call to get the items in the chestshop?
     
  15. Offline

    Acrobot

    wesley27
    I'm not sure, but you will probably need a higher priority of your event, as the item adding part also occurs during the TransactionEvent.
     
Thread Status:
Not open for further replies.

Share This Page