PrettyPipes/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java

237 lines
10 KiB
Java
Raw Normal View History

2020-10-14 22:04:52 +02:00
package de.ellpeck.prettypipes.pipe.modules.craft;
import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.items.ModuleItem;
import de.ellpeck.prettypipes.items.ModuleTier;
2021-03-03 01:56:19 +01:00
import de.ellpeck.prettypipes.misc.ItemEquality;
2020-10-14 23:39:11 +02:00
import de.ellpeck.prettypipes.misc.ItemFilter;
import de.ellpeck.prettypipes.network.NetworkLock;
import de.ellpeck.prettypipes.network.PipeNetwork;
2021-12-02 14:44:26 +01:00
import de.ellpeck.prettypipes.pipe.PipeBlockEntity;
2020-10-14 22:04:52 +02:00
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
2021-12-02 14:44:26 +01:00
import de.ellpeck.prettypipes.terminal.CraftingTerminalBlockEntity;
import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity;
2021-12-02 16:55:04 +01:00
import net.minecraft.core.BlockPos;
2022-06-30 16:00:33 +02:00
import net.minecraft.core.Direction;
2021-12-02 16:55:04 +01:00
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
2021-12-02 12:31:04 +01:00
import net.minecraft.world.item.ItemStack;
2022-06-30 16:00:33 +02:00
import net.minecraftforge.items.IItemHandler;
2020-10-14 22:04:52 +02:00
import net.minecraftforge.items.ItemStackHandler;
2020-10-14 23:39:11 +02:00
import org.apache.commons.lang3.tuple.Pair;
2020-10-14 22:04:52 +02:00
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.function.Consumer;
2020-10-14 22:04:52 +02:00
public class CraftingModuleItem extends ModuleItem {
public final int inputSlots;
public final int outputSlots;
2020-10-15 01:19:22 +02:00
private final int speed;
2020-10-14 22:04:52 +02:00
public CraftingModuleItem(String name, ModuleTier tier) {
super(name);
this.inputSlots = tier.forTier(1, 4, 9);
this.outputSlots = tier.forTier(1, 2, 4);
2020-10-15 01:19:22 +02:00
this.speed = tier.forTier(20, 10, 5);
2020-10-14 22:04:52 +02:00
}
@Override
2021-12-02 14:44:26 +01:00
public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) {
2020-10-14 22:04:52 +02:00
return true;
}
@Override
2021-12-02 14:44:26 +01:00
public boolean hasContainer(ItemStack module, PipeBlockEntity tile) {
2020-10-14 22:04:52 +02:00
return true;
}
@Override
2021-12-02 16:55:04 +01:00
public AbstractPipeContainer<?> getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) {
return new CraftingModuleContainer(Registry.craftingModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex);
2020-10-14 22:04:52 +02:00
}
@Override
2022-06-30 16:00:33 +02:00
public boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler) {
2020-10-15 01:19:22 +02:00
return false;
}
@Override
2022-06-30 16:00:33 +02:00
public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) {
2020-10-15 01:19:22 +02:00
return false;
}
@Override
2021-12-02 14:44:26 +01:00
public void tick(ItemStack module, PipeBlockEntity tile) {
2020-11-28 02:15:29 +01:00
if (!tile.shouldWorkNow(this.speed) || !tile.canWork())
2020-10-15 01:19:22 +02:00
return;
2021-12-02 16:55:04 +01:00
var network = PipeNetwork.get(tile.getLevel());
2020-10-15 01:19:22 +02:00
// process crafting ingredient requests
if (!tile.craftIngredientRequests.isEmpty()) {
network.startProfile("crafting_ingredients");
2021-12-02 16:55:04 +01:00
var request = tile.craftIngredientRequests.peek();
var equalityTypes = ItemFilter.getEqualityTypes(tile);
var dest = tile.getAvailableDestination(Direction.values(), request.stack, true, true);
2020-10-15 01:19:22 +02:00
if (dest != null) {
2021-12-02 16:55:04 +01:00
var requestRemain = network.requestExistingItem(request.location, tile.getBlockPos(), dest.getLeft(), request, dest.getRight(), equalityTypes);
network.resolveNetworkLock(request);
tile.craftIngredientRequests.remove();
// if we couldn't fit all items into the destination, create another request for the rest
2021-12-02 16:55:04 +01:00
var remain = request.stack.copy();
remain.shrink(dest.getRight().getCount() - requestRemain.getCount());
if (!remain.isEmpty()) {
2021-12-02 16:55:04 +01:00
var remainRequest = new NetworkLock(request.location, remain);
tile.craftIngredientRequests.add(remainRequest);
network.createNetworkLock(remainRequest);
2020-10-15 01:19:22 +02:00
}
}
network.endProfile();
2020-10-15 01:19:22 +02:00
}
// pull requested crafting results from the network once they are stored
if (!tile.craftResultRequests.isEmpty()) {
network.startProfile("crafting_results");
2021-12-02 16:55:04 +01:00
var items = network.getOrderedNetworkItems(tile.getBlockPos());
var equalityTypes = ItemFilter.getEqualityTypes(tile);
for (var request : tile.craftResultRequests) {
var remain = request.getRight().copy();
var destPipe = network.getPipe(request.getLeft());
2020-10-15 04:15:52 +02:00
if (destPipe != null) {
2021-12-02 16:55:04 +01:00
var dest = destPipe.getAvailableDestinationOrConnectable(remain, true, true);
if (dest == null)
continue;
2021-12-02 16:55:04 +01:00
for (var item : items) {
var requestRemain = network.requestExistingItem(item, request.getLeft(), dest.getLeft(), null, dest.getRight(), equalityTypes);
2020-10-15 04:15:52 +02:00
remain.shrink(dest.getRight().getCount() - requestRemain.getCount());
if (remain.isEmpty())
break;
}
if (remain.getCount() != request.getRight().getCount()) {
tile.craftResultRequests.remove(request);
// if we couldn't pull everything, log a new request
if (!remain.isEmpty())
tile.craftResultRequests.add(Pair.of(request.getLeft(), remain));
network.endProfile();
2020-10-15 04:15:52 +02:00
return;
}
2020-10-15 01:19:22 +02:00
}
}
network.endProfile();
2020-10-15 01:19:22 +02:00
}
}
2020-10-14 23:39:11 +02:00
2020-10-15 01:19:22 +02:00
@Override
2021-12-02 14:44:26 +01:00
public List<ItemStack> getAllCraftables(ItemStack module, PipeBlockEntity tile) {
2020-10-15 04:15:52 +02:00
List<ItemStack> ret = new ArrayList<>();
2021-12-02 16:55:04 +01:00
var output = this.getOutput(module);
for (var i = 0; i < output.getSlots(); i++) {
var stack = output.getStackInSlot(i);
2020-10-15 04:15:52 +02:00
if (!stack.isEmpty())
ret.add(stack);
2020-10-15 01:19:22 +02:00
}
2020-10-15 04:15:52 +02:00
return ret;
}
2020-10-15 01:19:22 +02:00
2020-10-15 04:15:52 +02:00
@Override
2021-12-02 14:44:26 +01:00
public int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
2021-12-02 16:55:04 +01:00
var network = PipeNetwork.get(tile.getLevel());
var items = network.getOrderedNetworkItems(tile.getBlockPos());
var equalityTypes = ItemFilter.getEqualityTypes(tile);
var input = this.getInput(module);
var craftable = 0;
var output = this.getOutput(module);
for (var i = 0; i < output.getSlots(); i++) {
var out = output.getStackInSlot(i);
2021-03-03 01:56:19 +01:00
if (!out.isEmpty() && ItemEquality.compareItems(out, stack, equalityTypes)) {
2020-10-15 01:19:22 +02:00
// figure out how many crafting operations we can actually do with the input items we have in the network
2022-06-30 16:00:33 +02:00
var availableCrafts = CraftingTerminalBlockEntity.getAvailableCrafts(tile, input.getSlots(), input::getStackInSlot, k -> true, s -> items, unavailableConsumer, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes);
2020-10-15 04:15:52 +02:00
if (availableCrafts > 0)
craftable += out.getCount() * availableCrafts;
2020-10-14 23:39:11 +02:00
}
}
2020-10-15 04:15:52 +02:00
return craftable;
2020-10-14 23:39:11 +02:00
}
@Override
2021-12-02 14:44:26 +01:00
public ItemStack craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
2020-10-14 23:39:11 +02:00
// check if we can craft the required amount of items
2021-12-02 16:55:04 +01:00
var craftableAmount = this.getCraftableAmount(module, tile, unavailableConsumer, stack, dependencyChain);
2020-10-15 04:15:52 +02:00
if (craftableAmount <= 0)
2020-10-14 23:39:11 +02:00
return stack;
2020-10-15 04:15:52 +02:00
2021-12-02 16:55:04 +01:00
var network = PipeNetwork.get(tile.getLevel());
var items = network.getOrderedNetworkItems(tile.getBlockPos());
2020-10-15 04:15:52 +02:00
2021-12-02 16:55:04 +01:00
var equalityTypes = ItemFilter.getEqualityTypes(tile);
var resultAmount = this.getResultAmountPerCraft(module, stack, equalityTypes);
// calculate how many crafting *operations* to do (as opposed to how many *items* to craft)
2021-12-02 16:55:04 +01:00
var requiredCrafts = Mth.ceil(stack.getCount() / (float) resultAmount);
var craftableCrafts = Mth.ceil(craftableAmount / (float) resultAmount);
var toCraft = Math.min(craftableCrafts, requiredCrafts);
2020-10-15 04:15:52 +02:00
2021-12-02 16:55:04 +01:00
var input = this.getInput(module);
for (var i = 0; i < input.getSlots(); i++) {
var in = input.getStackInSlot(i);
2020-10-15 04:15:52 +02:00
if (in.isEmpty())
continue;
2021-12-02 16:55:04 +01:00
var copy = in.copy();
2020-10-15 04:15:52 +02:00
copy.setCount(in.getCount() * toCraft);
2022-06-30 16:00:33 +02:00
var ret = ItemTerminalBlockEntity.requestItemLater(tile.getLevel(), tile.getBlockPos(), items, unavailableConsumer, copy, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes);
2020-10-15 04:15:52 +02:00
tile.craftIngredientRequests.addAll(ret.getLeft());
}
2020-10-15 04:15:52 +02:00
2021-12-02 16:55:04 +01:00
var remain = stack.copy();
remain.shrink(resultAmount * toCraft);
2021-12-02 16:55:04 +01:00
var result = stack.copy();
result.shrink(remain.getCount());
2020-10-15 04:15:52 +02:00
tile.craftResultRequests.add(Pair.of(destPipe, result));
return remain;
}
2020-10-14 22:04:52 +02:00
public ItemStackHandler getInput(ItemStack module) {
2021-12-02 16:55:04 +01:00
var handler = new ItemStackHandler(this.inputSlots);
2020-10-14 22:04:52 +02:00
if (module.hasTag())
handler.deserializeNBT(module.getTag().getCompound("input"));
return handler;
}
public ItemStackHandler getOutput(ItemStack module) {
2021-12-02 16:55:04 +01:00
var handler = new ItemStackHandler(this.outputSlots);
2020-10-14 22:04:52 +02:00
if (module.hasTag())
handler.deserializeNBT(module.getTag().getCompound("output"));
return handler;
}
public void save(ItemStackHandler input, ItemStackHandler output, ItemStack module) {
2021-12-02 16:55:04 +01:00
var tag = module.getOrCreateTag();
2020-10-14 22:04:52 +02:00
if (input != null)
tag.put("input", input.serializeNBT());
if (output != null)
tag.put("output", output.serializeNBT());
}
2020-10-14 23:39:11 +02:00
2021-03-03 01:56:19 +01:00
private int getResultAmountPerCraft(ItemStack module, ItemStack stack, ItemEquality... equalityTypes) {
2021-12-02 16:55:04 +01:00
var output = this.getOutput(module);
var resultAmount = 0;
for (var i = 0; i < output.getSlots(); i++) {
var out = output.getStackInSlot(i);
2021-03-03 01:56:19 +01:00
if (ItemEquality.compareItems(stack, out, equalityTypes))
2020-10-14 23:39:11 +02:00
resultAmount += out.getCount();
}
return resultAmount;
}
private static Stack<ItemStack> addDependency(Stack<ItemStack> deps, ItemStack module) {
deps = (Stack<ItemStack>) deps.clone();
deps.push(module);
return deps;
}
2020-10-14 22:04:52 +02:00
}