get/setTotalExperience not working

Discussion in 'Plugin Development' started by civ77, Jan 9, 2012.

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

    civ77

    My plugin is having trouble with get/setTotalExperience and whenever I type the commands (/deposit_xp or /withdraw_xp) I get "/depositxp" and "/withdrawxp" respectively in the chat window.
    Here is my debug readout:
    Show Spoiler

    Code:
    Depositing experience:
    2012-01-09 18:38:15 [INFO] DEBUG: Starting command...
    2012-01-09 18:38:15 [INFO] DEBUG: User in bank world...
    2012-01-09 18:38:15 [INFO] DEBUG: Updating experience...
    2012-01-09 18:38:15 [INFO] DEBUG: User has 0 Xp
    2012-01-09 18:38:15 [INFO] DEBUG: User has 12 Stored Xp
    2012-01-09 18:38:15 [INFO] DEBUG: User now has 12 Stored Xp
    2012-01-09 18:38:15 [INFO] DEBUG: User now has 0xp
    
    Withdrawing experience:
    2012-01-09 18:38:56 [INFO] DEBUG: Starting command...
    2012-01-09 18:38:56 [INFO] DEBUG: User in bank world...
    2012-01-09 18:38:56 [INFO] DEBUG: Updating experience...
    2012-01-09 18:38:56 [INFO] DEBUG: User has 0 Xp
    2012-01-09 18:38:56 [INFO] DEBUG: User has 12 Stored Xp
    2012-01-09 18:38:56 [INFO] DEBUG: User now has 0 Stored Xp
    2012-01-09 18:38:56 [INFO] DEBUG: User now has 12xp
    

    I believe these are the problematic sections of the plugin:
    Show Spoiler

    don't worry about the open brackets they're closed in the full class
    Code:
    if(client.getWorld()==Bukkit.getWorld(plugin.config_bankworld)){
        plugin.log.info("DEBUG: User in bank world...");
        if(distance<= 3){
        plugin.log.info("DEBUG: Updating experience...");
        xp = client.getTotalExperience();
        plugin.log.info("DEBUG: User has " + xp + " Xp");
        client.setTotalExperience(0);
        storedXp = plugin.ExpBankAccs.get(client.getName());
        plugin.log.info("DEBUG: User has " + storedXp + " Stored Xp");
        plugin.ExpBankAccs.put(client.getName(),storedXp + xp);
        plugin.log.info("DEBUG: User now has " + plugin.ExpBankAccs.get(client.getName()) + " Stored Xp");
        plugin.log.info("DEBUG: User now has " + client.getTotalExperience() + "xp");
        sender.sendMessage("Your experience was updated!");
    
    Code:
        if(client.getWorld()==Bukkit.getWorld(plugin.config_bankworld)){
        plugin.log.info("DEBUG: User in bank world...");
        if(distance<= 3){
        plugin.log.info("DEBUG: Updating experience...");
        xp = client.getTotalExperience();
        plugin.log.info("DEBUG: User has " + xp + " Xp");
        storedXp = plugin.ExpBankAccs.get(client.getName());
        plugin.log.info("DEBUG: User has " + storedXp + " Stored Xp");
        plugin.ExpBankAccs.put(client.getName(),0);
        plugin.log.info("DEBUG: User now has " + plugin.ExpBankAccs.get(client.getName()) + " Stored Xp");
        client.setTotalExperience(xp + storedXp);
        plugin.log.info("DEBUG: User now has " + client.getTotalExperience() + "xp");
        sender.sendMessage("Your experience was updated!");
    

    and here are the full classes just in case:
    Show Spoiler

    Deposit experience command:
    Code:
        /*
         * ExpBank - by Hayden
         *
         *
         * powered by Kickstarter
         */
        package me.hayden.expbank.commands;
        import org.bukkit.Bukkit;
        import org.bukkit.command.Command;
        import org.bukkit.entity.*;
        import org.bukkit.command.CommandExecutor;
        import org.bukkit.command.CommandSender;
        import me.hayden.expbank.ExpBank;
        public class CommandExecutor_Deposit_xp implements CommandExecutor {
        private ExpBank plugin;
        public CommandExecutor_Deposit_xp(ExpBank plugin){
        this.plugin = plugin;
        }
        @Override
        public boolean onCommand(CommandSender sender, Command command,String label, String[] args) {
        if (command.getName().equalsIgnoreCase("deposit_xp")) {
        if (!(sender instanceof Player)) {
        sender.sendMessage("This command is only applicable to players.");
        return true;
        }
        int xp = 0;
        int storedXp = 0;
        Player client = (Player) sender;
        double x1=1337, x2=1337, y1=1337, y2=1337, z1=1337, z2=1337;
        x2 =plugin.config_bankxcoord;
        y2 =plugin.config_bankycoord;
        z2 =plugin.config_bankzcoord;
        x1 = client.getLocation().getX();
        y1 = client.getLocation().getY();
        z1 = client.getLocation().getZ();
        double distance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2));
        plugin.log.info("DEBUG: Starting command...");
        if(plugin.ExpBankAccs.get(client.getName()) == (null)){
        plugin.ExpBankAccs.put(client.getName(), 0);
        plugin.log.info("DEBUG: New Bank account created...");
        }
        if(client.getLocation() == null){
        plugin.log.info("DEBUG:Client location was null!");
        return true;
        }
        if(client.getWorld()==Bukkit.getWorld(plugin.config_bankworld)){
        plugin.log.info("DEBUG: User in bank world...");
        if(distance<= 3){
        plugin.log.info("DEBUG: Updating experience...");
        xp = client.getTotalExperience();
        plugin.log.info("DEBUG: User has " + xp + " Xp");
        client.setTotalExperience(0);
        storedXp = plugin.ExpBankAccs.get(client.getName());
        plugin.log.info("DEBUG: User has " + storedXp + " Stored Xp");
        plugin.ExpBankAccs.put(client.getName(),storedXp + xp);
        plugin.log.info("DEBUG: User now has " + plugin.ExpBankAccs.get(client.getName()) + " Stored Xp");
        plugin.log.info("DEBUG: User now has " + client.getTotalExperience() + "xp");
        sender.sendMessage("Your experience was updated!");
        }
        else{
        sender.sendMessage("Please go to the bank.");
        plugin.log.info("DEBUG: User to far away...");
        }
        }
        else{
        sender.sendMessage("Please go to the bank.");
        plugin.log.info("DEBUG: User not in bank world...");
        }
        }
    	return false;
        }
        }
    
    Withdrawing experience command (%90 the same as the other command):
    Code:
        /*
         * ExpBank - by Hayden
         *
         *
         * powered by Kickstarter
         */
        package me.hayden.expbank.commands;
        import org.bukkit.Bukkit;
        import org.bukkit.command.Command;
        import org.bukkit.entity.*;
        import org.bukkit.command.CommandExecutor;
        import org.bukkit.command.CommandSender;
        import me.hayden.expbank.ExpBank;
        public class CommandExecutor_Withdraw_xp implements CommandExecutor {
        private ExpBank plugin;
        public CommandExecutor_Withdraw_xp(ExpBank plugin){
        this.plugin = plugin;
        }
        @Override
        public boolean onCommand(CommandSender sender, Command command,String label, String[] args) {
        if (command.getName().equalsIgnoreCase("withdraw_xp")) {
        if (!(sender instanceof Player)) {
        sender.sendMessage("This command is only applicable to players.");
        return true;
        }
        int xp = 0;
        int storedXp = 0;
        Player client = (Player) sender;
        double x1=1337, x2=1337, y1=1337, y2=1337, z1=1337, z2=1337;
        x2 =plugin.config_bankxcoord;
        y2 =plugin.config_bankycoord;
        z2 =plugin.config_bankzcoord;
        x1 = client.getLocation().getX();
        y1 = client.getLocation().getY();
        z1 = client.getLocation().getZ();
        double distance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2));
        plugin.log.info("DEBUG: Starting command...");
        if(plugin.ExpBankAccs.get(client.getName()) == (null)){
        plugin.ExpBankAccs.put(client.getName(), 0);
        plugin.log.info("DEBUG: New Bank account created...");
        }
        if(client.getLocation() == null){
        plugin.log.info("DEBUG:Client location was null!");
        return true;
        }
        if(client.getWorld()==Bukkit.getWorld(plugin.config_bankworld)){
        plugin.log.info("DEBUG: User in bank world...");
        if(distance<= 3){
        plugin.log.info("DEBUG: Updating experience...");
        xp = client.getTotalExperience();
        plugin.log.info("DEBUG: User has " + xp + " Xp");
        storedXp = plugin.ExpBankAccs.get(client.getName());
        plugin.log.info("DEBUG: User has " + storedXp + " Stored Xp");
        plugin.ExpBankAccs.put(client.getName(),0);
        plugin.log.info("DEBUG: User now has " + plugin.ExpBankAccs.get(client.getName()) + " Stored Xp");
        client.setTotalExperience(xp + storedXp);
        plugin.log.info("DEBUG: User now has " + client.getTotalExperience() + "xp");
        sender.sendMessage("Your experience was updated!");
        }
        else{
        sender.sendMessage("Please go to the bank.");
        plugin.log.info("DEBUG: User to far away...");
        }
        }
        else{
        sender.sendMessage("Please go to the bank.");
        plugin.log.info("DEBUG: User not in bank world...");
        }
        }
    	return false;
        }
        }
    
    This is the main class of my plugin, I don't think there are any problems with it but, just in case:
    Code:
    //ExpBank - by Hayden
    //Created with Kickstarter
    
    package me.hayden.expbank;
    
    
    import org.bukkit.plugin.java.JavaPlugin;
    
    import java.io.File;
    import java.util.logging.Logger;
    import java.util.HashMap;
    import org.bukkit.plugin.PluginDescriptionFile;
    import me.hayden.expbank.commands.CommandExecutor_Deposit_xp;
    import me.hayden.expbank.commands.CommandExecutor_Withdraw_xp;
    
    public class ExpBank extends JavaPlugin{
    	public Logger log;
    	private PluginDescriptionFile description;
    
    	private String prefix;
    	public double config_bankxcoord = 0;
    	public double config_bankycoord = 64;
    	public double config_bankzcoord = 0;
    	public String config_bankworld = "world";
    	public HashMap<String,Integer> ExpBankAccs = new HashMap<String,Integer>();
    	@Override
    	public void onEnable(){
    		log = Logger.getLogger("Minecraft");
    		description = getDescription();
    		prefix = "["+description.getName()+"] ";
    		File savefile = new File("plugins/ExpBank/save.dat");
            boolean exists = savefile.exists();
            if(exists){
            	try {
    				ExpBankAccs = (HashMap<String,Integer>)SLAPI.load("plugins/ExpBank/save.dat");
    			} catch (Exception e) {
    				log.severe("!!!failed to load ExpBank accounts!!!");
    				e.printStackTrace();
    			}
            }
    		log.info("loading "+description.getFullName());
    
    
    		getCommand("deposit_xp").setExecutor(new CommandExecutor_Deposit_xp(this));
    		getCommand("withdraw_xp").setExecutor(new CommandExecutor_Withdraw_xp(this));
    
    
    	}
    	@Override
    	public void onDisable(){
    		log.info("disabled "+description.getFullName());
    		try {
    			SLAPI.save(ExpBankAccs,"plugins/ExpBank/save.dat");
    		} catch (Exception e) {
    			log.severe("!!!failed to save ExpBank accounts!!!");
    			e.printStackTrace();
    		}
    
    	}
    
    }
    

    If you have a solution to either of these problems I would appreciate any help.
     
  2. Offline

    Don Redhorse

    hmm... without really looking a lot... take a look at the code of deathtp concerning playerinteract event... or in one of the threads in here..

    I needed to code a workaround to make exp work correctly... and I'm still not sure why.. there is also a bug on leaky about this.. which is also not in a "sure" state atm if it is fixed or not..
     
    civ77 likes this.
  3. Offline

    civ77

    Well that's an interesting workaround, thanks for the help.

    EDIT: @Don_Redhorse I had to make some changes to the class to allow the user to deposit their experience, but it won't work (the opposite command used to withdraw xp works like a charm) I assume this is because I had to use a negative number in the giveExp() method

    Here is the code:
    Code:
        for (int i = client.getTotalExperience(); i < 0; --i) {
            client.giveExp(-1);
            plugin.log.info("DEBUG:player New TotalExperience " + client.getTotalExperience());
        }
    
     
  4. Offline

    Don Redhorse

    getting the exp works... it is in the ondeath event class... you just use getTotalExperience
     
  5. Offline

    civ77

    I know, I meant that I need to use to versions of this exp setting loop, one of them works the other doesn't

    broken one (nothing happens):
    Code:
        for (int i = client.getTotalExperience(); i < 0; --i) {         client.giveExp(-1);         plugin.log.info("DEBUG:player New TotalExperience " + client.getTotalExperience());     }
    working one:
    Code:
        for (int i = 0; i < storedXp; ++i) {         client.giveExp(1);         plugin.log.info("DEBUG:Player New TotalExperience" + client.getTotalExperience())
     
  6. Offline

    nisovin

    On your broken loop I'm assuming you probably want to do i > 0, not i < 0.

    Edit: Also, your command returns are wrong. You should return false if you want the usage from plugin.yml to be displayed. Return true otherwise.
     
    civ77 likes this.
  7. Offline

    civ77

    oh, TY.

    It can only take away the experience from my XP bar not the levels, what can I do to fix this?

    bump

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

    hatstand

    civ77 likes this.
  9. Offline

    desht

    Yep the experience API is seriously brain-damaged (not sure what Notch was thinking). The workaround from @Don Redhorse works for giving exp, but using player.giveExp() with a negative quantity simply doesn't work when you take away enough XP to reduce the player's level. Although player.getTotalExperienece() returns what you'd expect, the client doesn't update the XP bar correctly, and player.getExp() starts returning a negative number (it should return a float between 0.0 and 1.0).
     
  10. Offline

    Don Redhorse

    so probably best would be to get the exp, put it to zero, and increase it again to the amount you want
     
  11. Offline

    desht

    Yeah. I actually have some ideas about making all of this a lot easier... give me a day or two to code something up :) My plan is to have a single method (let's call it grantExp(Player player, int xp) ) which can give an arbitrary quantity of exp to a player, positive or negative, and ensure that the player's level and exp bar are correct, and update correctly in the client.
     
    hatstand and Don Redhorse like this.
  12. Offline

    civ77

    Doesn't your awardExp class already do that?
     
  13. Offline

    desht

    Yeah, but not properly - it's based on the Minecraft Wiki, and that information is outdated - see my later comment in that thread. The implementation I'm working on now should (I hope) be based on exp tables that actually match up with MC 1.0. I think I can also improve the performance a little by avoiding some calculations if the player's level hasn't actually changed.
     
  14. Offline

    civ77

    So if I'm using the awardExp method I could have problems of users gaining or losing experience?
     
  15. Offline

    desht

    Their total exp count will be OK, but the level indicator may not match up with what the client is showing. In particular, grabbing XP from orbs would probably confuse the level/xp relationship.

    @civ77 @Don Redhorse @hatstand

    Okay, as promised, here's a hopefully correct implementation of awardExperience(): https://github.com/desht/ScrollingM...t/scrollingmenusign/util/ExperienceUtils.java

    I gave up on trying to work out a suitable formula for mapping xp <-> level, so I build a lookup table instead. This is based on the observations in https://bukkit.atlassian.net/browse/BUKKIT-47 :

    0 xp = level 0
    7 xp = level 1
    17 xp = level 2
    31 xp = level 3
    ...

    Each time, the incremement between levels goes up by either 3 or 4, depending on whether or not it's an even or odd level. So the increment is 7, 10, 14, 17, 21 ... This appears to match up with the testing I've also done, so hopefully I've gotten it right! I'd appreciate feedback on that.

    The central method in the ExperienceUtils class is awardExperience(). You give it a Player object, and an arbitrary quantity of exp, either positive or negative, and it will Do The Right Thing (tm). The player's correct level is recalculated each time it's called (this uses a binary chop on the lookup table, should be reasonably efficient), so it doesn't matter if the player has been levelled up or down by several levels - the client's exp bar should always show the right level and distance through the level. This also avoids the need to loop and give 1xp at a time to work around Minecraft's bizarre levelling behaviour.

    Anybody who wishes is free to use the ExperienceUtils class in their own plugin, I'd only request the "Author: desht" comment remains intact if you take a copy. I'd also of course like to be notified of any bugfixes. Oh, and change the class's package if you pull it into your own plugin :)

    If I get some positive feedback for this, I'll add a post to the Resources section.

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

    hatstand

    Awesome, going to run a few tests with my plugin, see how it runs.

    Edit: Working Fine.
     
    desht likes this.
Thread Status:
Not open for further replies.

Share This Page