Best way to take items from a player

Discussion in 'Plugin Development' started by Sammy, Apr 7, 2011.

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

    Sammy

    I have seen people making this many different ways and I hate the way I make it, so I would like to know what's the "full-prof" way, for example I wanna take:

    10 of SAND from a players inventory BUT the sand could be divided on a stack of 6 and another of 4
    78of DIRT from a players inventory with 64 on a stack, 10 on another and 4 in another

    My idea is to have some kind of method that will take what's asked regardless of the disposition of the items on the players inventory
     
  2. Offline

    petteyg359

    Did you mean "fool-proof"?

    Code:
    // notThereToStartWith = How many more items you requested to remove than were actually there
    Inventory i = getServer().getPlayer("Jimbo").getInventory();
    HashMap<Integer, ItemStack> notThereToStartWith = i.removeItem(new ItemStack(Material.SAND, 10), new ItemStack(Material.DIRT, 78));
    
     
  3. Offline

    Sammy

    No, fullproof as it can handle everything ^^
    Maybe it's not an expression in English ?

    The problem with your code is that, if the player doesn't have a ItemStack of 10 but 2 of 5 it wont work
     
  4. Offline

    MrChick

    You could sum all stacks of a type up, take the amount you want and then put them back... problem would be that this wouldn't preserve the inventory but clean it up
    But that would get pretty frickly too, I guess... there has to be a better way
     
  5. Offline

    Ne0nx3r0

    Does removeItems() still remove the items if they don't have enough? If not, you could just use it in a conditional and be done with it.

    Otherwise (You'll have to forgive the pseudo-code) you could just manually check if they have enough first:
    Code:
    item_wanted = Material.WHATEVER;
    amount_needed = 78;
    
    //verify they have enough in the first place
    amount_has = 0;
    has_enough = false;
    for(item in inventory){
        if(item.getType() == item_wanted){
            amount_has += item.getStackSize();
    
            if(amount_has >= amount_needed){
                has_enough = true;
                break;
            }
        }
    }
    
    if(!has_enough){
        //error
        return;
    }
    
    //remove the stacks as needed
    amount_remaining = amount_needed;
    for(item in inventory){
        if(item.getType() == item_wanted){
            if(amount_remaining > item.getStackSize()){
                amount_remaining -= item.getStackSize();
                item.setStackSize(item.getStackSize()-amount_remaining);
            }
            else{
                amount_remaining -= item.getStackSize();
                //remove the item here
            }
            if(amount_remaining <= 0){
                break;
            }
        }
    }
    
    This may be how you're doing it already; and I'm not entirely sure there's another way to do it other than iterating their inventory.

    *edit* appending a bit I took out thinking you could use removeItems(), just in case you can't; also fixing a few clerical errors here and there, the general idea seems sound though.
     
  6. Offline

    Sammy

    @ne0nx3r0 thanks for the help. :)

    But yes, that the way I do it, it works but it looks messy to me
     
  7. Offline

    Ne0nx3r0

    I'm an amateur at Java, but I used to code for Neverwinter Nights (c-based) and I did a lot with inventories... One thing I learned was that any decent inventory function HAS to iterate, whether you are doing it yourself, or the method you call is doing it. It's painful, but you can either iterate, or index. (and the latter is even MORE painful)

    On the bright side, this (I assume) isn't something that will happen very often (as in X times/second), so you can take comfort in knowing it doesn't have to be all that fast, but it does need to be accurate.
     
  8. Offline

    petteyg359

    It's supposed to. Have you tested it? If so, file a bug.

    You could answer that yourself by reading the javadoc. There's a big comment block above the function that would tell you "yes". The returned HashMap consists of the ItemStacks that couldn't be removed. If they have 60 dirt, and you remove an ItemStack of 64 dirt, removeItem will return an ItemStack of 4 dirt in the HashMap.

    Code:
    Player p = getServer().getPlayer("Jimbo");
    Player p2 = getServer().getPlayer("BillyJo");
    p.getInventory().clear(); // Jimbo has nothing.
    p2.getInventory().clear(); // BillyJo has nothing.
    p.getInventory().addItem(new ItemStack(Material.DIRT, 16));
    p.getInventory().addItem(new ItemStack(Material.SAND, 32));
    p.getInventory().addItem(new ItemStack(Material.STONE, 48));
    // Jimbo has 16 dirt, 32 sand, and 48 stone.
    HashMap<Integer, ItemStack> difference = p.getInventory().removeItem(new ItemStack(Material.DIRT, 64), new ItemStack(Material.SAND, 64), new ItemStack(Material.STONE, 64));
    //give BillyJo the difference
    for (ItemStack s : difference.values())
      p2.getInventory().addItem(s);
    // BillyJo has 48 dirt, 32 sand, and 16 stone.
    
     
  9. Offline

    Ne0nx3r0

    That is an elegant solution. (also saves one iteration, since you remove them as you go along)

    I wonder if it would be worthwhile to write something that one could use in a conditional, so they could run something like:
    Code:
    if(inventory.tryRemoveItems(new ItemStack(Material.DIRT,12)){
    //was removed
    }else{
    //wasn't removed
    }
    
    It seems like this is what most plugins dealing with inventory scavenging are dealing with anyway, and this wouldn't rearrange/clean their inventory. (not that it's -that- big of an issue; though this is a bit more maintainable, and clear)
     
  10. Offline

    Sammy

    @petteyg359
    Yes it worked, I must had messed up on something the first time, thanks mate :)

    @petteyg359
    How can I check if there are enough items before i remove them ? without doing iterations of course =)

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

    petteyg359

    You could just put back if the HashMap contains positive quantity.
     
  12. Offline

    Sammy

    It looses the players organization, but that's a good thing on my plugin. Thanks again =D
     
  13. Offline

    Ne0nx3r0

    Ran across this in another thread: inventory.contains(ItemStack,MinimumAmount)

    That sounds like it will do what you're looking for. (granted, you are still iterating, just letting the library do it for you) I was surprised there wasn't something like it.
     
  14. Offline

    Sammy

    @ne0nx3r0
    Contains doesn't work, because if looks for stacks not items, but petteyg359 already solved my problem
    Tks 'though
     
Thread Status:
Not open for further replies.

Share This Page