Removing Items from a chest

I am trying to make a plugin that requires me to find an inventory of a chest, then get an item in it, and decrease the stack size by one, or remove it (if there is only one).

Sadly I have not found any good information on the inventory managing, other then some basic things.
At the moment, I am able to get the inventory of a chest, but that’s all. I am not sure how to access each slot of an inventory, nor how to change the item stack there.

I am making this for 1.12.2 and using Sponge 7.0.0. Any help is appreciated.

So due to the fact you are doing it to all slots in the inventory and the fact you have the inventory, im going to show you what needs to happen.

First you need to get all the slots in the inventory.

Inventory inv;
Iterable<Inventory> slots = inv.slots();

Next up you need to do a “for” statement to pass through all the slots and ignore the ones without a item in

for(Inventory slot : slots) {
  Optional<ItemStack> opStack = slot.peek();
  if(!opStack.isPresent()){
    continue;
  }

After that do the manipulation on the itemstack you wish to and set it back

    continue;
  }
  ItemStack stack = opStack.get();
  //Do what ever
  slot.set(stack);
}
1 Like

Thank you so much for the fast response, This looks 10x easier then anything I have been seeing. I will test this out shortly!

1 Like

My next response probably wont be as quick as im going to bed. But also note that i wrote that on my phone so some functions maybe incorrectly named but there are the correctly named ones in sponge :slight_smile:

1 Like

Actually its even easier. You can just query for slots with matching items.
poll will then remove the items from the inventory:

inv.query(QueryOperationTypes.ITEM_STACK_IGNORE_QUANTITY.of(stackToMatch))
   .poll(amountToRemove);

Cool. Thanks for the inventory api buts its one of apis i least use so i havent taken much of a look

Question about that bit of code, how would I make that work for say, an entire chest inventory, or does it?

It does. Both mine and the lord of inventories do

The cool thing is you could even combine the inventories of multiple chests using inv.union(otherInv) then filter out with query and poll from all of them.

Sweet, I will try that out, since I am cycling through a few chests this will help.

-Edit-
Ok, so my goal, is to take a list of multiple chests, and compare the itemStacks in the inventory to a set of ItemStacks in a config, and if any stack is the same (not including the quantity) to decrease the stack and spawn it into the world. I already have a portion of this code set up, but what would be the best way to get all the stacks of items from the inventory and compare it to a List?

If you use my original code. In the “do whatever” part. Get the list and then do a for or stream loop to match the target ItemStack with your list of (im guessing) ItemStack Snapshots. If they match then do whatever. If not continue.

So something like this.

List<ItemStackSnapshot> yourlist;

ItemStack stack = opStack.peek();
ItemStackSnapshot asSnapshot = stack.createSnapshot();
if(!yourlist.stream().anyMatch(i -> compare(i, asSnapshot)){
  continue;
}

Now you will also need this. This is to compare two ItemStackSnapshots

private boolean compare(ItemStackSnapshot ori, ItemStackSnapshot snapshot){
  
for(Key<? extends BaseValue<? extends Object>> key : ori.getValues()){
    Optional<? extends Object> opOriValue = ori.get(key);
    if(!opOriValue.isPresent()){
        continue;
    }
    Optional<? extends Object> opStackValue = stack.get(key);
    if(!opStackValue.isPresent()) {
        return false;
    }
    if(opStackValue.get().equals(opOriValue.get()) {
      continue;
    }
   return false;
 }
return true;

}

Once again doing this from phone so spelling and many more mistakes could be present

Ok, So I attempted to use your piece of code in my methods and it fails to build each time I try. Here is the code that I am having issues with:

Methods.java

public static List<ItemStack> getListFromTier(Inventory chests, int tier){
	List<ItemStack> validOptions = new ArrayList<ItemStack>();
	for(Inventory slot : chests.slots()) {
		Optional<ItemStack> opStack = slot.peek();
		  if(!opStack.isPresent())
		    continue;
		  List<ItemStack> yourlist = TierConfiguration.getInstance().getTier(tier);
		  ItemStack stack = opStack.get();
		  ItemStackSnapshot asSnapshot = stack.createSnapshot();
		  if(!yourlist.stream().anyMatch(j -> compare(j.createSnapshot(), asSnapshot))){
		    continue;
		  }
		  validOptions.add(stack);
	}
	return validOptions;
}

private static boolean compare(ItemStackSnapshot ori, ItemStackSnapshot stack){
	for(Key<? extends BaseValue<? extends Object>> key : ori.getKeys()){
	    Optional<? extends Object> opOriValue = ori.get(key);
	    if(!opOriValue.isPresent()){
	        continue;
	    }
	    Optional<? extends Object> opStackValue = stack.get(key);
	    if(!opStackValue.isPresent()) {
	        return false;
	    }
	    if(opStackValue.get().equals(opOriValue.get())) {
	      continue;
	    }
	   return false;
	 }
	return true;
}

DropPartyEvent.java

dropParty = Sponge.getScheduler().createTaskBuilder().execute(() -> {
	for(int i = 0; i < itemsPerSec; i++) {
		System.out.println("#" + i + " in a second");
		TextLibs.sendConsoleMessage("trying to drop item");
		int tier = 0;
		int range = rand.nextInt(DefaultConfiguration.getInstance().getTotalChance());
		Inventory chests = null;
		for(int j = 5; j > 0; j--) {
			if(DefaultConfiguration.getInstance().getRange()[j] >= range 
					&& (j != 0 ? DefaultConfiguration.getInstance().getRange()[j-1] < range : true)) {
				tier = j;
				System.out.println("Tier " + tier + " range is " + range);
				break;
			}
		}
		for(ExtendedBlockPos pos : SetupConfiguration.getInstance().getChests(name)){
			Inventory chest = Methods.getCarrier(pos).getInventory();
			if(chests == null) {
				chests = chest;
			} else {
				chests.union(chest);
			}
		}
		List<ItemStack> validOptions = new ArrayList<ItemStack>();
		while(validOptions.isEmpty()) {
			validOptions = Methods.getListFromTier(chests, tier);
			if(validOptions.isEmpty() && tier > 0) {
				System.out.println("Tier " + tier + " Items not found, trying Tier " + (tier -1));
				tier--;
			} else if (validOptions.isEmpty() && tier == 0) {
				for(int k = 1; k < 5; k++) {
					if(!Methods.getListFromTier(chests, k).isEmpty()) {
						validOptions = Methods.getListFromTier(chests, k);
						break;
					}
					if(k == 5 && Methods.getListFromTier(chests, k).isEmpty()) {
						System.out.print("Chests are empty, ending party");
						endEvent();
					}
				}
			}
		}
		ItemStack randomStack = validOptions.get(rand.nextInt(validOptions.size()-1));
		for(Inventory slot : chests.slots()) {
			if(slot.contains(randomStack)) {
				SetupConfiguration.getInstance().spawnItemAtDrop(name, slot.poll(1).get());
				System.out.println("Dropping item at drop");
			}
		}
	}
}
	).interval(1, TimeUnit.SECONDS).submit(Main.getInstance());

I already feel like there are better ways to make this code work, but I am not sure as to what they would be, but the error is with this line of code from the Methods.java:

Optional<? extends Object> opStackValue = stack.get(key);

this is the error:
argument mismatch; Key<CAP#1> cannot be converted to Key<? extends BaseValue>)

Because your list is a list of ItemStacks and not the snapshots that I thought they were. There is a much better way.

Use

ItemTackComparators.IGNORE_SIZE.compare(j, stack)

instead of compare function