mirror of
https://github.com/Ellpeck/PrettyPipes.git
synced 2024-11-22 19:58:35 +01:00
part 2: actual crafting implementation
This commit is contained in:
parent
8029cc21a0
commit
57c3b13b64
9 changed files with 251 additions and 94 deletions
|
@ -1,10 +1,12 @@
|
||||||
package de.ellpeck.prettypipes.items;
|
package de.ellpeck.prettypipes.items;
|
||||||
|
|
||||||
|
import de.ellpeck.prettypipes.misc.ItemEqualityType;
|
||||||
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
||||||
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
|
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraftforge.items.IItemHandler;
|
import net.minecraftforge.items.IItemHandler;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -32,4 +34,6 @@ public interface IModule {
|
||||||
boolean canPipeWork(ItemStack module, PipeTileEntity tile);
|
boolean canPipeWork(ItemStack module, PipeTileEntity tile);
|
||||||
|
|
||||||
List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile);
|
List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile);
|
||||||
|
|
||||||
|
ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package de.ellpeck.prettypipes.items;
|
||||||
|
|
||||||
import de.ellpeck.prettypipes.Registry;
|
import de.ellpeck.prettypipes.Registry;
|
||||||
import de.ellpeck.prettypipes.Utility;
|
import de.ellpeck.prettypipes.Utility;
|
||||||
|
import de.ellpeck.prettypipes.misc.ItemEqualityType;
|
||||||
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
||||||
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
|
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
|
||||||
import net.minecraft.client.util.ITooltipFlag;
|
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.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.*;
|
import net.minecraft.util.text.*;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
@ -79,4 +81,9 @@ public abstract class ModuleItem extends Item implements IModule {
|
||||||
public List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile) {
|
public List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class ItemFilter extends ItemStackHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFiltered(ItemStack stack) {
|
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
|
// also check if any filter increase modules have the item we need
|
||||||
for (ItemStackHandler handler : this.getAllFilters()) {
|
for (ItemStackHandler handler : this.getAllFilters()) {
|
||||||
for (int i = 0; i < handler.getSlots(); i++) {
|
for (int i = 0; i < handler.getSlots(); i++) {
|
||||||
|
@ -132,14 +132,6 @@ public class ItemFilter extends ItemStackHandler {
|
||||||
return filters;
|
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() {
|
public void save() {
|
||||||
if (this.modified) {
|
if (this.modified) {
|
||||||
this.stack.getOrCreateTag().put("filter", this.serializeNBT());
|
this.stack.getOrCreateTag().put("filter", this.serializeNBT());
|
||||||
|
@ -167,6 +159,14 @@ public class ItemFilter extends ItemStackHandler {
|
||||||
this.modified = true;
|
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 {
|
public interface IFilteredContainer {
|
||||||
ItemFilter getFilter();
|
ItemFilter getFilter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,14 +190,14 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
|
||||||
return stack;
|
return stack;
|
||||||
ItemStack remain = stack.copy();
|
ItemStack remain = stack.copy();
|
||||||
for (NetworkLocation location : locations) {
|
for (NetworkLocation location : locations) {
|
||||||
remain = this.requestItem(location, destPipe, destInventory, remain, equalityTypes);
|
remain = this.requestExistingItem(location, destPipe, destInventory, remain, equalityTypes);
|
||||||
if (remain.isEmpty())
|
if (remain.isEmpty())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return remain;
|
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))
|
if (location.getPos().equals(destInventory))
|
||||||
return stack;
|
return stack;
|
||||||
ItemStack remain = stack.copy();
|
ItemStack remain = stack.copy();
|
||||||
|
|
|
@ -4,6 +4,9 @@ import de.ellpeck.prettypipes.PrettyPipes;
|
||||||
import de.ellpeck.prettypipes.Registry;
|
import de.ellpeck.prettypipes.Registry;
|
||||||
import de.ellpeck.prettypipes.Utility;
|
import de.ellpeck.prettypipes.Utility;
|
||||||
import de.ellpeck.prettypipes.items.IModule;
|
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.PipeItem;
|
||||||
import de.ellpeck.prettypipes.network.PipeNetwork;
|
import de.ellpeck.prettypipes.network.PipeNetwork;
|
||||||
import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer;
|
import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer;
|
||||||
|
@ -57,6 +60,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
public final Queue<NetworkLock> craftIngredientRequests = new ArrayDeque<>();
|
||||||
public PressurizerTileEntity pressurizer;
|
public PressurizerTileEntity pressurizer;
|
||||||
public int moduleDropCheck;
|
public int moduleDropCheck;
|
||||||
protected List<PipeItem> items;
|
protected List<PipeItem> items;
|
||||||
|
@ -75,6 +79,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public CompoundNBT write(CompoundNBT compound) {
|
||||||
compound.put("modules", this.modules.serializeNBT());
|
compound.put("modules", this.modules.serializeNBT());
|
||||||
compound.putInt("module_drop_check", this.moduleDropCheck);
|
compound.putInt("module_drop_check", this.moduleDropCheck);
|
||||||
|
compound.put("requests", Utility.serializeAll(this.craftIngredientRequests));
|
||||||
return super.write(compound);
|
return super.write(compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +87,8 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
public void read(BlockState state, CompoundNBT compound) {
|
public void read(BlockState state, CompoundNBT compound) {
|
||||||
this.modules.deserializeNBT(compound.getCompound("modules"));
|
this.modules.deserializeNBT(compound.getCompound("modules"));
|
||||||
this.moduleDropCheck = compound.getInt("module_drop_check");
|
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);
|
super.read(state, compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +140,26 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
PipeNetwork.get(this.world).clearDestinationCache(this.pos);
|
PipeNetwork.get(this.world).clearDestinationCache(this.pos);
|
||||||
}
|
}
|
||||||
profiler.endSection();
|
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<BlockPos, ItemStack> 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");
|
profiler.startSection("ticking_items");
|
||||||
|
@ -238,6 +265,17 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ItemStack craft(BlockPos destPipe, BlockPos destInventory, ItemStack stack, ItemEqualityType... equalityTypes) {
|
||||||
|
Iterator<Pair<ItemStack, IModule>> modules = this.streamModules().iterator();
|
||||||
|
while (modules.hasNext()) {
|
||||||
|
Pair<ItemStack, IModule> 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) {
|
public IItemHandler getItemHandler(Direction dir, PipeItem item) {
|
||||||
if (!this.isConnected(dir))
|
if (!this.isConnected(dir))
|
||||||
return null;
|
return null;
|
||||||
|
@ -301,6 +339,9 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
|
||||||
public void remove() {
|
public void remove() {
|
||||||
super.remove();
|
super.remove();
|
||||||
this.getItems().clear();
|
this.getItems().clear();
|
||||||
|
PipeNetwork network = PipeNetwork.get(this.world);
|
||||||
|
for (NetworkLock lock : this.craftIngredientRequests)
|
||||||
|
network.resolveNetworkLock(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,13 +4,23 @@ import de.ellpeck.prettypipes.Registry;
|
||||||
import de.ellpeck.prettypipes.items.IModule;
|
import de.ellpeck.prettypipes.items.IModule;
|
||||||
import de.ellpeck.prettypipes.items.ModuleItem;
|
import de.ellpeck.prettypipes.items.ModuleItem;
|
||||||
import de.ellpeck.prettypipes.items.ModuleTier;
|
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.PipeTileEntity;
|
||||||
import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer;
|
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.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraftforge.items.ItemStackHandler;
|
import net.minecraftforge.items.ItemStackHandler;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -43,14 +53,60 @@ public class CraftingModuleItem extends ModuleItem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile) {
|
public List<ItemStack> getCraftables(ItemStack module, PipeTileEntity tile) {
|
||||||
|
PipeNetwork network = PipeNetwork.get(tile.getWorld());
|
||||||
|
List<NetworkLocation> items = network.getOrderedNetworkItems(tile.getPos());
|
||||||
|
List<Pair<BlockPos, ItemStack>> craftables = network.getOrderedCraftables(tile.getPos());
|
||||||
|
ItemEqualityType[] equalityTypes = ItemFilter.getEqualityTypes(tile);
|
||||||
|
|
||||||
ItemStackHandler output = this.getOutput(module);
|
ItemStackHandler output = this.getOutput(module);
|
||||||
List<ItemStack> items = new ArrayList<>();
|
ItemStackHandler input = this.getInput(module);
|
||||||
|
|
||||||
|
List<ItemStack> ret = new ArrayList<>();
|
||||||
for (int i = 0; i < output.getSlots(); i++) {
|
for (int i = 0; i < output.getSlots(); i++) {
|
||||||
ItemStack stack = output.getStackInSlot(i);
|
ItemStack stack = output.getStackInSlot(i);
|
||||||
if (!stack.isEmpty())
|
if (!stack.isEmpty()) {
|
||||||
items.add(stack);
|
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<ItemStack> 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<NetworkLocation> items = network.getOrderedNetworkItems(tile.getPos());
|
||||||
|
List<Pair<BlockPos, ItemStack>> 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<NetworkLock> 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) {
|
public ItemStackHandler getInput(ItemStack module) {
|
||||||
|
@ -74,4 +130,15 @@ public class CraftingModuleItem extends ModuleItem {
|
||||||
if (output != null)
|
if (output != null)
|
||||||
tag.put("output", output.serializeNBT());
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class RetrievalModuleItem extends ModuleItem {
|
||||||
Pair<BlockPos, ItemStack> dest = tile.getAvailableDestination(copy, true, this.preventOversending);
|
Pair<BlockPos, ItemStack> dest = tile.getAvailableDestination(copy, true, this.preventOversending);
|
||||||
if (dest == null)
|
if (dest == null)
|
||||||
continue;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,13 @@ import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.inventory.container.Container;
|
import net.minecraft.inventory.container.Container;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.Style;
|
import net.minecraft.util.text.Style;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.util.text.TranslationTextComponent;
|
import net.minecraft.util.text.TranslationTextComponent;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.items.IItemHandler;
|
||||||
import net.minecraftforge.items.ItemStackHandler;
|
import net.minecraftforge.items.ItemStackHandler;
|
||||||
import org.apache.commons.lang3.mutable.MutableInt;
|
import org.apache.commons.lang3.mutable.MutableInt;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
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.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class CraftingTerminalTileEntity extends ItemTerminalTileEntity {
|
public class CraftingTerminalTileEntity extends ItemTerminalTileEntity {
|
||||||
|
|
||||||
|
@ -97,45 +103,11 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity {
|
||||||
PipeNetwork network = PipeNetwork.get(this.world);
|
PipeNetwork network = PipeNetwork.get(this.world);
|
||||||
network.startProfile("terminal_request_crafting");
|
network.startProfile("terminal_request_crafting");
|
||||||
this.updateItems();
|
this.updateItems();
|
||||||
|
// get the amount of crafts that we can do
|
||||||
// the highest amount we can craft with the items we have
|
int lowestAvailable = getAvailableCrafts(this.world, this.craftItems.getSlots(), this::getRequestedCraftItem, this::isGhostItem, s -> {
|
||||||
int lowestAvailable = Integer.MAX_VALUE;
|
NetworkItem item = this.networkItems.get(s);
|
||||||
// this is the amount of items required for each ingredient when crafting ONE
|
return item != null ? item.getLocations() : Collections.emptyList();
|
||||||
Map<EquatableItemStack, MutableInt> requiredItems = new HashMap<>();
|
}, this.craftables, s -> player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", s.getDisplayName()).setStyle(Style.EMPTY.setFormatting(TextFormatting.RED)), UUID.randomUUID()), ItemEqualityType.NBT);
|
||||||
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<EquatableItemStack, MutableInt> 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());
|
|
||||||
}
|
|
||||||
if (lowestAvailable > 0) {
|
if (lowestAvailable > 0) {
|
||||||
// if we're limiting the amount, pretend we only have that amount available
|
// if we're limiting the amount, pretend we only have that amount available
|
||||||
if (maxAmount < lowestAvailable)
|
if (maxAmount < lowestAvailable)
|
||||||
|
@ -175,4 +147,54 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity {
|
||||||
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
|
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
|
||||||
return new CraftingTerminalContainer(Registry.craftingTerminalContainer, window, player, this.pos);
|
return new CraftingTerminalContainer(Registry.craftingTerminalContainer, window, player, this.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getAvailableCrafts(World world, int slots, Function<Integer, ItemStack> inputFunction, Predicate<Integer> isGhost, Function<EquatableItemStack, Collection<NetworkLocation>> locationsFunction, List<Pair<BlockPos, ItemStack>> craftables, Consumer<ItemStack> 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<EquatableItemStack, MutableInt> 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<EquatableItemStack, MutableInt> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.Style;
|
import net.minecraft.util.text.Style;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.util.text.TranslationTextComponent;
|
import net.minecraft.util.text.TranslationTextComponent;
|
||||||
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.common.util.Constants;
|
import net.minecraftforge.common.util.Constants;
|
||||||
import net.minecraftforge.common.util.Constants.NBT;
|
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.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ItemTerminalTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
|
public class ItemTerminalTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
|
||||||
|
@ -52,7 +54,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
};
|
};
|
||||||
public Map<EquatableItemStack, NetworkItem> networkItems;
|
public Map<EquatableItemStack, NetworkItem> networkItems;
|
||||||
public List<Pair<BlockPos, ItemStack>> craftables;
|
public List<Pair<BlockPos, ItemStack>> craftables;
|
||||||
private final Queue<NetworkLock> pendingRequests = new ArrayDeque<>();
|
private final Queue<NetworkLock> existingRequests = new ArrayDeque<>();
|
||||||
|
|
||||||
protected ItemTerminalTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
protected ItemTerminalTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||||
super(tileEntityTypeIn);
|
super(tileEntityTypeIn);
|
||||||
|
@ -85,10 +87,10 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.pendingRequests.isEmpty()) {
|
if (!this.existingRequests.isEmpty()) {
|
||||||
NetworkLock request = this.pendingRequests.remove();
|
NetworkLock request = this.existingRequests.remove();
|
||||||
network.resolveNetworkLock(request);
|
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;
|
update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +106,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
public void remove() {
|
public void remove() {
|
||||||
super.remove();
|
super.remove();
|
||||||
PipeNetwork network = PipeNetwork.get(this.world);
|
PipeNetwork network = PipeNetwork.get(this.world);
|
||||||
for (NetworkLock lock : this.pendingRequests)
|
for (NetworkLock lock : this.existingRequests)
|
||||||
network.resolveNetworkLock(lock);
|
network.resolveNetworkLock(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,37 +153,12 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
network.endProfile();
|
network.endProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int requestItemImpl(ItemStack stack) {
|
public int requestItemImpl(ItemStack stack){
|
||||||
PipeNetwork network = PipeNetwork.get(this.world);
|
ItemStack remain = stack.copy();
|
||||||
EquatableItemStack equatable = new EquatableItemStack(stack);
|
NetworkItem item = this.networkItems.get(new EquatableItemStack(remain));
|
||||||
NetworkItem item = this.networkItems.get(equatable);
|
Collection<NetworkLocation> locations = item == null ? Collections.emptyList() : item.getLocations();
|
||||||
if (item != null) {
|
this.existingRequests.addAll(requestItemLater(this.world, this.getConnectedPipe().getPos(), this.pos, remain, locations, this.craftables, ItemEqualityType.NBT));
|
||||||
int remain = stack.getCount();
|
return stack.getCount() - remain.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PlayerEntity[] getLookingPlayers() {
|
protected PlayerEntity[] getLookingPlayers() {
|
||||||
|
@ -210,15 +187,15 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public CompoundNBT write(CompoundNBT compound) {
|
||||||
compound.put("items", this.items.serializeNBT());
|
compound.put("items", this.items.serializeNBT());
|
||||||
compound.put("requests", Utility.serializeAll(this.pendingRequests));
|
compound.put("requests", Utility.serializeAll(this.existingRequests));
|
||||||
return super.write(compound);
|
return super.write(compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(BlockState state, CompoundNBT compound) {
|
public void read(BlockState state, CompoundNBT compound) {
|
||||||
this.items.deserializeNBT(compound.getCompound("items"));
|
this.items.deserializeNBT(compound.getCompound("items"));
|
||||||
this.pendingRequests.clear();
|
this.existingRequests.clear();
|
||||||
this.pendingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new));
|
this.existingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new));
|
||||||
super.read(state, compound);
|
super.read(state, compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,4 +209,43 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
|
||||||
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
|
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
|
||||||
return new ItemTerminalContainer(Registry.itemTerminalContainer, window, player, this.pos);
|
return new ItemTerminalContainer(Registry.itemTerminalContainer, window, player, this.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<NetworkLock> requestItemLater(World world, BlockPos destPipe, BlockPos destInventory, ItemStack stack, Collection<NetworkLocation> locations, List<Pair<BlockPos, ItemStack>> craftables, ItemEqualityType... equalityTypes) {
|
||||||
|
List<NetworkLock> 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<BlockPos, ItemStack> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue