Solved GetDurability doesnt work?

Discussion in 'Plugin Development' started by Qaez, Dec 3, 2013.

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

    Qaez

    Hello,

    I am making a Magic Wand plugin, and now I am working with the loop through the spells,
    I use this for the looping part:

    Code:java
    1. @EventHandler
    2. public void onPlayerClick(PlayerInteractEvent event)
    3. {
    4. Action action = event.getAction();
    5. Player player = event.getPlayer();
    6. if (((action.equals(Action.RIGHT_CLICK_AIR)) ||
    7. (action.equals(Action.RIGHT_CLICK_BLOCK))) &&
    8. (player.getItemInHand().getType().equals(Material.BLAZE_ROD))) {
    9. if (player.getItemInHand().getItemMeta().hasDisplayName())
    10. {
    11. ItemStack wand = player.getItemInHand();
    12. ItemMeta wandMeta = wand.getItemMeta();
    13. if (wandMeta.getDisplayName().equals(ChatColor.GOLD + "Magic Wand"))
    14. {
    15. int dur = wand.getDurability();
    16. if (dur < 1) {
    17. wand.setDurability((short)(dur + 1));
    18. } else {
    19. wand.setDurability((short)0);
    20. }
    21.  
    22. player.getWorld().playEffect(player.getLocation(),
    23. Effect.STEP_SOUND, Material.GOLD_BLOCK);
    24.  
    25. player.sendMessage(ChatColor.GOLD + "You've selected: " +
    26. ChatColor.YELLOW + (String)this.plugin.Spells.get(dur));
    27. }
    28. }
    29. }
    30. }


    But this doesnt work..
    My onEnable is:
    Code:java
    1. @Override
    2. public void onEnable() {
    3. plugin = this;
    4. getServer().getPluginManager().registerEvents(castSpell, this);
    5. getServer().getPluginManager().registerEvents(selectSpell, this);
    6. this.Spells.add("Confuse");
    7. this.Spells.add("Comet");
    8. getCommand("wand").setExecutor(fc);
    9. logger.info("[Magic Wand] has been enabled!");
    10. }


    And this is my cast spell part:
    Code:java
    1. @SuppressWarnings("deprecation")
    2. @EventHandler
    3. public void CastSpells(PlayerInteractEvent e){
    4. Player player = e.getPlayer();
    5. World world = player.getWorld();
    6. if(player.getItemInHand().hasItemMeta() && player.getItemInHand().getItemMeta().hasDisplayName()){
    7. if(player.getItemInHand().getItemMeta().getDisplayName().contains(ChatColor.GOLD + "Magic wand")){
    8. if(e.getAction() == Action.LEFT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_AIR){
    9. ItemStack wand = player.getItemInHand();
    10. ItemMeta meta = wand.getItemMeta();
    11. int dur = wand.getDurability();
    12. if(dur == 0){
    13. con.castSpellAir(player);
    14. }else if(dur == 1){
    15. Comet(player);
    16. }
    17. }
    18.  
    19. }
    20. }
    21. }



    My actual problem is that when I right click it doesnt show anything in the chat and it only fires the confuse spell.
    I hope you can help me!
     
  2. Offline

    BajanAmerican

    Qaez
    if(player.getItemInHand().getType().equals(Maertial.BLAZE_ROD))

    should be

    if(player.getItemInHand().getType() == Material.BLAZE_ROD)


    *That is why you are not getting anything, you are comparing compatible types (Material and Material) not non-compatible types (Material and Object).
     
  3. Offline

    NathanWolf

    If it's not getting to sendMessage, I'm guessing it's not getting past this:

    if (wandMeta.getDisplayName().equals(ChatColor.GOLD + "Magic Wand"))

    It looks like in your cast handler, you use "contains" instead of equals- so try changing the right-click check to contains as well. Without seeing how you're creating the wands, I can't be sure, but that could be it.

    One other note- this:

    if(player.getItemInHand().getItemMeta().getDisplayName().contains(ChatColor.GOLD + "Magic wand")){
    Is a bad idea- get the ItemMeta separately and make sure it's non-null before you check the display name. Otherwise I think if a player were to swing a normal blaze rod here, you'd NPE.

    EDIT: You might also try BajanAmerican's suggestion, but (no offense meant), Material.equals(Material) ought to do the same thing as Material == Material .. I don't think that's the problem. As always, I could be wrong!
     
  4. Offline

    Qaez

    NathanWolf I am creating the wand like this:

    Code:java
    1. ItemStack Wand(){
    2. ItemStack is = new ItemStack(Material.BLAZE_ROD);
    3. ItemMeta im = is.getItemMeta();
    4. im.setDisplayName(ChatColor.GOLD + "Magic wand");
    5. is.setItemMeta(im);
    6. return is;
    7. }


    But it still isnt working.. Any other ideas?

    NathanWolf Wow its showing the text now! But it isnt going to the next spell?

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

    NathanWolf


    Heh- you are creating "Magic wand" but checking for "Magic Wand" :)
     
  6. Offline

    Qaez

    Yeah I fixed that NathanWolf but now it isnt going to the next spell
     
  7. Offline

    NathanWolf

    Is it really not going to the next spell, or did the message not change?

    I think you want to change

    player.sendMessage(ChatColor.GOLD + "You've selected: " +
    ChatColor.YELLOW + (String)this.plugin.Spells.get(dur));
    }

    to

    player.sendMessage(ChatColor.GOLD + "You've selected: " +
    ChatColor.YELLOW + (String)this.plugin.Spells.get(wand.getDurability()));
    }

    Since you don't update the "dur" variable.
     
  8. Offline

    Qaez

    It is really not going to the next spell NathanWolf

    EDIT:
    And it isnt showing the right spell in chat
     
  9. Offline

    NathanWolf

    Problem #2 is I think solved by the change I have above (you're using the wrong index when printing the message)

    Problem #1 I'm not sure... I actually happen to use durability on a blaze rod for my wands, so I'm pretty sure that works (it just saves it as the data tag since that item doesn't wear out). Maybe add some log prints before and after you change the durability, and then when casting - just to see if the value is getting lost or reset somehow?
     
  10. Offline

    Qaez

    NathanWolf Ok I checked it and it doesnt do this part:
    Code:java
    1. else{
    2. wand.setDurability((short)0);
    3. Bukkit.broadcastMessage("set to null check");
    4. }

    And its not adding 1 to it
     
  11. Offline

    NathanWolf

    Weird... uh, maybe try this?

    short dur = wand.getDurability();
    Bukkit.broadcastMessage("Durability = " + dur);

    (btw just declaring dur as a short eliminates the need for all that casting)
     
  12. Offline

    Qaez

    NathanWolf This is weird it just doesnt add 1 to it.. Do you have skype or something? Then I can share screen so you can see
     
  13. Offline

    the_merciless


    I always use .equals() on materials and it works just fine.
     
  14. Offline

    NathanWolf

    Noooooopers, sorry :)

    To be clear, you tried something like this?

    Code:java
    1. short dur = wand.getDurability();
    2. Bukkit.broadcastMessage("Durability = " + dur);
    3. if (dur < 1) {
    4. Bukkit.broadcastMessage("Changed to 1");
    5. dur = 1;
    6. } else {
    7. dur = 0;
    8. Bukkit.broadcastMessage("Changed to 0");
    9. }
    10. wand.setDurability(dur);
    11. Bukkit.broadcastMessage("New dur=" + wand.getDurability());
    12.  


    And what does it print?
     
  15. Offline

    Qaez

    NathanWolf
    It keeps printing:
    Durability = 0
    Changed to 1
    New dur = 0
     
  16. Offline

    NathanWolf

    Allllllrighty, so. Are you on 1.7 now?

    Because, I swear this used to work- but, doesn't seem to any more. I just logged into my own server to check- I made a limited-use wand (I use durability for # times the wand has been used) ... and sure enough it no longer updates.

    This might be an intentional change since the blaze rod doesn't use the data byte for durability (or otherwise). Or, it might be something that Bukkit will fix as 1.7 stabilizes.. not sure.

    I do think this worked in 1.6 though since I was using it.. I just hadn't checked since upgrading.
     
  17. Offline

    Qaez

  18. Offline

    NathanWolf

    One common solution to this is to use lore - so you'd add a line of lore text that has the selected spell. Check the lore and change it as needed. (This gets a little in-depth, but basically start with ItemStack.getItemMeta, then look at getLore and setLore)

    Otherwise if you don't care about the selected spell being persistent you could just store a HashMap of player names to selected spell (either name or index). Then look up the value for each player (it won't stick with the wand anymore).
     
    Qaez likes this.
  19. Offline

    Qaez

    NathanWolf Allright! Thanks for all your help! You helped me a lot!
     
    NathanWolf likes this.
  20. Offline

    NathanWolf

    Happy to help! And happy to know about this issue, I wish I would've figure out what was going on sooner.

    For what it's worth, I think I'll fix this in my plugin by using NBT tags- but I didn't even want to recommend that due to the complexity and unsupported-ness of that approach.
     
  21. Offline

    Qaez

    NathanWolf I have this now:
    Code:java
    1. if(player.getItemInHand().getItemMeta().getDisplayName().contains(ChatColor.GOLD + "Magic wand")){
    2. ItemStack wand = player.getItemInHand();
    3. ItemMeta wandMeta = wand.getItemMeta();
    4. if (wandMeta.getDisplayName().contains(ChatColor.GOLD + "Magic wand"))
    5. {
    6. if(counter < 2){
    7. counter++;
    8. }else{
    9. counter = 1;
    10. }
    11. if(counter == 1){
    12. wandMeta.setLore(plugin.Confuse);
    13. }else if(counter == 2){
    14. wandMeta.setLore(plugin.Comet);
    15. }
    16. }
    17. }


    But this doesnt work?

    NathanWolf It says could not pass InteractEvent to FireworkTest <-- name of plugin

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

    NathanWolf

    Where is "counter" defined? Maybe just paste (or pastebin) your whole class?

    This:

    if (wandMeta.getDisplayName().contains(ChatColor.GOLD + "Magic wand"))
    Should be
    if (wandMeta != null && wandMeta.getDisplayName().contains(ChatColor.GOLD + "Magic wand"))
    The "could not pass" message generally means an exception occurred, and *ought* to be accompanied by a stack trace. But, personally- I've seen the dev build not give stack traces.
    If there is one, please paste it!
     
  23. Offline

    Qaez

  24. Offline

    NathanWolf

    That all looks like it ought to, mostly, work... do you have a stack trace or anything?

    There are definitely a few issues- the biggest being what I mentioned above, you need to check for null ItemMeta. Otherwise this is going to throw an error anytime someone swings a normal blaze rod...

    which might be what's happening to you if the rod isn't getting set up- but I assume it's got the custom name and everything?

    Another note- you are effectively doing this whole check twice:

    if(player.getItemInHand().getItemMeta().getDisplayName().contains(ChatColor.GOLD + "Magic wand")){
    ItemStack wand = player.getItemInHand();
    ItemMeta wandMeta = wand.getItemMeta();
    if (wandMeta.getDisplayName().contains(ChatColor.GOLD + "Magic wand"))
    {

    Look at your code closely, you'll see it.

    Otherwise without a stack trace it will be hard to know why this isn't working.

    And, finally- this gets off into bigger implementation issues- but you will need one listener, but one "spells" tracking class per player. Otherwise everyone will be updating the same counter when they right-click... this is something you can worry about once you get it working single-player, though :)
     
  25. Offline

    Qaez

    NathanWolf I dont use stack-traces .. I dont know what to do now.. I will let you know when I fixed it!
     
  26. Offline

    NathanWolf

    It's not something you use - it's something the Java VM spits out whenever there is an error. It should appear in your server console near where it says "could not pass event".

    A related note- you probably should not be trying to learn to develop a plugin on a dev build of bukkit. If you can, switch back to 1.6 until 1.7 stabilizes into an RB. You don't want to have to be fighting a buggy platform while debugging your own code.

    I mention this because I'm certain 1.6 spits out stack traces when it's supposed to, and I'm not so sure about 1.7.

    And, finally- protip: Learn to use a debugger! Seriously, coding (and especially debugging) anything would take me about 10x longer if I didn't use a debugger. Eclipse can do this for you with a little bit of setup - you have to make a run configuration for your project that includes the CB jar on the classpath, and specify the CB Main class to run.

    Then you can launch Bukkit from inside Eclipse, and set breakpoints and step through your own plugin code.

    It takes a bit of setup, but is totally, totally worth it.
     
  27. Offline

    Qaez

  28. Offline

    NathanWolf

    I would assume so, but I've never used it so I can't help there :)

    Any good Java IDE should also include a UI for the Java debugger.
     
  29. Offline

    Qaez

    NathanWolf But is a debugger the same as a run or not?

    NathanWolf I found the bug it is a nullpointer because it says that the lore is null..

    NathanWolf It just doesnt set the lore is some kind of way... Any ideas? This is my code right now:
    Code:java
    1. if (wandMeta != null && wandMeta.getDisplayName().contains(ChatColor.GOLD + "Magic wand"))
    2. {
    3. if(!counters.containsKey(player.getName())){
    4. counters.put(player.getName(), counter);
    5. }
    6. if(counters.containsKey(player.getName())){
    7. counter = counters.get(player.getName());
    8. }
    9.  
    10. switch (counter){
    11. case 0:
    12. wandMeta.setLore(plugin.confuse);
    13. player.sendMessage(ChatColor.GOLD + "You've selected: " + ChatColor.GRAY + plugin.confuse);
    14. break;
    15. case 1:
    16. wandMeta.setLore(plugin.comet);
    17. player.sendMessage(ChatColor.GOLD + "You've selected: " + ChatColor.GRAY + plugin.comet);
    18. break;
    19. default:
    20. wandMeta.setLore(plugin.confuse);
    21. break;
    22. }
    23. if(counter < 1){
    24. counter++;
    25. counters.put(player.getName(), counter);
    26. }else{
    27. counter = 0;
    28. counters.put(player.getName(), counter);
    29. }
    30. }


    The switcher does work fine! And it displays the spell but it just doesnt cast the spell

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

    NathanWolf

    The difference between running and debugging is that when you're debugging a program called a "debugger" is attached to your process. Watching it for you, basically.

    This lets you do a few things, but most importantly you can tell it to pause at a certain place in your code- this is called a "breakpoint". So, if you want to know exactly what happens when your interact handler fires, you set a breakpoint at the beginning of your handler code.

    Now, when you run CraftBukkit in a debugger, you can connect to the server while debugging it. You swing your wand, and the debugger pops up saying you hit your breakpoint. You can then hit a button in the debugger to "step" through your code- execute one line at a time. You can see exactly what it does and why.

    Anyway, the lore may be null if it's empty. If you're setting the lore, create a new ArrayList<String>(), populate it with your text, and then call setLore().

    If you're checking for existing lore, just keep it mind that it may return null, that means the item has no lore.

    Ah, we crossed paths- lore is a list, not a string. So to set it, you'd need to do this:

    ArrayList<String> newLore = new ArrayList<String>();
    newLore.add(plugin.confuse);
    wandMeta.setLore(newLore);

    Also, random thought- you may want to create a new thread for any new issues you have.

    This thread could actually be helpful/relevant to someone, in that we discovered setting durability on items that don't support it no longer works in 1.7 - but I fear that information is lost in the rest of our discussion :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
Thread Status:
Not open for further replies.

Share This Page