aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/net/glease/ggfab/mte
diff options
context:
space:
mode:
authorNotAPenguin <michiel.vandeginste@gmail.com>2024-02-27 16:09:06 +0100
committerGitHub <noreply@github.com>2024-02-27 16:09:06 +0100
commit14fce70432ac1c982006775f88d5451d0b537d0a (patch)
tree3c1bc9759fdaeef11a0f7023068e4a40e060c488 /src/main/java/net/glease/ggfab/mte
parent39d9a964a111677301b216044b0fe82231ef8c43 (diff)
downloadGT5-Unofficial-14fce70432ac1c982006775f88d5451d0b537d0a.tar.gz
GT5-Unofficial-14fce70432ac1c982006775f88d5451d0b537d0a.tar.bz2
GT5-Unofficial-14fce70432ac1c982006775f88d5451d0b537d0a.zip
Add AAL batch mode (#32)
This PR adds support for batch mode to the AAL. A few notes: - Similarly to regular batch mode, the amount of batches to run is chosen so the time of each slice is at least 128 ticks. If the time per slice is already 128 ticks, this does nothing. - Batch size is also controlled by how many recipes we can do with the amount of the first item we have. If we want to run 10 batches but only have enough starting items for 5, it will run 5 batches. - If there are not enough fluids to run multiple batches, it will not batch at all and simply process one recipe at a time. - If a slice cannot extract enough materials to do a full batch, it gets stuck (similarly to a regular AAL). - Currently, this only works well with stocking input buses, see the comment I left on line 616. I don't think this should be a problem since you will never use input buses with more than one slot to automate an AAL. Short demo video (not yet using adaptive batch sizes) https://streamable.com/hrp1v3
Diffstat (limited to 'src/main/java/net/glease/ggfab/mte')
-rw-r--r--src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java136
1 files changed, 114 insertions, 22 deletions
diff --git a/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java b/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java
index ed04c2fbce..e540bb4562 100644
--- a/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java
+++ b/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java
@@ -36,6 +36,7 @@ import net.glease.ggfab.GGConstants;
import net.glease.ggfab.mui.ClickableTextWidget;
import net.glease.ggfab.util.OverclockHelper;
import net.minecraft.client.resources.I18n;
+import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
@@ -189,6 +190,10 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
private boolean sortFluidHatches;
private int currentInputLength;
private String lastStopReason = "";
+ private int currentRecipeParallel = 1;
+ // Batch mode will increase parallel per slice to try to get as close as possible to this amount of ticks
+ // per slice, but will never go over this amount.
+ private static final int BATCH_MODE_DESIRED_TICKS_PER_SLICE = 128;
public MTE_AdvAssLine(int aID, String aName, String aNameRegional) {
super(aID, aName, aNameRegional);
@@ -343,6 +348,8 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
currentRecipe = recipe;
currentStick = stick;
currentInputLength = recipe.mInputs.length;
+ // Reset parallel, we need to re-check on next recipe check to see if there are enough items in the first slice
+ currentRecipeParallel = 1;
}
private void clearCurrentRecipe() {
@@ -375,6 +382,7 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
aNBT.setLong("inputV", inputVoltage);
aNBT.setLong("inputEU", inputEUt);
aNBT.setLong("baseEU", baseEUt);
+ aNBT.setInteger("currentParallel", currentRecipeParallel);
}
}
@@ -406,6 +414,7 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
inputVoltage = aNBT.getLong("inputV");
inputEUt = aNBT.getLong("inputEU");
baseEUt = aNBT.getLong("baseEU");
+ currentRecipeParallel = aNBT.getInteger("currentParallel");
if (inputVoltage <= 0 || inputEUt <= 0 || baseEUt >= 0) {
criticalStopMachine("ggfab.gui.advassline.shutdown.load.energy");
loadedStack = null;
@@ -604,8 +613,10 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
}
if (getBaseMetaTileEntity().isAllowedToWork()) {
- if (hasAllItems(currentRecipe) && hasAllFluids(currentRecipe) && slices[0].start()) {
- drainAllFluids(currentRecipe);
+ if (hasAllItems(currentRecipe, this.currentRecipeParallel)
+ && hasAllFluids(currentRecipe, this.currentRecipeParallel)
+ && slices[0].start()) {
+ drainAllFluids(currentRecipe, this.currentRecipeParallel);
mProgresstime = 0;
}
}
@@ -621,6 +632,10 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
if (index < mInputBusses.size()) {
GT_MetaTileEntity_Hatch_InputBus bus = mInputBusses.get(index);
if (bus.isValid()) {
+ // This limits items extracted per slice to 64. Normally this is not an issue, but with batch
+ // mode it can suddenly cause the AAL to get stuck because it thinks there are not enough
+ // items in the bus. I'm not quite sure how to get around this, even though it should not matter
+ // in practice since all AAL automation uses stocking buses instead of regular input buses.
stuff = bus.getStackInSlot(0);
}
}
@@ -649,11 +664,12 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
// If we run into missing buses/hatches or bad inputs, we go to the next data stick.
// This check only happens if we have a valid up-to-date data stick.
- // Check item Inputs align
- if (!hasAllItems(tRecipe)) return null;
+ // Check item Inputs align. For this we do not need to consider batch mode parallels yet, this will be done
+ // later on during recipe start.
+ if (!hasAllItems(tRecipe, 1)) return null;
- // Check Fluid Inputs align
- if (!hasAllFluids(tRecipe)) return null;
+ // Check Fluid Inputs align. Again, do not consider parallels
+ if (!hasAllFluids(tRecipe, 1)) return null;
if (GT_Values.D1) {
GT_FML_LOGGER.info("Check overclock");
@@ -664,13 +680,17 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
return tRecipe;
}
- private boolean hasAllItems(GT_Recipe.GT_Recipe_AssemblyLine tRecipe) {
+ private boolean hasAllItems(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) {
int aItemCount = tRecipe.mInputs.length;
if (mInputBusses.size() < aItemCount) return false;
for (int i = 0; i < aItemCount; i++) {
ItemStack tSlotStack = getInputBusContent(i);
if (tSlotStack == null) return false;
- int tRequiredStackSize = isStackValidIngredient(tSlotStack, tRecipe.mInputs[i], tRecipe.mOreDictAlt[i]);
+ int tRequiredStackSize = isStackValidIngredient(
+ tSlotStack,
+ tRecipe.mInputs[i],
+ tRecipe.mOreDictAlt[i],
+ parallel);
if (tRequiredStackSize < 0) return false;
if (GT_Values.D1) {
@@ -680,7 +700,9 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
return true;
}
- private boolean hasAllFluids(GT_Recipe.GT_Recipe_AssemblyLine tRecipe) {
+ private boolean hasAllFluids(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) {
+ // TODO: Actually use the parallel parameter here, though this is already checked on recipe check,
+ // we may need to re-check
int aFluidCount = tRecipe.mFluidInputs.length;
if (mInputHatches.size() < aFluidCount) return false;
for (int i = 0; i < aFluidCount; i++) {
@@ -780,8 +802,41 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
mMaxProgresstime = laserOverclock.getDuration();
}
}
+ // Save this for batch mode parallel calculations
+ int timePerSlice = mMaxProgresstime;
// correct the recipe duration
mMaxProgresstime *= recipe.mInputs.length;
+
+ // Finally apply batch mode parallels if possible.
+ // For this we need to verify the first item slot and all fluids slots have enough resources
+ // to execute parallels.
+ // Note that we skip this entirely if the time for each slice is more than
+ // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks, since in this case the amount of batches will always be 1
+ if (super.isBatchModeEnabled() && timePerSlice < BATCH_MODE_DESIRED_TICKS_PER_SLICE) {
+ // Calculate parallel based on time per slice, and the amount of items in the first slot.
+ // If there is not enough fluid, no batching will be done.
+
+ ItemStack firstItemSlot = getInputBusContent(0);
+ int recipesAvailable = Math.floorDiv(firstItemSlot.stackSize, recipe.mInputs[0].stackSize);
+ // Divide recipes available by the amount of slices in the recipe. This will prevent the AAL from
+ // batching instead of parallelizing, which would make it effectively slower.
+ recipesAvailable = Math.floorDiv(recipesAvailable, recipe.mInputs.length);
+ // Sanity check to avoid this being zero when there is only one recipe available.
+ recipesAvailable = Math.max(recipesAvailable, 1);
+ int desiredBatches = Math.floorDiv(BATCH_MODE_DESIRED_TICKS_PER_SLICE, timePerSlice);
+ // Limit the amount of parallel to both the amount of recipes available and the maximum number
+ // of batches we want to run. The latter is done to prevent batch mode from ever going above
+ // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks per slice (see also where it is defined above).
+ int parallel = Math.min(recipesAvailable, desiredBatches);
+ // We no longer need to check if we have enough items in the first slot, as this is
+ // guaranteed by taking the minimum earlier.
+ if (hasAllFluids(recipe, parallel)) {
+ this.currentRecipeParallel = parallel;
+ // Update recipe duration with final batch mode multiplier
+ mMaxProgresstime *= this.currentRecipeParallel;
+ }
+ }
+
break;
}
}
@@ -802,9 +857,11 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
// something very very wrong...
return CheckRecipeResultRegistry.NONE;
}
- drainAllFluids(recipe);
+ drainAllFluids(recipe, this.currentRecipeParallel);
- mOutputItems = new ItemStack[] { recipe.mOutput };
+ // Apply parallel
+ mOutputItems = new ItemStack[] { recipe.mOutput.copy() };
+ mOutputItems[0].stackSize *= this.currentRecipeParallel;
if (this.lEUt > 0) {
this.lEUt = -this.lEUt;
@@ -904,9 +961,12 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
* Caller is responsible to check and ensure the hatches are there and has all the fluid needed. You will usually
* want to ensure hasAllFluid was called right before calling this, otherwise very bad things can happen.
*/
- private void drainAllFluids(GT_Recipe.GT_Recipe_AssemblyLine recipe) {
+ private void drainAllFluids(GT_Recipe.GT_Recipe_AssemblyLine recipe, int parallel) {
for (int i = 0; i < recipe.mFluidInputs.length; i++) {
- mInputHatches.get(i).drain(ForgeDirection.UNKNOWN, recipe.mFluidInputs[i], true);
+ // Apply parallel
+ FluidStack fluidInput = recipe.mFluidInputs[i].copy();
+ fluidInput.amount *= parallel;
+ mInputHatches.get(i).drain(ForgeDirection.UNKNOWN, fluidInput, true);
}
sortFluidHatches = true;
}
@@ -917,21 +977,43 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
super.stopMachine();
}
- private static int isStackValidIngredient(ItemStack aSlotStack, ItemStack aIngredient, ItemStack[] alts) {
- if (alts == null || alts.length == 0) return isStackValidIngredient(aSlotStack, aIngredient);
+ private static int isStackValidIngredient(ItemStack aSlotStack, ItemStack aIngredient, ItemStack[] alts,
+ int parallel) {
+ if (alts == null || alts.length == 0) return isStackValidIngredient(aSlotStack, aIngredient, parallel);
for (ItemStack tAltStack : alts) {
- int i = isStackValidIngredient(aSlotStack, tAltStack);
+ int i = isStackValidIngredient(aSlotStack, tAltStack, parallel);
if (i >= 0) return i;
}
return -1;
}
- private static int isStackValidIngredient(ItemStack aSlotStack, ItemStack aIngredient) {
- if (GT_Utility.areStacksEqual(aSlotStack, aIngredient, true) && aIngredient.stackSize <= aSlotStack.stackSize)
- return aIngredient.stackSize;
+ private static int isStackValidIngredient(ItemStack aSlotStack, ItemStack aIngredient, int parallel) {
+ int ingredientStackSizeWithParallel = aIngredient.stackSize * parallel;
+ if (GT_Utility.areStacksEqual(aSlotStack, aIngredient, true)
+ && ingredientStackSizeWithParallel <= aSlotStack.stackSize)
+ return ingredientStackSizeWithParallel;
return -1;
}
+ @Override
+ public boolean supportsBatchMode() {
+ return true;
+ }
+
+ @Override
+ public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer,
+ float aX, float aY, float aZ) {
+ if (aPlayer.isSneaking()) {
+ batchMode = !batchMode;
+ if (batchMode) {
+ GT_Utility.sendChatToPlayer(aPlayer, "Batch recipes");
+ } else {
+ GT_Utility.sendChatToPlayer(aPlayer, "Don't batch recipes");
+ }
+ }
+ return true;
+ }
+
private class SliceStatusWidget extends TextWidget implements ISyncedWidget {
private final Slice slice;
@@ -1008,7 +1090,9 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
if (progress == 0 || --progress == 0) {
// id==0 will be end of chain if 1 input, so we need a +1 here
if (id + 1 >= currentInputLength) {
- if (addOutput(currentRecipe.mOutput) || !voidingMode.protectItem) reset();
+ // use previously calculated parallel output
+ ItemStack output = mOutputItems[0];
+ if (addOutput(output) || !voidingMode.protectItem) reset();
else stuck = true;
} else {
if (slices[id + 1].start()) reset();
@@ -1022,7 +1106,11 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
startRecipeProcessing();
ItemStack stack = getInputBusContent(id);
if (stack == null) return false;
- int size = isStackValidIngredient(stack, currentRecipe.mInputs[id], currentRecipe.mOreDictAlt[id]);
+ int size = isStackValidIngredient(
+ stack,
+ currentRecipe.mInputs[id],
+ currentRecipe.mOreDictAlt[id],
+ currentRecipeParallel);
if (size < 0) return false;
progress = mMaxProgresstime / currentInputLength;
stack.stackSize -= size;
@@ -1040,7 +1128,11 @@ public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBas
public boolean hasInput() {
ItemStack stack = getInputBusContent(id);
if (stack == null) return false;
- return isStackValidIngredient(stack, currentRecipe.mInputs[id], currentRecipe.mOreDictAlt[id]) >= 0;
+ return isStackValidIngredient(
+ stack,
+ currentRecipe.mInputs[id],
+ currentRecipe.mOreDictAlt[id],
+ currentRecipeParallel) >= 0;
}
@Override