From 57c3b13b64eb8eba238b7b0d4161970c86dd067c Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 14 Oct 2020 23:39:11 +0200 Subject: [PATCH] part 2: actual crafting implementation --- .../de/ellpeck/prettypipes/items/IModule.java | 4 + .../ellpeck/prettypipes/items/ModuleItem.java | 7 ++ .../ellpeck/prettypipes/misc/ItemFilter.java | 18 ++-- .../prettypipes/network/PipeNetwork.java | 4 +- .../prettypipes/pipe/PipeTileEntity.java | 41 +++++++ .../modules/craft/CraftingModuleItem.java | 75 ++++++++++++- .../retrieval/RetrievalModuleItem.java | 2 +- .../terminal/CraftingTerminalTileEntity.java | 100 +++++++++++------- .../terminal/ItemTerminalTileEntity.java | 94 +++++++++------- 9 files changed, 251 insertions(+), 94 deletions(-) diff --git a/src/main/java/de/ellpeck/prettypipes/items/IModule.java b/src/main/java/de/ellpeck/prettypipes/items/IModule.java index a7cfe7d..22ffa4b 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/IModule.java +++ b/src/main/java/de/ellpeck/prettypipes/items/IModule.java @@ -1,10 +1,12 @@ package de.ellpeck.prettypipes.items; +import de.ellpeck.prettypipes.misc.ItemEqualityType; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import de.ellpeck.prettypipes.pipe.PipeTileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; import net.minecraftforge.items.IItemHandler; import java.util.List; @@ -32,4 +34,6 @@ public interface IModule { boolean canPipeWork(ItemStack module, PipeTileEntity tile); List getCraftables(ItemStack module, PipeTileEntity tile); + + ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes); } diff --git a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java index 8fc99ce..862e12f 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java @@ -2,6 +2,7 @@ package de.ellpeck.prettypipes.items; import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Utility; +import de.ellpeck.prettypipes.misc.ItemEqualityType; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import de.ellpeck.prettypipes.pipe.PipeTileEntity; import net.minecraft.client.util.ITooltipFlag; @@ -9,6 +10,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.*; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; @@ -79,4 +81,9 @@ public abstract class ModuleItem extends Item implements IModule { public List getCraftables(ItemStack module, PipeTileEntity tile) { return Collections.emptyList(); } + + @Override + public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) { + return stack; + } } diff --git a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java index 948cf40..db36cc5 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java @@ -108,7 +108,7 @@ public class ItemFilter extends ItemStackHandler { } private boolean isFiltered(ItemStack stack) { - ItemEqualityType[] types = this.getEqualityTypes(); + ItemEqualityType[] types = getEqualityTypes(this.pipe); // also check if any filter increase modules have the item we need for (ItemStackHandler handler : this.getAllFilters()) { for (int i = 0; i < handler.getSlots(); i++) { @@ -132,14 +132,6 @@ public class ItemFilter extends ItemStackHandler { return filters; } - public ItemEqualityType[] getEqualityTypes() { - return this.pipe.streamModules() - .map(Pair::getRight) - .filter(m -> m instanceof FilterModifierModuleItem) - .map(m -> ((FilterModifierModuleItem) m).type) - .toArray(ItemEqualityType[]::new); - } - public void save() { if (this.modified) { this.stack.getOrCreateTag().put("filter", this.serializeNBT()); @@ -167,6 +159,14 @@ public class ItemFilter extends ItemStackHandler { this.modified = true; } + public static ItemEqualityType[] getEqualityTypes(PipeTileEntity pipe) { + return pipe.streamModules() + .map(Pair::getRight) + .filter(m -> m instanceof FilterModifierModuleItem) + .map(m -> ((FilterModifierModuleItem) m).type) + .toArray(ItemEqualityType[]::new); + } + public interface IFilteredContainer { ItemFilter getFilter(); } diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index 01a302a..6821a4f 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -190,14 +190,14 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL return stack; ItemStack remain = stack.copy(); for (NetworkLocation location : locations) { - remain = this.requestItem(location, destPipe, destInventory, remain, equalityTypes); + remain = this.requestExistingItem(location, destPipe, destInventory, remain, equalityTypes); if (remain.isEmpty()) break; } return remain; } - public ItemStack requestItem(NetworkLocation location, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) { + public ItemStack requestExistingItem(NetworkLocation location, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) { if (location.getPos().equals(destInventory)) return stack; ItemStack remain = stack.copy(); diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java index b668fb4..be12ac5 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java @@ -4,6 +4,9 @@ import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.items.IModule; +import de.ellpeck.prettypipes.misc.ItemEqualityType; +import de.ellpeck.prettypipes.network.NetworkLocation; +import de.ellpeck.prettypipes.network.NetworkLock; import de.ellpeck.prettypipes.network.PipeItem; import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer; @@ -57,6 +60,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide return 1; } }; + public final Queue craftIngredientRequests = new ArrayDeque<>(); public PressurizerTileEntity pressurizer; public int moduleDropCheck; protected List items; @@ -75,6 +79,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public CompoundNBT write(CompoundNBT compound) { compound.put("modules", this.modules.serializeNBT()); compound.putInt("module_drop_check", this.moduleDropCheck); + compound.put("requests", Utility.serializeAll(this.craftIngredientRequests)); return super.write(compound); } @@ -82,6 +87,8 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public void read(BlockState state, CompoundNBT compound) { this.modules.deserializeNBT(compound.getCompound("modules")); this.moduleDropCheck = compound.getInt("module_drop_check"); + this.craftIngredientRequests.clear(); + this.craftIngredientRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new)); super.read(state, compound); } @@ -133,6 +140,26 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide PipeNetwork.get(this.world).clearDestinationCache(this.pos); } profiler.endSection(); + + // request crafting ingredients + if (this.world.getGameTime() % 4 == 0 && !this.craftIngredientRequests.isEmpty()) { + PipeNetwork network = PipeNetwork.get(this.world); + NetworkLock request = this.craftIngredientRequests.remove(); + Pair dest = this.getAvailableDestination(request.stack, true, true); + if (dest != null) { + network.requestExistingItem(request.location, this.getPos(), dest.getLeft(), dest.getRight(), ItemEqualityType.NBT); + network.resolveNetworkLock(request); + + // if we couldn't fit all items into the destination, create another request for the rest + ItemStack remain = request.stack.copy(); + remain.shrink(dest.getRight().getCount()); + if (!remain.isEmpty()) { + NetworkLock remainRequest = new NetworkLock(request.location, remain); + this.craftIngredientRequests.add(remainRequest); + network.createNetworkLock(remainRequest); + } + } + } } profiler.startSection("ticking_items"); @@ -238,6 +265,17 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide .collect(Collectors.toList()); } + public ItemStack craft(BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) { + Iterator> modules = this.streamModules().iterator(); + while (modules.hasNext()) { + Pair module = modules.next(); + stack = module.getRight().craft(module.getLeft(), this, destPipe, destInventory, stack, equalityTypes); + if (stack.isEmpty()) + break; + } + return stack; + } + public IItemHandler getItemHandler(Direction dir, PipeItem item) { if (!this.isConnected(dir)) return null; @@ -301,6 +339,9 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide public void remove() { super.remove(); this.getItems().clear(); + PipeNetwork network = PipeNetwork.get(this.world); + for (NetworkLock lock : this.craftIngredientRequests) + network.resolveNetworkLock(lock); } @Override diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java index 263843b..501de99 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java @@ -4,13 +4,23 @@ import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.ModuleItem; import de.ellpeck.prettypipes.items.ModuleTier; +import de.ellpeck.prettypipes.misc.ItemEqualityType; +import de.ellpeck.prettypipes.misc.ItemFilter; +import de.ellpeck.prettypipes.network.NetworkLocation; +import de.ellpeck.prettypipes.network.NetworkLock; +import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.pipe.PipeTileEntity; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; +import de.ellpeck.prettypipes.terminal.CraftingTerminalTileEntity; +import de.ellpeck.prettypipes.terminal.ItemTerminalTileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraftforge.items.ItemStackHandler; +import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.List; @@ -43,14 +53,60 @@ public class CraftingModuleItem extends ModuleItem { @Override public List getCraftables(ItemStack module, PipeTileEntity tile) { + PipeNetwork network = PipeNetwork.get(tile.getWorld()); + List items = network.getOrderedNetworkItems(tile.getPos()); + List> craftables = network.getOrderedCraftables(tile.getPos()); + ItemEqualityType[] equalityTypes = ItemFilter.getEqualityTypes(tile); + ItemStackHandler output = this.getOutput(module); - List items = new ArrayList<>(); + ItemStackHandler input = this.getInput(module); + + List ret = new ArrayList<>(); for (int i = 0; i < output.getSlots(); i++) { ItemStack stack = output.getStackInSlot(i); - if (!stack.isEmpty()) - items.add(stack); + if (!stack.isEmpty()) { + int availableCrafts = CraftingTerminalTileEntity.getAvailableCrafts(tile.getWorld(), input.getSlots(), input::getStackInSlot, k -> false, s -> items, craftables, null, equalityTypes); + if (availableCrafts > 0) { + ItemStack copy = stack.copy(); + copy.setCount(stack.getCount() * availableCrafts); + ret.add(copy); + } + } + } + return ret; + } + + @Override + public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) { + // check if we can craft the required amount of items + List craftables = this.getCraftables(module, tile); + int craftableAmount = craftables.stream() + .filter(c -> ItemEqualityType.compareItems(c, stack, equalityTypes)) + .mapToInt(ItemStack::getCount).sum(); + if (craftableAmount > 0) { + PipeNetwork network = PipeNetwork.get(tile.getWorld()); + List items = network.getOrderedNetworkItems(tile.getPos()); + List> allCraftables = network.getOrderedCraftables(tile.getPos()); + + int resultAmount = this.getResultAmountPerCraft(module, stack, equalityTypes); + int requiredCrafts = MathHelper.ceil(stack.getCount() / (float) resultAmount); + + ItemStackHandler input = this.getInput(module); + for (int i = 0; i < input.getSlots(); i++) { + ItemStack in = input.getStackInSlot(i).copy(); + if (in.isEmpty()) + continue; + in.setCount(in.getCount() * requiredCrafts); + List requests = ItemTerminalTileEntity.requestItemLater(tile.getWorld(), destPipe, destInventory, in, items, allCraftables, equalityTypes); + tile.craftIngredientRequests.addAll(requests); + } + + ItemStack remain = stack.copy(); + remain.shrink(craftableAmount); + return remain; + } else { + return stack; } - return items; } public ItemStackHandler getInput(ItemStack module) { @@ -74,4 +130,15 @@ public class CraftingModuleItem extends ModuleItem { if (output != null) tag.put("output", output.serializeNBT()); } + + private int getResultAmountPerCraft(ItemStack module, ItemStack stack, ItemEqualityType... equalityTypes) { + ItemStackHandler output = this.getOutput(module); + int resultAmount = 0; + for (int i = 0; i < output.getSlots(); i++) { + ItemStack out = output.getStackInSlot(i); + if (ItemEqualityType.compareItems(stack, out, equalityTypes)) + resultAmount += out.getCount(); + } + return resultAmount; + } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java index 6a288ec..2501dd0 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java @@ -54,7 +54,7 @@ public class RetrievalModuleItem extends ModuleItem { Pair dest = tile.getAvailableDestination(copy, true, this.preventOversending); if (dest == null) continue; - if (network.requestItem(tile.getPos(), dest.getLeft(), dest.getRight(), filter.getEqualityTypes()).isEmpty()) + if (network.requestItem(tile.getPos(), dest.getLeft(), dest.getRight(), ItemFilter.getEqualityTypes(tile)).isEmpty()) break; } } diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java index 194d4dc..fb6886b 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java @@ -20,10 +20,13 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemStackHandler; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.tuple.Pair; @@ -31,6 +34,9 @@ import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; public class CraftingTerminalTileEntity extends ItemTerminalTileEntity { @@ -97,45 +103,11 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity { PipeNetwork network = PipeNetwork.get(this.world); network.startProfile("terminal_request_crafting"); this.updateItems(); - - // the highest amount we can craft with the items we have - int lowestAvailable = Integer.MAX_VALUE; - // this is the amount of items required for each ingredient when crafting ONE - Map requiredItems = new HashMap<>(); - for (int i = 0; i < this.craftItems.getSlots(); i++) { - ItemStack requested = this.getRequestedCraftItem(i); - if (requested.isEmpty()) - continue; - MutableInt amount = requiredItems.computeIfAbsent(new EquatableItemStack(requested), s -> new MutableInt()); - amount.add(1); - int fit = requested.getMaxStackSize() - (this.isGhostItem(i) ? 0 : requested.getCount()); - if (lowestAvailable > fit) - lowestAvailable = fit; - } - for (Map.Entry entry : requiredItems.entrySet()) { - EquatableItemStack stack = entry.getKey(); - NetworkItem item = this.networkItems.get(stack); - // total amount of available items of this type - int available = 0; - if (item != null) { - for (NetworkLocation location : item.getLocations()) { - int amount = location.getItemAmount(this.world, stack.stack, ItemEqualityType.NBT); - if (amount <= 0) - continue; - amount -= network.getLockedAmount(location.getPos(), stack.stack, ItemEqualityType.NBT); - available += amount; - } - // divide the total by the amount required to get the amount that - // we have available for each crafting slot that contains this item - available /= entry.getValue().intValue(); - if (available < lowestAvailable) - lowestAvailable = available; - } else { - lowestAvailable = 0; - } - if (available <= 0) - player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.stack.getDisplayName()).setStyle(Style.EMPTY.setFormatting(TextFormatting.RED)), UUID.randomUUID()); - } + // get the amount of crafts that we can do + int lowestAvailable = getAvailableCrafts(this.world, this.craftItems.getSlots(), this::getRequestedCraftItem, this::isGhostItem, s -> { + NetworkItem item = this.networkItems.get(s); + return item != null ? item.getLocations() : Collections.emptyList(); + }, this.craftables, s -> player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", s.getDisplayName()).setStyle(Style.EMPTY.setFormatting(TextFormatting.RED)), UUID.randomUUID()), ItemEqualityType.NBT); if (lowestAvailable > 0) { // if we're limiting the amount, pretend we only have that amount available if (maxAmount < lowestAvailable) @@ -175,4 +147,54 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity { public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) { return new CraftingTerminalContainer(Registry.craftingTerminalContainer, window, player, this.pos); } + + public static int getAvailableCrafts(World world, int slots, Function inputFunction, Predicate isGhost, Function> locationsFunction, List> craftables, Consumer unavailableConsumer, ItemEqualityType... equalityTypes) { + PipeNetwork network = PipeNetwork.get(world); + // the highest amount we can craft with the items we have + int lowestAvailable = Integer.MAX_VALUE; + // this is the amount of items required for each ingredient when crafting ONE + Map requiredItems = new HashMap<>(); + for (int i = 0; i < slots; i++) { + ItemStack requested = inputFunction.apply(i); + if (requested.isEmpty()) + continue; + MutableInt amount = requiredItems.computeIfAbsent(new EquatableItemStack(requested), s -> new MutableInt()); + amount.add(1); + int fit = requested.getMaxStackSize() - (isGhost.test(i) ? 0 : requested.getCount()); + if (lowestAvailable > fit) + lowestAvailable = fit; + } + for (Map.Entry entry : requiredItems.entrySet()) { + EquatableItemStack stack = entry.getKey(); + + // total amount of available items of this type + int available = 0; + for (NetworkLocation location : locationsFunction.apply(stack)) { + int amount = location.getItemAmount(world, stack.stack, equalityTypes); + if (amount <= 0) + continue; + amount -= network.getLockedAmount(location.getPos(), stack.stack, equalityTypes); + available += amount; + } + // divide the total by the amount required to get the amount that + // we have available for each crafting slot that contains this item + available /= entry.getValue().intValue(); + + // check how many craftable items we have and add those on + if (!craftables.isEmpty()) { + int craftable = craftables.stream().map(Pair::getRight) + .filter(c -> ItemEqualityType.compareItems(c, stack.stack)) + .mapToInt(ItemStack::getCount).sum(); + available += craftable / entry.getValue().intValue(); + } + + // clamp to lowest available + if (available < lowestAvailable) + lowestAvailable = available; + + if (available <= 0 && unavailableConsumer != null) + unavailableConsumer.accept(stack.stack); + } + return lowestAvailable; + } } diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java index defa9cf..a0d452a 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java @@ -28,6 +28,7 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants.NBT; @@ -40,6 +41,7 @@ import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; public class ItemTerminalTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity { @@ -52,7 +54,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine }; public Map networkItems; public List> craftables; - private final Queue pendingRequests = new ArrayDeque<>(); + private final Queue existingRequests = new ArrayDeque<>(); protected ItemTerminalTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); @@ -85,10 +87,10 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine break; } - if (!this.pendingRequests.isEmpty()) { - NetworkLock request = this.pendingRequests.remove(); + if (!this.existingRequests.isEmpty()) { + NetworkLock request = this.existingRequests.remove(); network.resolveNetworkLock(request); - network.requestItem(request.location, pipe.getPos(), this.pos, request.stack, ItemEqualityType.NBT); + network.requestExistingItem(request.location, pipe.getPos(), this.pos, request.stack, ItemEqualityType.NBT); update = true; } } @@ -104,7 +106,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine public void remove() { super.remove(); PipeNetwork network = PipeNetwork.get(this.world); - for (NetworkLock lock : this.pendingRequests) + for (NetworkLock lock : this.existingRequests) network.resolveNetworkLock(lock); } @@ -151,37 +153,12 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine network.endProfile(); } - protected int requestItemImpl(ItemStack stack) { - PipeNetwork network = PipeNetwork.get(this.world); - EquatableItemStack equatable = new EquatableItemStack(stack); - NetworkItem item = this.networkItems.get(equatable); - if (item != null) { - int remain = stack.getCount(); - for (NetworkLocation location : item.getLocations()) { - int amount = location.getItemAmount(this.world, stack, ItemEqualityType.NBT); - if (amount <= 0) - continue; - amount -= network.getLockedAmount(location.getPos(), stack, ItemEqualityType.NBT); - if (amount > 0) { - if (remain < amount) - amount = remain; - remain -= amount; - while (amount > 0) { - ItemStack copy = stack.copy(); - copy.setCount(Math.min(stack.getMaxStackSize(), amount)); - NetworkLock lock = new NetworkLock(location, copy); - this.pendingRequests.add(lock); - network.createNetworkLock(lock); - amount -= copy.getCount(); - - } - if (remain <= 0) - break; - } - } - return stack.getCount() - remain; - } - return 0; + public int requestItemImpl(ItemStack stack){ + ItemStack remain = stack.copy(); + NetworkItem item = this.networkItems.get(new EquatableItemStack(remain)); + Collection locations = item == null ? Collections.emptyList() : item.getLocations(); + this.existingRequests.addAll(requestItemLater(this.world, this.getConnectedPipe().getPos(), this.pos, remain, locations, this.craftables, ItemEqualityType.NBT)); + return stack.getCount() - remain.getCount(); } protected PlayerEntity[] getLookingPlayers() { @@ -210,15 +187,15 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine @Override public CompoundNBT write(CompoundNBT compound) { compound.put("items", this.items.serializeNBT()); - compound.put("requests", Utility.serializeAll(this.pendingRequests)); + compound.put("requests", Utility.serializeAll(this.existingRequests)); return super.write(compound); } @Override public void read(BlockState state, CompoundNBT compound) { this.items.deserializeNBT(compound.getCompound("items")); - this.pendingRequests.clear(); - this.pendingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new)); + this.existingRequests.clear(); + this.existingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new)); super.read(state, compound); } @@ -232,4 +209,43 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) { return new ItemTerminalContainer(Registry.itemTerminalContainer, window, player, this.pos); } + + public static List requestItemLater(World world, BlockPos destPipe, BlockPos destInventory, ItemStack stack, Collection locations, List> craftables, ItemEqualityType... equalityTypes) { + List requests = new ArrayList<>(); + PipeNetwork network = PipeNetwork.get(world); + // check for existing items + for (NetworkLocation location : locations) { + int amount = location.getItemAmount(world, stack, ItemEqualityType.NBT); + if (amount <= 0) + continue; + amount -= network.getLockedAmount(location.getPos(), stack, ItemEqualityType.NBT); + if (amount > 0) { + if (stack.getCount() < amount) + amount = stack.getCount(); + stack.shrink(amount); + while (amount > 0) { + ItemStack copy = stack.copy(); + copy.setCount(Math.min(stack.getMaxStackSize(), amount)); + NetworkLock lock = new NetworkLock(location, copy); + network.createNetworkLock(lock); + requests.add(lock); + amount -= copy.getCount(); + } + if (stack.isEmpty()) + break; + } + } + // check for craftable items + for (Pair craftable : craftables) { + if (!ItemEqualityType.compareItems(stack, craftable.getRight(), equalityTypes)) + continue; + PipeTileEntity pipe = network.getPipe(craftable.getLeft()); + if (pipe == null) + continue; + stack = pipe.craft(destPipe, destInventory, stack, equalityTypes); + if (stack.isEmpty()) + break; + } + return requests; + } }