ExperienceManager (was ExperienceUtils) - make giving/taking exp a bit more intuitive

Discussion in 'Resources' started by desht, Jan 13, 2012.

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

    desht


    Okay. getCurrentExp() is pretty simple:
    PHP:
     
    public int getCurrentExp() {
      
    Player player getPlayer();
      
    int lvl player.getLevel();
      return 
    getXpForLevel(lvl) + (int) (xpRequiredForNextLevel[lvl] * player.getExp());
    }
    Seems the only way it could be going wrong there is if player.getLevel() is returning some impossibly huge value - that would cause getXpForLevel() to reinitialise the lookup tables to some excessive size. How did you give the player 9363 levels in the first place...?
     
  2. Actually that is a good point. Thinking about it now I don't know how it happened, I had 2 players with 499 levels of XP and one player died and dropped his XP, I picked it up and suddenly I was at level 9363. I'll leave it for now then as I doubt anyone will have that much XP.
     
  3. Offline

    desht

    OK, sounds good. It's probably still worth adding a safeguard so that a bad return value doesn't take the whole server down with it... I can put a hard maximum on the permitted size of the lookup tables.
     
  4. Okay, I could just use a try catch couldn't I?
     
  5. Offline

    desht

    Updated with a couple of new features:
    • Hard max level limit imposed (default: 100000, can be changed with ExperienceManager.setHardMaxLevel()) - this will prevent the lookup tables growing without limit and causing out of memory errors
    • getLevelForExp() now also extends the lookup tables as necessary and always returns the correct level (previously it just returned the highest level the existing lookup tables knew about)

    To catch the OutOfMemoryError? No. Catching exceptions is fine, attempting to catch any subclass of Error... not so fine :)

    Anyway see my last post - I've put a safeguard in now.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
    iKeirNez likes this.
  6. Thanks! Seems to be working perfectly now :D
     
  7. desht You might be interested in this for when 1.3 comes out (hopefully August 1st according to jeb). If CraftBukkit has not already fixed this and your class file is still being used then this will have to be updated.

    Info found on redstonehelpers reddit post: Link
     
  8. Offline

    desht

    Yep, I'm aware of it - a lot depends on how CB handles experience once 1.3 is out...
     
  9. Offline

    codename_B

    I've been looking for this!
     
  10. Offline

    desht

    Help yourself :)

    BTW I've updated the initial post a bit to account for various updates to the class.
     
  11. desht CommandsEX version 1.75 now uses your Experience Manager class :D
     
    desht likes this.
  12. Offline

    raGan.

    Does anyone know if this method is working as expected ?
    BUKKIT-1906: Add method for returning total experience required for next level
     
  13. Worked for me when I tried it awhile ago.
     
  14. Offline

    raGan.

    Should we expect update soon ?
     
  15. I'm also looking for this.

    But just an ideea... how about just spawn some exp orbs under the player, he should pick them up instantly and give exp properly through the minecraft system.
     
  16. Offline

    raGan.

    And how would subtracting work ?
     
  17. Then someone else could possibly pick it up. Also it seems that in 1.3 they have improved the way experience works so maybe we will not need this anymore.
     
  18. Offline

    raGan.

    I believe only change that is necessary is initLookupTables() method.
     
  19. Well, it would be alot better if giveExp() would've worked properly, with negative values and levelling down as well.
     
  20. Offline

    Comphenix

    That's exactly what I do for my plugin, and it works perfectly in 1.3:
    https://github.com/aadnk/ExperienceMod/blob/master/ExperienceMod/src/com/comphenix/xp/Server.java

    Prior to 1.3, the experience orbs would take a couple of seconds before they would be visible on the client side. So, this method wouldn't create that familiar sound indicating that you've gotten experience.

    I've also updated my own ExperienceManager for 1.3:
    https://github.com/aadnk/Experience...nix/xp/rewards/xp/ExperienceManager.java#L126

    It's based on the experience system in Essentials, however, and not the utility class in this thread. Mainly because I couldn't find the cause for a bug that occurs when you're enchanting, so I simply switched classes. Though, looking at the differences, I suppose it's because desht's class doesn't reset everything before giving experience.
     
  21. Offline

    desht

    I'll be updating it on Monday - on a mobile device right now, can't do much till then.
     
  22. Offline

    desht

    It's updated now: https://github.com/desht/dhutils/blob/master/src/main/java/me/desht/dhutils/ExperienceManager.java

    The lookup table initialisation has been redone to use MC 1.3 values - 17 xp per level until level 16, then the increment rises by 3 each level until 30, after which it rises by 7 each level.

    I also found & fixed a subtle bug where adding 1 xp when the player had 299 xp did nothing - I was wrongly rounding down when calculating player current exp instead of rounding nearest.

    Comphenix looks like a good approach too, but my implementation shouldn't suffer from the exp loss when enchanting problem either - it's all down to the fact that the Bukkit player.getTotalExperience() method doesn't take enchanting into account. I don't use that method any more.
     
    Zarkaos, iKeirNez, Digi and 1 other person like this.
  23. Thanks, for this! Updated the class in CommandsEX
     
  24. Offline

    Comphenix

    It's been a while since I last encountered the problem, and I can't remember exactly what caused it. I tried various combinations of enchanting and killing myself (to drop experience), but no luck yet (in 1.3.1 at least). I don't think it's because you switched from getTotalExperience() either - the first version of ExperienceManager I used was already fixed. I'll get back to you if I do find anything concrete.

    However, I can't help but to wonder if the problem was caused by the fact that you never update the total experience value. For instance, in 1.2.5 EntityPlayer.java, the total experience is used by Minecraft to determine if the client's copy of the experience amount needs to be updated:
    Code:
    if (this.expTotal != this.lastSentExp) {
        this.lastSentExp = this.expTotal;
        this.netServerHandler.sendPacket(new Packet43SetExperience(this.exp, this.expTotal, this.expLevel));
    }
    So, to be completely safe, I've added the following to ExperienceManager.setExp():
    Code:
    if (xp > base) {
        player.setTotalExperience(player.getTotalExperience() + xp - (int)base);
    }
    Also, in case you're interested (and since you requested changes to be brought back to you), I've also added the ability to set fractional experience in my copy:
    https://github.com/aadnk/Experience...omphenix/xp/rewards/xp/ExperienceManager.java

    I'm using it to alter how much experience you need before gaining a level - allowing one to, for instance, accurately recreate 1.2.5 experience leveling in 1.3.1. It's much easier than storing the fraction myself, or set a probability of giving an experience.

    I also used WeakReference to store a reference to the player, instead of looking it up all the time. That should be a bit faster, especially considering the fact that getPlayer() is an O(n) operation. Bukkit doesn't use a hash table, judging by the source code.
     
    Erbros likes this.
  25. Offline

    desht

    Comphenix Well, it only took 3 months, but I've merged your updates into my code since they appear to work nicely - thanks :)
     
    Comphenix likes this.
  26. Offline

    Zarkaos

    Thanks a lot for your ExperienceManager!
    I tried it in my XpBank project and after a first look, it appears to work great on 1.4.5! It really saved me from the hell in which I was trying to figure out how the experience system worked with Player.setExp(), Player.giveExp() etc..
    I'll perform more comprehensives tests and see what happens.

    If you wanna check out my github, there it is: https://github.com/Zarkaos/XpBankBukkit

    (also sorry for my English, I'm french ;))
     
  27. Offline

    ImTheFool

    This is absolutely wonderful. Thank you.
     
  28. Offline

    KodekPL

    After some test I see that when you have more than 833 exp, the getCurrentExp() return wrong value. It's always greater than it should be. More exp you have, more wrong getCurrentExp() is.

    EDIT:
    So after changing line 77 (if (i >= 30)) to if (i > 30) it fix the problem, but I'm not sure about that. Hopefully desht will check it out :)
     
  29. Offline

    desht

    Thanks, I'll take a look into that one!
     
  30. Offline

    Skyshayde

    I may be doing something wrong, but I can't use a variable with changeExp().

    my code is

    int xp = dmg * xpfactor;
    pl.damager.put(playername, 0);
    ExperienceManager em = new ExperienceManager(player);
    em.changeExp(xp);
     
Thread Status:
Not open for further replies.

Share This Page