(New to Bukkit/Java) Simple NPE Error

Discussion in 'Plugin Development' started by iKanak, Apr 25, 2012.

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

    iKanak

    I know this bug must be simple, because when I move the code out of my event listener classes, and just put all the code in my bind class it works. I know this means that the types of some of my variables must be wrong, but I don't know what it needs to be.

    1st NPE: at me.iKanak.EventListener.PlayerDeath.onPlayerDeath(PlayerDeath.java:32)

    2nd NPE: at me.iKanak.EventListener.PlayerRespawn.onPlayerRespawn(PlayerRespawn.java:30)

    Main Class (HavocBind) Package: me.iKanak.EventListener
    Show Spoiler

    Code:Java
    1.  
    2. package me.iKanak.HavocBind;
    3.  
    4. import java.util.logging.Logger;
    5.  
    6. import me.iKanak.EventListener.PlayerDeath;
    7. import me.iKanak.EventListener.PlayerRespawn;
    8.  
    9. import org.bukkit.ChatColor;
    10. import org.bukkit.command.Command;
    11. import org.bukkit.command.CommandSender;
    12. import org.bukkit.entity.Player;
    13. import org.bukkit.plugin.PluginDescriptionFile;
    14. import org.bukkit.plugin.PluginManager;
    15. import org.bukkit.plugin.java.JavaPlugin;
    16.  
    17. public class HavocBind extends JavaPlugin {
    18.  
    19. public final Logger logger = Logger.getLogger("Minecraft");
    20. public final Bind bind = new Bind(this);
    21. public final PlayerDeath playerDeath = new PlayerDeath(this);
    22. public final PlayerRespawn playerRespawn = new PlayerRespawn(this);
    23. public boolean debugging = true;
    24.  
    25. public void onDisable () {
    26. PluginDescriptionFile pdfFile = this.getDescription();
    27. this.logger.info(pdfFile.getName() + " is now disabled!");
    28. }
    29.  
    30. public void onEnable () {
    31. PluginManager pm = getServer().getPluginManager();
    32. pm.registerEvents(this.playerDeath, this);
    33. pm.registerEvents(this.playerRespawn, this);
    34. PluginDescriptionFile pdfFile = this.getDescription();
    35. this.logger.info(pdfFile.getName() + " is now enabled!");
    36. }
    37.  
    38. public void debug (String debugMessage) {
    39. if (debugging) {
    40. this.logger.info(debugMessage);
    41. }
    42. }
    43.  
    44. public boolean onCommand (CommandSender sender, Command cmd, String commandLabel, String[] args) {
    45. if (sender instanceof Player) {
    46. Player player = (Player) sender;
    47. if (cmd.getName().equalsIgnoreCase("bind")) {
    48. bind.bind(player, bind.firstUnbound(player));
    49. }
    50. if (cmd.getName().equalsIgnoreCase("unbind")) {
    51. if (args.length > 0) {
    52. try {
    53. int slotNum = Integer.parseInt(args[0]);
    54. bind.unbind(player, slotNum);
    55. } catch (Exception e) {
    56. sender.sendMessage(ChatColor.RED + "You must choose which slot to unbind! Use: /unbind <slot>");
    57. }
    58. } else {
    59. bind.unbind(player, 0);
    60. }
    61. }
    62. if (cmd.getName().equalsIgnoreCase("bound")) {
    63. bind.listBound(player);
    64. }
    65. return true;
    66. }
    67. return false;
    68. }
    69.  
    70. }
    71.  



    Bind Class; Pack
    Show Spoiler

    Code:Java
    1.  
    2. package me.iKanak.HavocBind;
    3.  
    4. import java.util.HashMap;
    5.  
    6. import org.bukkit.ChatColor;
    7. import org.bukkit.Material;
    8. import org.bukkit.entity.Player;
    9. import org.bukkit.inventory.ItemStack;
    10.  
    11. public class Bind {
    12.  
    13. public static HavocBind plugin;
    14. public final HashMap<Player, ItemStack> slot1 = new HashMap<Player, ItemStack>();
    15. public final HashMap<Player, ItemStack> slot2 = new HashMap<Player, ItemStack>();
    16. public final HashMap<Player, ItemStack> slot3 = new HashMap<Player, ItemStack>();
    17. public final HashMap<Player, ItemStack> slot4 = new HashMap<Player, ItemStack>();
    18. public final HashMap<Player, ItemStack> slot5 = new HashMap<Player, ItemStack>();
    19. public final HashMap<Player, ItemStack> slot6 = new HashMap<Player, ItemStack>();
    20. public final HashMap<Player, ItemStack> slot7 = new HashMap<Player, ItemStack>();
    21. public final HashMap<Player, ItemStack> slot8 = new HashMap<Player, ItemStack>();
    22. public final HashMap<Player, ItemStack> slot9 = new HashMap<Player, ItemStack>();
    23. public final HashMap<Player, ItemStack> slot10 = new HashMap<Player, ItemStack>();
    24.  
    25. public Bind (HavocBind instance) {
    26. plugin = instance;
    27. }
    28.  
    29. public void bind (Player player, Integer slotNum) {
    30. ItemStack item = player.getItemInHand();
    31. Material material = item.getType();
    32. String materialName = material.toString();
    33. String number = null;
    34. plugin.debug(materialName(item) + " is trying to be bound.");
    35. if (allowed(item)) {
    36. if (!(itemBound(player, item))) {
    37. if (allowBind(player, slotNum)) {
    38. plugin.debug(materialName(item) + " has been bound.");
    39. slot(slotNum).put(player, item);
    40. number = ordinalNum(slotNum);
    41. } else {
    42. player.sendMessage(ChatColor.RED + "Your soul is not strong enough to bind any more!");
    43. player.sendMessage(ChatColor.RED + "Try using /unbind <slot> to make room for more bindings.");
    44. }
    45. } else {
    46. player.sendMessage(ChatColor.RED + "That " + ChatColor.GOLD + materialName + ChatColor.RED + " is already bound to your soul!!");
    47. }
    48. } else {
    49. player.sendMessage(ChatColor.RED + "Only tools, weapons, and armour pieces can be bound to your soul!");
    50. }
    51. if (number != null) {
    52. player.sendMessage(ChatColor.YELLOW + "Your " + ChatColor.GOLD + materialName + ChatColor.YELLOW + " has been bound to your " + ChatColor.GOLD + number + ChatColor.YELLOW + " slot.");
    53. }
    54. }
    55.  
    56. public void unbind (Player player, Integer slotNum) {
    57. ItemStack item = player.getItemInHand();
    58. Material material = item.getType();
    59. String materialName = material.toString();
    60. String itemName = null;
    61. String number = null;
    62. plugin.debug(materialName + " is trying to be unbound.");
    63. if (slotNumBound(player, slotNum) || slotNum == 0) {
    64. if (slotNum == 0) {
    65. if (itemBoundSlot(player, item) != null) {
    66. plugin.debug(materialName(item) + " (in-hand) has been unbound.");
    67. itemBoundSlot(player, item).remove(player);
    68. player.sendMessage(ChatColor.YELLOW + "Your " + ChatColor.GOLD + materialName + ChatColor.YELLOW + " has been unbound from your soul.");
    69. } else {
    70. player.sendMessage(ChatColor.RED + "That " + ChatColor.GOLD + materialName + ChatColor.RED + " isn't bound to your soul!");
    71. }
    72. } else {
    73. itemName = materialName(slot(slotNum).get(player));
    74. number = ordinalNum(slotNum);
    75. slot(slotNum).remove(player);
    76. plugin.debug(itemName + " in the " + number + " slot has been unbound.");
    77. player.sendMessage(ChatColor.YELLOW + "Your " + ChatColor.GOLD + itemName + ChatColor.YELLOW + " has been unbound from your " + ChatColor.GOLD + number + ChatColor.YELLOW + " slot.");
    78. }
    79. } else {
    80. player.sendMessage(ChatColor.RED + "Nothing is bound to that slot!");
    81. }
    82. }
    83.  
    84. public void listBound (Player player) {
    85. int slotNum = 1;
    86. boolean sendSlotsBoundMessage = true;
    87. boolean anyBinds = false;
    88. while (slotNum <= 10) {
    89. if (slotNumBound(player, slotNum)) {
    90. if (sendSlotsBoundMessage) {
    91. player.sendMessage(ChatColor.GRAY + "You currently have " + ChatColor.GOLD + currentBinds(player) + ChatColor.GRAY + "/" + ChatColor.GOLD + possibleBinds(player) + ChatColor.GRAY + " slots full: ");
    92. sendSlotsBoundMessage = false;
    93. anyBinds = true;
    94. }
    95. plugin.debug(materialName(slot(slotNum).get(player)) + " is bound to the " + ordinalNum(slotNum) + " slot.");
    96. player.sendMessage(ChatColor.GRAY + " - Your " + ChatColor.GOLD + materialName(slot(slotNum).get(player)) + ChatColor.GRAY + " is bound to your " + ChatColor.GOLD + ordinalNum(slotNum) + ChatColor.GRAY + " slot.");
    97. }
    98. slotNum++;
    99. }
    100. if (!anyBinds) {
    101. player.sendMessage(ChatColor.RED + "You currently have nothing bound to your soul!");
    102. }
    103. }
    104.  
    105. public String ordinalNum (Integer num) {
    106. switch (num) {
    107. case 1:
    108. return "first";
    109. case 2:
    110. return "second";
    111. case 3:
    112. return "third";
    113. case 4:
    114. return "fourth";
    115. case 5:
    116. return "fifth";
    117. case 6:
    118. return "sixth";
    119. case 7:
    120. return "seventh";
    121. case 8:
    122. return "eighth";
    123. case 9:
    124. return "ninth";
    125. case 10:
    126. return "tenth";
    127. }
    128. return null;
    129. }
    130.  
    131. public String materialName (ItemStack item) {
    132. return item.getType().toString();
    133. }
    134.  
    135. public Integer firstUnbound (Player player) {
    136. int slotNum = 1;
    137. while (slotNumBound(player, slotNum)) {
    138. if (allowBind(player, slotNum)) {
    139. slotNum++;
    140. }
    141. }
    142. return slotNum;
    143. }
    144.  
    145. public Integer currentBinds (Player player) {
    146. int currentBinds = 0;
    147. int slotNum = 1;
    148. while (slotNum <= 10) {
    149. if (slotNumBound(player, slotNum)) {
    150. currentBinds++;
    151. }
    152. slotNum++;
    153. }
    154. return currentBinds;
    155. }
    156.  
    157. public Integer possibleBinds (Player player) {
    158. int possibleBinds = 10;
    159. String permission = Integer.toString(possibleBinds);
    160. while (possibleBinds >= 1) {
    161. if (player.hasPermission("HavocSurvey.bind" + permission)) {
    162. return possibleBinds;
    163. }
    164. possibleBinds--;
    165. permission = Integer.toString(possibleBinds);
    166. }
    167. return possibleBinds;
    168. }
    169.  
    170. public ItemStack notNullItem (Player player, HashMap<Player, ItemStack> slot) {
    171. if (slot.containsKey(player)) {
    172. return slot.get(player);
    173. }
    174. return new ItemStack(1);
    175. }
    176.  
    177. public HashMap<Player, ItemStack> slot (Integer slotNum) {
    178. if (slotNum <= 10) {
    179. if (slotNum == 1) {
    180. return slot1;
    181. } else if (slotNum == 2) {
    182. return slot2;
    183. } else if (slotNum == 3) {
    184. return slot3;
    185. } else if (slotNum == 4) {
    186. return slot4;
    187. } else if (slotNum == 5) {
    188. return slot5;
    189. } else if (slotNum == 6) {
    190. return slot6;
    191. } else if (slotNum == 7) {
    192. return slot7;
    193. } else if (slotNum == 8) {
    194. return slot8;
    195. } else if (slotNum == 9) {
    196. return slot9;
    197. } else if (slotNum == 10) {
    198. return slot10;
    199. }
    200. }
    201. return null;
    202. }
    203.  
    204. public HashMap<Player, ItemStack> itemBoundSlot (Player player, ItemStack item) {
    205. int slotNum = 1;
    206. while (slotNum <= 10) {
    207. if (itemsMatch(notNullItem(player, slot(slotNum)), item)) {
    208. return slot(slotNum);
    209. }
    210. slotNum++;
    211. }
    212. return null;
    213. }
    214.  
    215. public boolean allowBind (Player player, Integer slotNum) {
    216. ItemStack item = player.getItemInHand();
    217. if (allowed(item)) {
    218. if (bindPermission(player, slotNum)) {
    219. return true;
    220. }
    221. }
    222. return false;
    223. }
    224.  
    225. public boolean allowed (ItemStack item) {
    226. String materialName = materialName(item);
    227. if (materialName.contains("SPADE") || materialName.contains("HOE") || materialName.contains("AXE") || materialName.contains("PICKAXE") || materialName.contains("BOW") || materialName.contains("SWORD") || materialName.contains("HELMET") || materialName.contains("CHESTPLATE") || materialName.contains("LEGGINGS") || materialName.contains("BOOTS")) {
    228. return true;
    229. }
    230. return false;
    231. }
    232.  
    233. public boolean bindPermission (Player player, Integer perm) {
    234. String permission = perm.toString();
    235. while (perm <= 10) {
    236. if (player.hasPermission("HavocSurvey.bind" + permission)) {
    237. return true;
    238. }
    239. perm++;
    240. permission = perm.toString();
    241. }
    242. return false;
    243. }
    244.  
    245. public boolean slotNumBound (Player player, Integer slotNum) {
    246. if (1 <= slotNum && slotNum <= 10) {
    247. return slot(slotNum).containsKey(player);
    248. }
    249. return false;
    250. }
    251.  
    252. public boolean itemBound (Player player, ItemStack item) {
    253. int slotNum = 1;
    254. while (slotNum <= 10) {
    255. if (itemsMatch(notNullItem(player, slot(slotNum)), item)) {
    256. return true;
    257. }
    258. slotNum++;
    259. }
    260. return false;
    261. }
    262.  
    263. public boolean itemsMatch (ItemStack item1, ItemStack item2) {
    264. if (item1.getType() == item2.getType()) {
    265. plugin.debug(materialName(item1) + " matches the material.");
    266. if (item1.getEnchantments().equals(item2.getEnchantments())) {
    267. plugin.debug(materialName(item1) + " matches the enchantments.");
    268. if (item1.getDurability() == item2.getDurability()) {
    269. plugin.debug(materialName(item1) + " (" + String.valueOf(item1.getDurability()) +") matches the durability (" + String.valueOf(item2.getDurability()) + ").");
    270. return true;
    271. }
    272. }
    273. }
    274. return false;
    275. }
    276.  
    277. }
    278.  



    PlayerDeath
    Show Spoiler

    Code:Java
    1.  
    2. package me.iKanak.EventListener;
    3.  
    4. import java.util.ArrayList;
    5. import java.util.HashMap;
    6. import java.util.List;
    7.  
    8. import org.bukkit.entity.Player;
    9. import org.bukkit.event.EventHandler;
    10. import org.bukkit.event.Listener;
    11. import org.bukkit.event.entity.PlayerDeathEvent;
    12. import org.bukkit.inventory.ItemStack;
    13.  
    14. import me.iKanak.HavocBind.Bind;
    15. import me.iKanak.HavocBind.HavocBind;
    16.  
    17. public class PlayerDeath implements Listener {
    18.  
    19. public static HavocBind plugin;
    20. public final Bind bind = new Bind(plugin);
    21. public final HashMap<Player, List<ItemStack>> keptItems = new HashMap<Player, List<ItemStack>>();
    22.  
    23. public PlayerDeath (HavocBind instance) {
    24. plugin = instance;
    25. }
    26.  
    27. @EventHandler
    28. public void onPlayerDeath (PlayerDeathEvent event) {
    29. Player player = event.getEntity();
    30. List<ItemStack> kept = new ArrayList<ItemStack>();
    31. List<ItemStack> dropped = new ArrayList<ItemStack>();
    32. for (ItemStack item : event.getDrops()) {
    33. plugin.debug("Inventory has " + bind.materialName(item) + ".");
    34. if (bind.itemBound(player, item)) {
    35. plugin.debug(bind.materialName(item) + " is kept");
    36. kept.add(item);
    37. } else {
    38. dropped.add(item);
    39. }
    40. }
    41. event.getDrops().clear();
    42. event.getDrops().addAll(dropped);
    43. keptItems.put(player, kept);
    44. }
    45.  
    46. }
    47.  



    PlayerRespawn
    Show Spoiler

    Code:Java
    1.  
    2. package me.iKanak.EventListener;
    3.  
    4. import java.util.List;
    5.  
    6. import org.bukkit.entity.Player;
    7. import org.bukkit.event.EventHandler;
    8. import org.bukkit.event.Listener;
    9. import org.bukkit.event.player.PlayerRespawnEvent;
    10. import org.bukkit.inventory.Inventory;
    11. import org.bukkit.inventory.ItemStack;
    12.  
    13. import me.iKanak.HavocBind.Bind;
    14. import me.iKanak.HavocBind.HavocBind;
    15.  
    16. public class PlayerRespawn implements Listener {
    17. public static HavocBind plugin;
    18. public static Bind bind = new Bind(plugin);
    19. public static PlayerDeath playerDeath = new PlayerDeath(plugin);
    20.  
    21. public PlayerRespawn (HavocBind instance) {
    22. plugin = instance;
    23. }
    24.  
    25. @EventHandler
    26. public void onPlayerRespawn (PlayerRespawnEvent event) {
    27. Player player = event.getPlayer();
    28. Inventory inventory = player.getInventory();
    29. List<ItemStack> kept = playerDeath.keptItems.get(player);
    30. playerDeath.keptItems.remove(player);
    31. for (ItemStack item : kept) {
    32. plugin.debug("Adding " + bind.materialName(item) + " to inventory after respawn.");
    33. inventory.addItem(item);
    34. bind.itemBoundSlot(player, item).remove(player);
    35. }
    36. }
    37.  
    38. }
    39.  

    Show Spoiler
     
  2. Offline

    Karl Marx

    Here's a problem:
    (in PlayerRespawn)
    1. public static HavocBind plugin;
    2. public static Bind bind = new Bind(plugin);
    3. public static PlayerDeath playerDeath = new PlayerDeath(plugin);
    4. public PlayerRespawn (HavocBind instance) {
    5. plugin = instance;
    6. }

    All those static assignments are being run at the time the class is loaded, when "public static HavocBind plugin" is still null. You are therefore passing null to the constructors of Bind and PlayerDeath, which is causing the null pointer exceptions.

    The easiest solution would be to put those initializations inside of the PlayerRespan constructor, after plugin is assigned an Object; but the overall structure could use some cleaning up while you're at it.
     
  3. Offline

    iKanak

    Okay, I moved it so it looks like:


    Code:Java
    1. public static HavocBind plugin;
    2.  
    3. public static Bind bind;
    4.  
    5. public final HashMap<Player, List<ItemStack>> keptItems = new HashMap<Player, List<ItemStack>>();
    6.  
    7.  
    8.  
    9. public PlayerDeath (HavocBind instance) {
    10.  
    11. plugin = instance;
    12.  
    13. bind = new Bind(instance);
    14.  
    15. }


    Code:Java
    1. public static HavocBind plugin;
    2. public static Bind bind;
    3. public PlayerDeath playerDeath;
    4.  
    5. public PlayerRespawn (HavocBind instance) {
    6. plugin = instance;
    7. bind = new Bind(instance);
    8. playerDeath = new PlayerDeath(instance);
    9. }

     
  4. Offline

    Karl Marx

    And...?

    Are you still getting the same error? The formatting on here is so bad that I haven't bothered to look much deeper than that. Can you confirm that the line numbers here all match up with what's in your original files? I'm suspicious of the blank line at the top of all the files.
     
  5. Offline

    iKanak

    I also made playerDeath static.

    Now I'm only getting 1 NPE in my PlayerRespawn class.
    The error is on line 32 where it says "for (ItemStack item : kept) {"

    I think line 32 is sending out a NPE because something is wrong with my "if (bind.itemBound(player, item)) {" in my playerDeath class. Even though certain items should getting added to my kept list, they aren't. Let me look into that...

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 25, 2016
  6. Offline

    Karl Marx

    There may be a bug there, but I gave up trying to step through your code to find exactly what it is. You should really take a step back and rethink your structure before you create too many more bugs.

    Regardless of whether there's a bug in your PlayerDeath class, though, if the error says line 32, then that is exactly where the NPE is occurring. "kept" is definitely null when the NPE occurs (behind the scenes, the compiler is calling kept.iterator(), which is the source of the NPE). It makes sense to me that kept would sometimes be null during regular use (if there's nothing to keep, for example) so I would recommend embracing the possibility with a simple if(kept == null) check before the "for" loop, instead of trying to force your other code to provide an empty List.

    Also, I'm curious; from a player's perspective, how should this plugin work?
     
  7. Offline

    iKanak

    This plugin is basically going to allow players to bind items to their "soul". Once bound, the item is kept on death. I'll probably add in vault support for charging money for this, and giving to a player if it's a player that kills them.
     
Thread Status:
Not open for further replies.

Share This Page