ConstructionWand/src/main/java/thetadev/constructionwand/wand/supplier/SupplierInventory.java

144 lines
5 KiB
Java

package thetadev.constructionwand.wand.supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import thetadev.constructionwand.ConstructionWand;
import thetadev.constructionwand.api.IWandSupplier;
import thetadev.constructionwand.basics.ReplacementRegistry;
import thetadev.constructionwand.basics.WandUtil;
import thetadev.constructionwand.basics.option.WandOptions;
import thetadev.constructionwand.basics.pool.IPool;
import thetadev.constructionwand.basics.pool.OrderedPool;
import thetadev.constructionwand.containers.ContainerManager;
import thetadev.constructionwand.wand.undo.PlaceSnapshot;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Default WandSupplier. Takes items from player inventory.
*/
public class SupplierInventory implements IWandSupplier
{
protected final Player player;
protected final WandOptions options;
protected HashMap<BlockItem, Integer> itemCounts;
protected IPool<BlockItem> itemPool;
public SupplierInventory(Player player, WandOptions options) {
this.player = player;
this.options = options;
}
public void getSupply(@Nullable BlockItem target) {
itemCounts = new LinkedHashMap<>();
ItemStack offhandStack = player.getItemInHand(InteractionHand.OFF_HAND);
itemPool = new OrderedPool<>();
// Block in offhand -> override
if(!offhandStack.isEmpty() && offhandStack.getItem() instanceof BlockItem) {
addBlockItem((BlockItem) offhandStack.getItem());
}
// Otherwise use target block
else if(target != null && target != Items.AIR) {
addBlockItem(target);
// Add replacement items
if(options.match.get() != WandOptions.MATCH.EXACT) {
for(Item it : ReplacementRegistry.getMatchingSet(target)) {
if(it instanceof BlockItem) addBlockItem((BlockItem) it);
}
}
}
}
protected void addBlockItem(BlockItem item) {
int count = WandUtil.countItem(player, item);
if(count > 0) {
itemCounts.put(item, count);
itemPool.add(item);
}
}
@Override
@Nullable
public PlaceSnapshot getPlaceSnapshot(Level world, BlockPos pos, BlockHitResult rayTraceResult,
@Nullable BlockState supportingBlock) {
if(!WandUtil.isPositionPlaceable(world, player, pos, options.replace.get())) return null;
itemPool.reset();
while(true) {
// Draw item from pool (returns null if none are left)
BlockItem item = itemPool.draw();
if(item == null) return null;
int count = itemCounts.get(item);
if(count == 0) continue;
PlaceSnapshot placeSnapshot = PlaceSnapshot.get(world, player, rayTraceResult, pos, item, supportingBlock, options);
if(placeSnapshot != null) {
int ncount = count - 1;
itemCounts.put(item, ncount);
// Remove item from pool if there are no items left
if(ncount == 0) itemPool.remove(item);
return placeSnapshot;
}
}
}
@Override
public int takeItemStack(ItemStack stack) {
int count = stack.getCount();
Item item = stack.getItem();
if(player.getInventory().items == null) return count;
if(player.isCreative()) return 0;
List<ItemStack> hotbar = WandUtil.getHotbarWithOffhand(player);
List<ItemStack> mainInv = WandUtil.getMainInv(player);
// Take items from main inv, loose items first
count = takeItemsInvList(count, item, mainInv, false);
count = takeItemsInvList(count, item, mainInv, true);
// Take items from hotbar, containers first
count = takeItemsInvList(count, item, hotbar, true);
count = takeItemsInvList(count, item, hotbar, false);
return count;
}
private int takeItemsInvList(int count, Item item, List<ItemStack> inv, boolean container) {
ContainerManager containerManager = ConstructionWand.instance.containerManager;
for(ItemStack stack : inv) {
if(count == 0) break;
if(container) {
count = containerManager.useItems(player, new ItemStack(item), stack, count);
}
if(!container && WandUtil.stackEquals(stack, item)) {
int toTake = Math.min(count, stack.getCount());
stack.shrink(toTake);
count -= toTake;
player.getInventory().setChanged();
}
}
return count;
}
}