Update Auto crafting table to use the better code from the rolling machine, should fix some issues.

This commit is contained in:
modmuss50 2019-03-06 14:06:02 +00:00
parent c1343cdc26
commit 3ca9347212
2 changed files with 180 additions and 187 deletions

View file

@ -82,7 +82,7 @@ public class GuiAutoCrafting extends GuiBase {
@Override @Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
super.drawGuiContainerForegroundLayer(mouseX, mouseY); super.drawGuiContainerForegroundLayer(mouseX, mouseY);
IRecipe recipe = tileAutoCraftingTable.getIRecipe(); IRecipe recipe = tileAutoCraftingTable.findMatchingRecipe(tileAutoCraftingTable.getCraftingInventory());
if (recipe != null) { if (recipe != null) {
renderItemStack(recipe.getRecipeOutput(), 95, 42); renderItemStack(recipe.getRecipeOutput(), 95, 42);
} }

View file

@ -34,7 +34,6 @@ import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.SoundCategory;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import reborncore.api.IToolDrop; import reborncore.api.IToolDrop;
import reborncore.api.tile.IInventoryProvider; import reborncore.api.tile.IInventoryProvider;
@ -47,12 +46,13 @@ import reborncore.client.containerBuilder.IContainerProvider;
import reborncore.client.containerBuilder.builder.BuiltContainer; import reborncore.client.containerBuilder.builder.BuiltContainer;
import reborncore.client.containerBuilder.builder.ContainerBuilder; import reborncore.client.containerBuilder.builder.ContainerBuilder;
import techreborn.init.ModBlocks; import techreborn.init.ModBlocks;
import techreborn.init.ModSounds;
import techreborn.lib.ModInfo; import techreborn.lib.ModInfo;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/** /**
* Created by modmuss50 on 20/06/2017. * Created by modmuss50 on 20/06/2017.
@ -66,14 +66,17 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
@ConfigRegistry(config = "machines", category = "autocrafter", key = "AutoCrafterMaxEnergy", comment = "AutoCrafting Table Max Energy (Value in EU)") @ConfigRegistry(config = "machines", category = "autocrafter", key = "AutoCrafterMaxEnergy", comment = "AutoCrafting Table Max Energy (Value in EU)")
public static int maxEnergy = 10_000; public static int maxEnergy = 10_000;
public int[] craftingSlots = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
private int outputSlot = 9;
public Inventory inventory = new Inventory(11, "TileAutoCraftingTable", 64, this); public Inventory inventory = new Inventory(11, "TileAutoCraftingTable", 64, this);
public int progress; public IRecipe currentRecipe;
public ItemStack currentRecipeOutput;
public int tickTime;
public int maxProgress = 120; public int maxProgress = 120;
public int euTick = 10; public int euTick = 10;
public int balanceSlot = 0;
InventoryCrafting inventoryCrafting = null; InventoryCrafting inventoryCrafting = null;
IRecipe lastCustomRecipe = null;
IRecipe lastRecipe = null;
public boolean locked = true; public boolean locked = true;
@ -81,25 +84,6 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
super(); super();
} }
@Nullable
public IRecipe getIRecipe() {
InventoryCrafting crafting = getCraftingInventory();
if (!crafting.isEmpty()) {
if (lastRecipe != null) {
if (lastRecipe.matches(crafting, world)) {
return lastRecipe;
}
}
for (IRecipe testRecipe : CraftingManager.REGISTRY) {
if (testRecipe.matches(crafting, world)) {
lastRecipe = testRecipe;
return testRecipe;
}
}
}
return null;
}
public InventoryCrafting getCraftingInventory() { public InventoryCrafting getCraftingInventory() {
if (inventoryCrafting == null) { if (inventoryCrafting == null) {
inventoryCrafting = new InventoryCrafting(new Container() { inventoryCrafting = new InventoryCrafting(new Container() {
@ -115,48 +99,24 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
return inventoryCrafting; return inventoryCrafting;
} }
public boolean canMake(IRecipe recipe) { public boolean canMake(InventoryCrafting craftMatrix) {
if (recipe != null && recipe.canFit(3, 3)) { ItemStack stack = findMatchingRecipeOutput(craftMatrix);
boolean missingOutput = false; if (locked) {
int[] stacksInSlots = new int[9]; for (int i = 0; i < craftMatrix.getSizeInventory(); i++) {
for (int i = 0; i < 9; i++) { ItemStack stack1 = craftMatrix.getStackInSlot(i);
stacksInSlots[i] = inventory.getStackInSlot(i).getCount(); if (!stack1.isEmpty() && stack1.getCount() < 2) {
} return false;
for (Ingredient ingredient : recipe.getIngredients()) {
if (ingredient != Ingredient.EMPTY) {
boolean foundIngredient = false;
for (int i = 0; i < 9; i++) {
ItemStack stack = inventory.getStackInSlot(i);
int requiredSize = locked ? 1 : 0;
if (stack.getMaxStackSize() == 1) {
requiredSize = 0;
}
if (stacksInSlots[i] > requiredSize) {
if (ingredient.apply(stack)) {
if (stack.getItem().getContainerItem() != null) {
if (!hasRoomForExtraItem(stack.getItem().getContainerItem(stack))) {
continue;
}
}
foundIngredient = true;
stacksInSlots[i]--;
break;
} }
} }
} }
if (!foundIngredient) { if (stack.isEmpty()) {
missingOutput = true; return false;
} }
} ItemStack output = getStackInSlot(outputSlot);
} if (output.isEmpty()) {
if (!missingOutput) {
if (hasOutputSpace(recipe.getRecipeOutput(), 9)) {
return true; return true;
} }
} return ItemUtils.isItemEqual(stack, output, true, true);
return false;
}
return false;
} }
boolean hasRoomForExtraItem(ItemStack stack) { boolean hasRoomForExtraItem(ItemStack stack) {
@ -180,41 +140,6 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
return false; return false;
} }
public boolean make(IRecipe recipe) {
if (recipe == null || !canMake(recipe)) {
return false;
}
for (int i = 0; i < recipe.getIngredients().size(); i++) {
Ingredient ingredient = recipe.getIngredients().get(i);
// Looks for the best slot to take it from
ItemStack bestSlot = inventory.getStackInSlot(i);
if (ingredient.apply(bestSlot)) {
handleContainerItem(bestSlot);
bestSlot.shrink(1);
} else {
for (int j = 0; j < 9; j++) {
ItemStack stack = inventory.getStackInSlot(j);
if (ingredient.apply(stack)) {
handleContainerItem(stack);
stack.shrink(1); // TODO is this right? or do I need
// to use it as an actull
// crafting grid
break;
}
}
}
}
ItemStack output = inventory.getStackInSlot(9);
// TODO fire forge recipe event
ItemStack ouputStack = recipe.getCraftingResult(getCraftingInventory());
if (output.isEmpty()) {
inventory.setInventorySlotContents(9, ouputStack.copy());
} else {
// TODO use ouputStack in someway?
output.grow(recipe.getRecipeOutput().getCount());
}
return true;
}
private void handleContainerItem(ItemStack stack) { private void handleContainerItem(ItemStack stack) {
if (stack.getItem().hasContainerItem(stack)) { if (stack.getItem().hasContainerItem(stack)) {
@ -241,61 +166,113 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
return false; return false;
} }
public boolean isItemValidForRecipeSlot(IRecipe recipe, ItemStack stack, int slotID) { public Optional<InventoryCrafting> balanceRecipe(InventoryCrafting craftCache) {
if (recipe == null) { if (currentRecipe == null) {
return true; return Optional.empty();
} }
int bestSlot = findBestSlotForStack(recipe, stack); if (world.isRemote) {
if (bestSlot != -1) { return Optional.empty();
return bestSlot == slotID;
} }
return true; if (!locked) {
return Optional.empty();
} }
if (craftCache.isEmpty()) {
public int findBestSlotForStack(IRecipe recipe, ItemStack stack) { return Optional.empty();
if (recipe == null) { }
return -1; balanceSlot++;
if (balanceSlot > craftCache.getSizeInventory()) {
balanceSlot = 0;
}
//Find the best slot for each item in a recipe, and move it if needed
ItemStack sourceStack = inventory.getStackInSlot(balanceSlot);
if (sourceStack.isEmpty()) {
return Optional.empty();
} }
List<Integer> possibleSlots = new ArrayList<>(); List<Integer> possibleSlots = new ArrayList<>();
for (int i = 0; i < recipe.getIngredients().size(); i++) { for (int s = 0; s < currentRecipe.getIngredients().size(); s++) {
ItemStack stackInSlot = inventory.getStackInSlot(i); ItemStack stackInSlot = inventory.getStackInSlot(s);
Ingredient ingredient = recipe.getIngredients().get(i); Ingredient ingredient = currentRecipe.getIngredients().get(s);
if (ingredient != Ingredient.EMPTY && ingredient.apply(stack)) { if (ingredient != Ingredient.EMPTY && ingredient.apply(sourceStack)) {
if (stackInSlot.isEmpty()) { if (stackInSlot.isEmpty()) {
possibleSlots.add(i); possibleSlots.add(s);
} else if (stackInSlot.getItem() == stack.getItem() } else if (stackInSlot.getItem() == sourceStack.getItem() && stackInSlot.getItemDamage() == sourceStack.getItemDamage()) {
&& stackInSlot.getItemDamage() == stack.getItemDamage()) { possibleSlots.add(s);
if (stackInSlot.getMaxStackSize() >= stackInSlot.getCount() + stack.getCount()) {
possibleSlots.add(i);
} }
} }
} }
if(!possibleSlots.isEmpty()){
int totalItems = possibleSlots.stream()
.mapToInt(value -> inventory.getStackInSlot(value).getCount()).sum();
int slots = possibleSlots.size();
//This makes an array of ints with the best possible slot distribution
int[] split = new int[slots];
int remainder = totalItems % slots;
Arrays.fill(split, totalItems / slots);
while (remainder > 0){
for (int i = 0; i < split.length; i++) {
if(remainder > 0){
split[i] +=1;
remainder --;
} }
}
}
List<Integer> slotDistrubution = possibleSlots.stream()
.mapToInt(value -> inventory.getStackInSlot(value).getCount())
.boxed().collect(Collectors.toList());
boolean needsBalance = false;
for (int i = 0; i < split.length; i++) {
int required = split[i];
if(slotDistrubution.contains(required)){
//We need to remove the int, not at the int, this seems to work around that
slotDistrubution.remove(new Integer(required));
} else {
needsBalance = true;
}
}
if (!needsBalance) {
return Optional.empty();
}
} else {
return Optional.empty();
}
//Slot, count //Slot, count
Pair<Integer, Integer> smallestCount = null; Pair<Integer, Integer> bestSlot = null;
for (Integer slot : possibleSlots) { for (Integer slot : possibleSlots) {
ItemStack slotStack = inventory.getStackInSlot(slot); ItemStack slotStack = inventory.getStackInSlot(slot);
if (slotStack.isEmpty()) { if (slotStack.isEmpty()) {
return slot; bestSlot = Pair.of(slot, 0);
} }
if (smallestCount == null) { if (bestSlot == null) {
smallestCount = Pair.of(slot, slotStack.getCount()); bestSlot = Pair.of(slot, slotStack.getCount());
} else if (smallestCount.getRight() >= slotStack.getCount()) { } else if (bestSlot.getRight() >= slotStack.getCount()) {
smallestCount = Pair.of(slot, slotStack.getCount()); bestSlot = Pair.of(slot, slotStack.getCount());
} }
} }
if (smallestCount != null) { if (bestSlot == null
return smallestCount.getLeft(); || bestSlot.getLeft() == balanceSlot
|| bestSlot.getRight() == sourceStack.getCount()
|| inventory.getStackInSlot(bestSlot.getLeft()).isEmpty()
|| !ItemUtils.isItemEqual(sourceStack, inventory.getStackInSlot(bestSlot.getLeft()), true, true, true)) {
return Optional.empty();
} }
return -1; sourceStack.shrink(1);
inventory.getStackInSlot(bestSlot.getLeft()).grow(1);
inventory.hasChanged = true;
return Optional.of(getCraftingInventory());
} }
public int getProgress() { public int getProgress() {
return progress; return tickTime;
} }
public void setProgress(int progress) { public void setProgress(int progress) {
this.progress = progress; this.tickTime = progress;
} }
public int getMaxProgress() { public int getMaxProgress() {
@ -309,6 +286,19 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
this.maxProgress = maxProgress; this.maxProgress = maxProgress;
} }
public IRecipe findMatchingRecipe(InventoryCrafting crafting){
for (IRecipe testRecipe : CraftingManager.REGISTRY) {
if (testRecipe.matches(crafting, world)) {
return testRecipe;
}
}
return null;
}
public ItemStack findMatchingRecipeOutput(InventoryCrafting crafting){
return findMatchingRecipe(crafting).getRecipeOutput();
}
// TilePowerAcceptor // TilePowerAcceptor
@Override @Override
public void update() { public void update() {
@ -316,29 +306,64 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
if (world.isRemote) { if (world.isRemote) {
return; return;
} }
IRecipe recipe = getIRecipe(); charge(10);
if (recipe != null) {
if (progress >= maxProgress) { InventoryCrafting craftMatrix = getCraftingInventory();
if (make(recipe)) { currentRecipe = findMatchingRecipe(craftMatrix);
progress = 0; if (currentRecipe != null) {
if (world.getTotalWorldTime() % 2 == 0) {
Optional<InventoryCrafting> balanceResult = balanceRecipe(craftMatrix);
if (balanceResult.isPresent()) {
craftMatrix = balanceResult.get();
}
}
currentRecipeOutput = currentRecipe.getCraftingResult(craftMatrix);
} else {
currentRecipeOutput = ItemStack.EMPTY;
}
if (!currentRecipeOutput.isEmpty() && canMake(craftMatrix)) {
if (tickTime >= Math.max((int) (maxProgress * (1.0 - getSpeedMultiplier())), 1)) {
currentRecipeOutput = findMatchingRecipeOutput(craftMatrix);
if (!currentRecipeOutput.isEmpty()) {
boolean hasCrafted = false;
if (inventory.getStackInSlot(outputSlot).isEmpty()) {
inventory.setInventorySlotContents(outputSlot, currentRecipeOutput);
tickTime = 0;
hasCrafted = true;
} else {
if (inventory.getStackInSlot(outputSlot).getCount()
+ currentRecipeOutput.getCount() <= currentRecipeOutput.getMaxStackSize()) {
final ItemStack stack = inventory.getStackInSlot(outputSlot);
stack.setCount(stack.getCount() + currentRecipeOutput.getCount());
inventory.setInventorySlotContents(outputSlot, stack);
tickTime = 0;
hasCrafted = true;
}
}
if (hasCrafted) {
for (int i = 0; i < craftMatrix.getSizeInventory(); i++) {
inventory.decrStackSize(i, 1);
}
currentRecipeOutput = ItemStack.EMPTY;
currentRecipe = null;
}
}
} }
} else { } else {
if (canMake(recipe)) { tickTime = 0;
if (canUseEnergy(euTick)) {
progress++;
if (progress == 1) {
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), ModSounds.AUTO_CRAFTING,
SoundCategory.BLOCKS, 0.3F, 0.8F);
} }
useEnergy(euTick); if (!currentRecipeOutput.isEmpty()) {
} if (canUseEnergy(getEuPerTick(euTick))
} else { && tickTime < Math.max((int) (maxProgress * (1.0 - getSpeedMultiplier())), 1)
progress = 0; && canMake(craftMatrix)) {
useEnergy(getEuPerTick(euTick));
tickTime++;
} }
} }
} if (currentRecipeOutput.isEmpty()) {
if (recipe == null) { tickTime = 0;
progress = 0; currentRecipe = null;
} }
} }
@ -393,42 +418,9 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
// TileLegacyMachineBase // TileLegacyMachineBase
@Override @Override
public boolean canBeUpgraded() { public boolean canBeUpgraded() {
return false;
}
@Override
public boolean isItemValidForSlot(int index, ItemStack stack) {
int bestSlot = findBestSlotForStack(getIRecipe(), stack);
if (bestSlot != -1) {
return index == bestSlot;
}
return super.isItemValidForSlot(index, stack);
}
@Override
public int[] getSlotsForFace(EnumFacing side) {
return new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
}
@Override
public boolean canInsertItem(int index, ItemStack stack, EnumFacing direction) {
if (index > 8) {
return false;
}
int bestSlot = findBestSlotForStack(getIRecipe(), stack);
if (bestSlot != -1) {
return index == bestSlot;
}
return true; return true;
} }
@Override
public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction) {
if (index > 8) {
return true;
}
return false;
}
// This machine doesnt have a facing // This machine doesnt have a facing
@Override @Override
@ -454,6 +446,7 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
return new ContainerBuilder("autocraftingtable").player(player.inventory).inventory().hotbar().addInventory() return new ContainerBuilder("autocraftingtable").player(player.inventory).inventory().hotbar().addInventory()
.tile(this).slot(0, 28, 25).slot(1, 46, 25).slot(2, 64, 25).slot(3, 28, 43).slot(4, 46, 43) .tile(this).slot(0, 28, 25).slot(1, 46, 25).slot(2, 64, 25).slot(3, 28, 43).slot(4, 46, 43)
.slot(5, 64, 43).slot(6, 28, 61).slot(7, 46, 61).slot(8, 64, 61).outputSlot(9, 145, 42) .slot(5, 64, 43).slot(6, 28, 61).slot(7, 46, 61).slot(8, 64, 61).outputSlot(9, 145, 42)
.onCraft(inv -> this.inventory.setInventorySlotContents(1, findMatchingRecipeOutput(getCraftingInventory())))
.outputSlot(10, 145, 70).syncEnergyValue().syncIntegerValue(this::getProgress, this::setProgress) .outputSlot(10, 145, 70).syncEnergyValue().syncIntegerValue(this::getProgress, this::setProgress)
.syncIntegerValue(this::getMaxProgress, this::setMaxProgress) .syncIntegerValue(this::getMaxProgress, this::setMaxProgress)
.syncIntegerValue(this::getLockedInt, this::setLockedInt).addInventory().create(this); .syncIntegerValue(this::getLockedInt, this::setLockedInt).addInventory().create(this);
@ -461,6 +454,6 @@ public class TileAutoCraftingTable extends TilePowerAcceptor
@Override @Override
public boolean hasSlotConfig() { public boolean hasSlotConfig() {
return false; return true;
} }
} }