aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java33
-rw-r--r--src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java212
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java39
3 files changed, 241 insertions, 43 deletions
diff --git a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java
index bcf205611e..469f2d64a1 100644
--- a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java
+++ b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java
@@ -17,14 +17,15 @@ import java.util.Map;
/** Used by machines that are locked to a single recipe, for fast computation. */
public class GT_Single_Recipe_Check {
- private final GT_MetaTileEntity_MultiBlockBase multiBlockBase;
- private final GT_Recipe recipe;
- private final ImmutableMap<ItemId, Integer> itemCost;
- private final ImmutableMap<Fluid, Integer> fluidCost;
- private final int totalItemCost;
- private final int totalFluidCost;
-
- private GT_Single_Recipe_Check(
+ protected final GT_MetaTileEntity_MultiBlockBase multiBlockBase;
+ protected final GT_Recipe recipe;
+ protected final ImmutableMap<ItemId, Integer> itemCost;
+ protected final ImmutableMap<Fluid, Integer> fluidCost;
+
+ protected final int totalItemCost;
+ protected final int totalFluidCost;
+
+ protected GT_Single_Recipe_Check(
GT_MetaTileEntity_MultiBlockBase multiBlockBase,
GT_Recipe recipe,
ImmutableMap<ItemId, Integer> itemCost,
@@ -176,7 +177,7 @@ public class GT_Single_Recipe_Check {
return true;
}
- private static Map<ItemId, Integer> buildItemMap(
+ protected static Map<ItemId, Integer> buildItemMap(
GT_MetaTileEntity_MultiBlockBase multiBlockBase) {
Map<ItemId, Integer> itemMap = new HashMap<>();
for (ItemStack itemStack : multiBlockBase.getStoredInputs()) {
@@ -185,7 +186,7 @@ public class GT_Single_Recipe_Check {
return itemMap;
}
- private static Map<Fluid, Integer> buildFluidMap(
+ protected static Map<Fluid, Integer> buildFluidMap(
GT_MetaTileEntity_MultiBlockBase multiBlockBase) {
Map<Fluid, Integer> fluidMap = new HashMap<>();
for (FluidStack fluidStack : multiBlockBase.getStoredFluids()) {
@@ -256,9 +257,9 @@ public class GT_Single_Recipe_Check {
}
@AutoValue
- abstract static class ItemId {
+ protected abstract static class ItemId {
/** This method copies NBT, as it is mutable. */
- private static ItemId create(ItemStack itemStack) {
+ protected static ItemId create(ItemStack itemStack) {
NBTTagCompound nbt = itemStack.getTagCompound();
if (nbt != null) {
nbt = (NBTTagCompound) nbt.copy();
@@ -269,15 +270,15 @@ public class GT_Single_Recipe_Check {
}
/** This method does not copy NBT in order to save time. Make sure not to mutate it! */
- private static ItemId createNoCopy(ItemStack itemStack) {
+ protected static ItemId createNoCopy(ItemStack itemStack) {
return new AutoValue_GT_Single_Recipe_Check_ItemId(
itemStack.getItem(), itemStack.getItemDamage(), itemStack.getTagCompound());
}
- abstract Item item();
- abstract int metaData();
+ protected abstract Item item();
+ protected abstract int metaData();
@Nullable
- abstract NBTTagCompound nbt();
+ protected abstract NBTTagCompound nbt();
}
}
diff --git a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java
new file mode 100644
index 0000000000..225e0bd723
--- /dev/null
+++ b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java
@@ -0,0 +1,212 @@
+package gregtech.api.util;
+
+import com.google.common.collect.ImmutableMap;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** Processing Array-specialized version of {@link gregtech.api.util.GT_Single_Recipe_Check}. */
+public class GT_Single_Recipe_Check_Processing_Array extends GT_Single_Recipe_Check {
+ protected final int recipeAmperage;
+
+ /**
+ * The machine type that the locked recipe is for.
+ * We will not allow running with other machines.
+ */
+ protected final ItemStack machineStack;
+
+ protected GT_Single_Recipe_Check_Processing_Array(
+ GT_MetaTileEntity_MultiBlockBase multiBlockBase,
+ GT_Recipe recipe,
+ ImmutableMap<ItemId, Integer> itemCost,
+ ImmutableMap<Fluid, Integer> fluidCost,
+ int recipeAmperage,
+ ItemStack machineStack) {
+ super(multiBlockBase, recipe, itemCost, fluidCost);
+
+ this.recipeAmperage = recipeAmperage;
+ this.machineStack = machineStack;
+ }
+
+ public int getRecipeAmperage() {
+ return recipeAmperage;
+ }
+
+ @Override
+ public boolean checkRecipeInputsSingleStack(boolean consumeInputs) {
+ throw new UnsupportedOperationException("Use checkRecipeInputs(boolean, int) instead.");
+ }
+
+ @Override
+ public boolean checkRecipeInputs(boolean consumeInputs) {
+ throw new UnsupportedOperationException("Use checkRecipeInputs(boolean, int) instead.");
+ }
+
+ /** Returns the number of parallel recipes, or 0 if recipe is not satisfied at all. */
+ public int checkRecipeInputs(boolean consumeInputs, int maxParallel) {
+ if (!GT_Utility.areStacksEqual(machineStack, multiBlockBase.mInventory[1])) {
+ // Machine stack was modified. This is not allowed, so stop processing.
+ return 0;
+ }
+ int parallel = maxParallel;
+
+ List<ItemStack> items = null;
+ if (totalItemCost > 0) {
+ items = multiBlockBase.getStoredInputs();
+
+ Map<ItemId, Integer> itemMap = new HashMap<>();
+ for (ItemStack itemStack : items) {
+ itemMap.merge(ItemId.createNoCopy(itemStack), itemStack.stackSize, Integer::sum);
+ }
+
+ for (Map.Entry<ItemId, Integer> entry : itemCost.entrySet()) {
+ parallel = Math.min(parallel, itemMap.getOrDefault(entry.getKey(), 0) / entry.getValue());
+ if (parallel <= 0) {
+ return 0;
+ }
+ }
+ }
+
+ List<FluidStack> fluids = null;
+ if (totalFluidCost > 0) {
+ fluids = multiBlockBase.getStoredFluids();
+
+ Map<Fluid, Integer> fluidMap = new HashMap<>();
+ for (FluidStack fluidStack : fluids) {
+ fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum);
+ }
+
+ for (Map.Entry<Fluid, Integer> entry : fluidCost.entrySet()) {
+ parallel = Math.min(parallel, fluidMap.getOrDefault(entry.getKey(), 0) / entry.getValue());
+ if (parallel <= 0) {
+ return 0;
+ }
+ }
+ }
+
+ final int finalParallel = parallel;
+ if (consumeInputs) {
+ if (totalItemCost > 0) {
+ int remainingItemCost = totalItemCost * finalParallel;
+ Map<ItemId, Integer> runningItemCost =
+ itemCost.entrySet().stream()
+ .collect(
+ Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue() * finalParallel));
+
+ for (ItemStack itemStack : items) {
+ ItemId key = ItemId.createNoCopy(itemStack);
+ int runningCost = runningItemCost.getOrDefault(key, 0);
+ int paid = Math.min(itemStack.stackSize, runningCost);
+ itemStack.stackSize -= paid;
+ runningItemCost.put(key, runningCost - paid);
+
+ remainingItemCost -= paid;
+ if (remainingItemCost <= 0) {
+ break;
+ }
+ }
+ }
+
+ if (totalFluidCost > 0) {
+ int remainingFluidCost = totalFluidCost * finalParallel;
+ Map<Fluid, Integer> runningFluidCost =
+ fluidCost.entrySet().stream()
+ .collect(
+ Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue() * finalParallel));
+
+ for (FluidStack fluidStack : fluids) {
+ Fluid key = fluidStack.getFluid();
+ int runningCost = runningFluidCost.getOrDefault(key, 0);
+ int paid = Math.min(fluidStack.amount, runningCost);
+ fluidStack.amount -= paid;
+ runningFluidCost.put(key, runningCost - paid);
+
+ remainingFluidCost -= paid;
+ if (remainingFluidCost <= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ return finalParallel;
+ }
+
+ public static Builder processingArrayBuilder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) {
+ return new Builder(multiBlockBase);
+ }
+
+ public static final class Builder {
+ private final GT_MetaTileEntity_MultiBlockBase multiBlockBase;
+
+ // In order to compute which items and fluids are consumed by the recipe, we compare the
+ // multi-block's items and fluids before and after inputs are consumed by the recipe.
+ private Map<ItemId, Integer> beforeItems;
+ private Map<Fluid, Integer> beforeFluids;
+ private Map<ItemId, Integer> afterItems;
+ private Map<Fluid, Integer> afterFluids;
+
+ private GT_Recipe recipe;
+ private int recipeAmperage;
+
+ private Builder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) {
+ this.multiBlockBase = multiBlockBase;
+ }
+
+ /** Call this before inputs are consumed by the recipe. */
+ public Builder setBefore() {
+ beforeItems = buildItemMap(multiBlockBase);
+ beforeFluids = buildFluidMap(multiBlockBase);
+ return this;
+ }
+
+ /** Call this after inputs are consumed by the recipe. */
+ public Builder setAfter() {
+ afterItems = buildItemMap(multiBlockBase);
+ afterFluids = buildFluidMap(multiBlockBase);
+ return this;
+ }
+
+ public Builder setRecipe(GT_Recipe recipe) {
+ this.recipe = recipe;
+ return this;
+ }
+
+ public Builder setRecipeAmperage(int recipeAmperage) {
+ this.recipeAmperage = recipeAmperage;
+ return this;
+ }
+
+ public GT_Single_Recipe_Check_Processing_Array build() {
+ ImmutableMap.Builder<ItemId, Integer> itemCostBuilder = ImmutableMap.builder();
+ for (Map.Entry<ItemId, Integer> entry : beforeItems.entrySet()) {
+ int cost = entry.getValue() - afterItems.getOrDefault(entry.getKey(), 0);
+ if (cost > 0) {
+ itemCostBuilder.put(entry.getKey(), cost);
+ }
+ }
+
+ ImmutableMap.Builder<Fluid, Integer> fluidCostBuilder = ImmutableMap.builder();
+ for (Map.Entry<Fluid, Integer> entry : beforeFluids.entrySet()) {
+ int cost = entry.getValue() - afterFluids.getOrDefault(entry.getKey(), 0);
+ if (cost > 0) {
+ fluidCostBuilder.put(entry.getKey(), cost);
+ }
+ }
+
+ return new GT_Single_Recipe_Check_Processing_Array(
+ multiBlockBase, recipe, itemCostBuilder.build(), fluidCostBuilder.build(),
+ recipeAmperage, multiBlockBase.mInventory[1].copy());
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java
index d5649ab0e4..a48f63c60a 100644
--- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java
@@ -19,7 +19,7 @@ import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
import gregtech.api.util.GT_ProcessingArray_Manager;
import gregtech.api.util.GT_Recipe;
import gregtech.api.util.GT_Recipe.GT_Recipe_Map;
-import gregtech.api.util.GT_Single_Recipe_Check;
+import gregtech.api.util.GT_Single_Recipe_Check_Processing_Array;
import gregtech.api.util.GT_Utility;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
@@ -51,12 +51,6 @@ public class GT_MetaTileEntity_ProcessingArray extends GT_MetaTileEntity_CubicMu
private boolean mSeparate = false;
private String mMachineName = "";
- /** If locked to a single recipe, the locked recipe's amperage. */
- private int mSingleRecipeAmperage;
-
- /** If locked to a single recipe, the single-block machines that were used to run that single recipe. */
- private ItemStack mSingleRecipeMachineStack;
-
public GT_MetaTileEntity_ProcessingArray(int aID, String aName, String aNameRegional) {
super(aID, aName, aNameRegional);
}
@@ -245,24 +239,12 @@ public class GT_MetaTileEntity_ProcessingArray extends GT_MetaTileEntity_CubicMu
}
public boolean processLockedRecipe() {
- if (!GT_Utility.areStacksEqual(mSingleRecipeMachineStack, mInventory[1])) {
- // Machine stack was modified. This is not allowed, so stop processing.
- return false;
- }
+ GT_Single_Recipe_Check_Processing_Array tSingleRecipeCheck = (GT_Single_Recipe_Check_Processing_Array) mSingleRecipeCheck;
int machines = Math.min(64, mInventory[1].stackSize << mMult); //Upped max Cap to 64
- int i = 0;
- for (; i < machines; i++) {
- // TODO we should create a separate single recipe check class just for PAs.
- // This class can memorize the amperage and machine stack for us, as well as compute
- // the max number of runs in a single iteration over the inputs, rather than requiring
- // one iteration per machine in the stack. But let's do that after we've tested this.
- if (!mSingleRecipeCheck.checkRecipeInputs(true)) {
- break;
- }
- }
+ int parallel = tSingleRecipeCheck.checkRecipeInputs(true, machines);
- return processRecipeOutputs(mSingleRecipeCheck.getRecipe(), mSingleRecipeAmperage, i);
+ return processRecipeOutputs(tSingleRecipeCheck.getRecipe(), tSingleRecipeCheck.getRecipeAmperage(), parallel);
}
public boolean processRecipe(ItemStack[] tInputs, FluidStack[] tFluids, GT_Recipe.GT_Recipe_Map map) {
@@ -273,11 +255,11 @@ public class GT_MetaTileEntity_ProcessingArray extends GT_MetaTileEntity_CubicMu
!isValidForLowGravity(tRecipe, getBaseMetaTileEntity().getWorld().provider.dimensionId))
return false;
- GT_Single_Recipe_Check.Builder tSingleRecipeCheckBuilder = null;
+ GT_Single_Recipe_Check_Processing_Array.Builder tSingleRecipeCheckBuilder = null;
if (mLockedToSingleRecipe) {
// We're locked to a single recipe, but haven't built the recipe checker yet.
// Build the checker on next successful recipe.
- tSingleRecipeCheckBuilder = GT_Single_Recipe_Check.builder(this).setBefore();
+ tSingleRecipeCheckBuilder = GT_Single_Recipe_Check_Processing_Array.processingArrayBuilder(this).setBefore();
}
boolean recipeLocked = false;
@@ -289,9 +271,12 @@ public class GT_MetaTileEntity_ProcessingArray extends GT_MetaTileEntity_CubicMu
break;
} else if (mLockedToSingleRecipe && !recipeLocked) {
// We want to lock to a single run of the recipe.
- mSingleRecipeCheck = tSingleRecipeCheckBuilder.setAfter().setRecipe(tRecipe).build();
- mSingleRecipeAmperage = map.mAmperage;
- mSingleRecipeMachineStack = mInventory[1].copy();
+ mSingleRecipeCheck =
+ tSingleRecipeCheckBuilder
+ .setAfter()
+ .setRecipe(tRecipe)
+ .setRecipeAmperage(map.mAmperage)
+ .build();
recipeLocked = true;
}
}