CC-Tweaked/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java

147 lines
6.0 KiB
Java

// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.platform.ForgeContainerTransfer;
import dan200.computercraft.shared.util.CapabilityUtil;
import net.minecraft.world.Container;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.InvWrapper;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static dan200.computercraft.core.util.ArgumentHelpers.assertBetween;
/**
* Inventory methods for Forge's {@link IItemHandler}.
*/
public final class InventoryMethods extends AbstractInventoryMethods<IItemHandler> {
@Override
@LuaFunction(mainThread = true)
public int size(IItemHandler inventory) {
return inventory.getSlots();
}
@Override
@LuaFunction(mainThread = true)
public Map<Integer, Map<String, ?>> list(IItemHandler inventory) {
Map<Integer, Map<String, ?>> result = new HashMap<>();
var size = inventory.getSlots();
for (var i = 0; i < size; i++) {
var stack = inventory.getStackInSlot(i);
if (!stack.isEmpty()) result.put(i + 1, VanillaDetailRegistries.ITEM_STACK.getBasicDetails(stack));
}
return result;
}
@Override
@Nullable
@LuaFunction(mainThread = true)
public Map<String, ?> getItemDetail(IItemHandler inventory, int slot) throws LuaException {
assertBetween(slot, 1, inventory.getSlots(), "Slot out of range (%s)");
var stack = inventory.getStackInSlot(slot - 1);
return stack.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(stack);
}
@Override
@LuaFunction(mainThread = true)
public long getItemLimit(IItemHandler inventory, int slot) throws LuaException {
assertBetween(slot, 1, inventory.getSlots(), "Slot out of range (%s)");
return inventory.getSlotLimit(slot - 1);
}
@Override
@LuaFunction(mainThread = true)
public int pushItems(
IItemHandler from, IComputerAccess computer,
String toName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
) throws LuaException {
// Find location to transfer to
var location = computer.getAvailablePeripheral(toName);
if (location == null) throw new LuaException("Target '" + toName + "' does not exist");
var to = extractHandler(location);
if (to == null) throw new LuaException("Target '" + toName + "' is not an inventory");
// Validate slots
int actualLimit = limit.orElse(Integer.MAX_VALUE);
assertBetween(fromSlot, 1, from.getSlots(), "From slot out of range (%s)");
if (toSlot.isPresent()) assertBetween(toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)");
if (actualLimit <= 0) return 0;
return moveItem(from, fromSlot - 1, to, toSlot.orElse(0) - 1, actualLimit);
}
@Override
@LuaFunction(mainThread = true)
public int pullItems(
IItemHandler to, IComputerAccess computer,
String fromName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
) throws LuaException {
// Find location to transfer to
var location = computer.getAvailablePeripheral(fromName);
if (location == null) throw new LuaException("Source '" + fromName + "' does not exist");
var from = extractHandler(location);
if (from == null) throw new LuaException("Source '" + fromName + "' is not an inventory");
// Validate slots
int actualLimit = limit.orElse(Integer.MAX_VALUE);
assertBetween(fromSlot, 1, from.getSlots(), "From slot out of range (%s)");
if (toSlot.isPresent()) assertBetween(toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)");
if (actualLimit <= 0) return 0;
return moveItem(from, fromSlot - 1, to, toSlot.orElse(0) - 1, actualLimit);
}
@Nullable
private static IItemHandler extractHandler(IPeripheral peripheral) {
var object = peripheral.getTarget();
var direction = peripheral instanceof dan200.computercraft.shared.peripheral.generic.GenericPeripheral sided ? sided.side() : null;
if (object instanceof BlockEntity blockEntity && blockEntity.isRemoved()) return null;
if (object instanceof ICapabilityProvider provider) {
var cap = CapabilityUtil.getCapability(provider, ForgeCapabilities.ITEM_HANDLER, direction);
if (cap.isPresent()) return cap.orElseThrow(NullPointerException::new);
}
if (object instanceof IItemHandler handler) return handler;
if (object instanceof Container container) return new InvWrapper(container);
return null;
}
/**
* Move an item from one handler to another.
*
* @param from The handler to move from.
* @param fromSlot The slot to move from.
* @param to The handler to move to.
* @param toSlot The slot to move to. Use any number < 0 to represent any slot.
* @param limit The max number to move. {@link Integer#MAX_VALUE} for no limit.
* @return The number of items moved.
*/
private static int moveItem(IItemHandler from, int fromSlot, IItemHandler to, int toSlot, final int limit) {
var fromWrapper = new ForgeContainerTransfer(from).singleSlot(fromSlot);
var toWrapper = new ForgeContainerTransfer(to);
if (toSlot >= 0) toWrapper = toWrapper.singleSlot(toSlot);
return Math.max(0, fromWrapper.moveTo(toWrapper, limit));
}
}