Experience not properly updated by EnchantItemEvent

Discussion in 'Spigot Plugin Development' started by KerchooK, Jul 2, 2018.

  1. I have a scoreboard that displays the player's experience. It is set to 0 when updated by the EnchantItemEvent no matter what the player's level. The same thing happens with the anvil, but I am not going to bore you with that code, I assume it is because of the same issue, whatever it is.

    Here is my code for the event
    Code (Text):
    @EventHandler
        public void onEnchant(EnchantItemEvent e) {
            String player = e.getEnchanter().getName();

            int currentxp = (int) e.getEnchanter().getExp();

            Score xpcount = objective.getScore(player);

            xpcount.setScore(currentxp);

    //this is a message so I know the event occured
            e.getEnchanter().sendMessage("Item Enchanted");

        }
     
  2. Can we please see more of the class, if not the whole class, to see where these variables are actually used.

    Is the message actually sent when the player enchants an item?
    If not, is the class registered as an event?
     
  3. This method doesn't appear to do much of anything. It creates a new Score object and sets its score with #setScore(), but then it's just there.
     
  4. I believe #getExp() doesn't do what you think it does. This method returns the current exp points towards the next level. If you want to get the player's exp level you need to use #getLevel(). If you are looking for total exp across all levels then you want #getTotalExperience().
     
    • Useful Useful x 1
  5. Code (Text):
    ScoreboardManager sbm = Bukkit.getScoreboardManager();

        Scoreboard board = sbm.getNewScoreboard();

        Objective objective = board.registerNewObjective("experience", "xp");
    I have used it here and it works just fine.
    Code (Text):
    @EventHandler
        public void onXPChange(PlayerExpChangeEvent e) {

            String player = e.getPlayer().getName();
           
            int currentxp = (int) e.getPlayer().getExp();

            objective.setDisplayName("Experience Leaderboard");

            Score xpcount = objective.getScore(player);

            xpcount.setScore(currentxp);

            e.getPlayer().setScoreboard(board);

            e.getPlayer().sendMessage("XP Changed");
           
        }
    I want it to replace the old value with the new.
     
  6. Create the scoreboard on the player join event and update it, but then on the xp level change event, just update it, no need to create another scoreboard.
    Also, @BillyGalbreath was right, you have to use player.getLevel().

    Also, you have to register your objective as a level so it updates on its own and you don't need to listen for the xp change event, and you never actually set a display slot, so the scoreboard didn't know where to appear.

    Code (Text):
    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
        Objective objective = scoreboard.registerNewObjective("experience", "level");
        objective.setDisplaySlot(DisplaySlot.SIDEBAR);
        objective.setDisplayName("Experience Leaderboard");
        event.getPlayer().setScoreboard(scoreboard);
    }
     
    #6 FloThePony, Jul 2, 2018
    Last edited: Jul 2, 2018
    • Like Like x 1
  7. Ok, so I've cleaned up my code some. and I made a few fixes. This is my current problem
    .getLevel() only does what it is supposed to in the EnchantItemEvent and PlayerJoinEvent, everywhere else it shows as if I had typed it as .getTotalExperience()
    No need to spoon feed, I just need to know what to replace these with. I will attach all of my code to make things clear.
    Code (Text):
    @EventHandler
        public void onPlayerJoin(PlayerJoinEvent e) {

            Scoreboard board = Bukkit.getScoreboardManager().getNewScoreboard();

            Objective objective = board.registerNewObjective("experience", "xp");

            objective.getScoreboard().resetScores("experience");

            objective.setDisplaySlot(DisplaySlot.SIDEBAR);

            objective.setDisplayName("Experience Leaderboard");

            e.getPlayer().setScoreboard(board);

            e.getPlayer().getScoreboard().getObjective("experience").getScore(e.getPlayer().getDisplayName())
                    .setScore(e.getPlayer().getLevel());

        }

        @EventHandler
        public void onXPChange(PlayerExpChangeEvent e) {

            e.getPlayer().getScoreboard().getObjective("experience").getScore(e.getPlayer().getDisplayName())
                    .setScore(e.getPlayer().getLevel());

            e.getPlayer().sendMessage("XP Changed");

        }

        @EventHandler
        public void onDeath(PlayerDeathEvent e) {

            if (e.getEntity() instanceof Player) {

                e.getEntity().getScoreboard().getObjective("experience").getScore(e.getEntity().getDisplayName())
                        .setScore(e.getEntity().getLevel());

                e.getEntity().sendMessage("Death Occured");

            }

        }

        @EventHandler
        public void onEnchant(EnchantItemEvent e) {

            e.getEnchanter().getScoreboard().getObjective("experience").getScore(e.getEnchanter().getDisplayName())
                    .setScore((int) e.getEnchanter().getLevel());
     
            e.getEnchanter().sendMessage("Item Enchanted");

        }
    The messages are for me to confirm that the events have run

    EDIT:
    The only fix I can think of is to just use getTotalExperience and track all of the experience spent since the player's last death and subtract it from the total amount or setting total experience to the amount after spending it.
     
    #7 KerchooK, Jul 2, 2018
    Last edited: Jul 2, 2018