aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech
diff options
context:
space:
mode:
authormiozune <miozune@gmail.com>2023-05-26 21:09:03 +0900
committerGitHub <noreply@github.com>2023-05-26 14:09:03 +0200
commitd0e291fa8cb31cedcf9ef8fbafb536f19b216907 (patch)
tree2e7474220b3f7cbeeb9db8717f010786397934e9 /src/main/java/gregtech
parent497080d591db8af491ece783bf9a480b50a7c16b (diff)
downloadGT5-Unofficial-d0e291fa8cb31cedcf9ef8fbafb536f19b216907.tar.gz
GT5-Unofficial-d0e291fa8cb31cedcf9ef8fbafb536f19b216907.tar.bz2
GT5-Unofficial-d0e291fa8cb31cedcf9ef8fbafb536f19b216907.zip
Add void protection mode to fluid and ore drillers (#2023)
* Refactor GT_ParallelHelper part 1 * Refactor GT_ParallelHelper part 2 * Move void protection logic to separated class * Clean doc * Fix inverted logic in VoidProtectionHelper * Add void protection mode to fluid and ore drillers
Diffstat (limited to 'src/main/java/gregtech')
-rw-r--r--src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java42
-rw-r--r--src/main/java/gregtech/api/util/GT_ParallelHelper.java450
-rw-r--r--src/main/java/gregtech/api/util/ValidationResult.java24
-rw-r--r--src/main/java/gregtech/api/util/ValidationType.java6
-rw-r--r--src/main/java/gregtech/api/util/VoidProtectionHelper.java402
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java69
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java5
-rw-r--r--src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java73
8 files changed, 651 insertions, 420 deletions
diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java
index 94392d089c..7eacf05b4e 100644
--- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java
+++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java
@@ -9,6 +9,8 @@ import static mcp.mobius.waila.api.SpecialChars.RESET;
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nullable;
+
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -120,6 +122,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity
.get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorLow", 5);
this.damageFactorHigh = (float) GregTech_API.sMachineFile
.get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorHigh", 0.6f);
+ voidExcess = !isVoidExcessButtonEnabled();
}
public static boolean isValidMetaTileEntity(MetaTileEntity aMetaTileEntity) {
@@ -933,12 +936,19 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity
}
public boolean depleteInput(FluidStack aLiquid) {
+ return depleteInput(aLiquid, false);
+ }
+
+ public boolean depleteInput(FluidStack aLiquid, boolean simulate) {
if (aLiquid == null) return false;
for (GT_MetaTileEntity_Hatch_Input tHatch : mInputHatches) {
tHatch.mRecipeMap = getRecipeMap();
if (isValidMetaTileEntity(tHatch)) {
FluidStack tLiquid = tHatch.drain(ForgeDirection.UNKNOWN, aLiquid, false);
if (tLiquid != null && tLiquid.amount >= aLiquid.amount) {
+ if (simulate) {
+ return true;
+ }
tLiquid = tHatch.drain(ForgeDirection.UNKNOWN, aLiquid, true);
return tLiquid != null && tLiquid.amount >= aLiquid.amount;
}
@@ -1512,6 +1522,38 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity
return true;
}
+ /**
+ * Checks if items can fit in the output buses. If your outputs come from GT_Recipe,
+ * {@link GT_ParallelHelper} will work better.
+ */
+ protected boolean canFitOutput(ItemStack[] items) {
+ return canFitOutput(items, null);
+ }
+
+ /**
+ * Checks if fluids can fit in the output hatches. If your outputs come from GT_Recipe,
+ * {@link GT_ParallelHelper} will work better.
+ */
+ protected boolean canFitOutput(FluidStack[] fluids) {
+ return canFitOutput(null, fluids);
+ }
+
+ /**
+ * Checks if items / fluids can fit in the output buses / hatches. If your outputs come from GT_Recipe,
+ * {@link GT_ParallelHelper} will work better.
+ */
+ protected boolean canFitOutput(@Nullable ItemStack[] items, @Nullable FluidStack[] fluids) {
+ VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper().setController(this);
+ if (items != null) {
+ voidProtectionHelper.setItemOutputs(items);
+ }
+ if (fluids != null) {
+ voidProtectionHelper.setFluidOutputs(fluids);
+ }
+ voidProtectionHelper.build();
+ return voidProtectionHelper.getMaxParallel() > 0;
+ }
+
@Override
public boolean useModularUI() {
return true;
diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java
index 4e281e976f..04218f4566 100644
--- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java
+++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java
@@ -1,83 +1,93 @@
package gregtech.api.util;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.PriorityQueue;
-
-import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
-import org.apache.commons.lang3.tuple.MutablePair;
-import org.apache.commons.lang3.tuple.MutableTriple;
-
-import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
-
-import gregtech.api.fluid.FluidTankGT;
-import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
-import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output;
import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase;
import gregtech.api.multitileentity.multiblock.base.Controller;
import gregtech.api.objects.XSTR;
-import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME;
-import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME;
public class GT_ParallelHelper {
/**
- * @mMachineMeta a MetaTileEntity Controller
+ * A MetaTileEntity Controller
*/
private GT_MetaTileEntity_MultiBlockBase mMachineMeta;
/**
- * @mMachineMulti a MultiTileEntity Controller
+ * A MultiTileEntity Controller
*/
private Controller<?> mMachineMulti;
/**
- * @mRecipe Recipe used when trying to calculate parallels
+ * Recipe used when trying to calculate parallels
*/
private GT_Recipe mRecipe;
/**
- * @mAvailableEUt EUt available to the multiblock (This should be the total eut available)
+ * EUt available to the multiblock (This should be the total eut available)
*/
private long mAvailableEUt;
/**
- * @mCurrentParallel The current parallel possible for the multiblock
- * @mMaxParallel The maximum possible parallel possible for the multiblock
- * @mBatchModifier The Batch Modifier applied when batch mode is enabled. 1 does nothing. 2 doubles max possible
- * parallel, but also duration
+ * The current parallel possible for the multiblock
+ */
+ private int mCurrentParallel = 0;
+ /**
+ * The maximum possible parallel possible for the multiblock
+ */
+ private int mMaxParallel = 1;
+ /**
+ * The Batch Modifier applied when batch mode is enabled. 1 does nothing. 2 doubles max possible
+ * parallel, but also duration
+ */
+ private int mBatchModifier = 1;
+ /**
+ * The inputs of the multiblock for the current recipe check
+ */
+ private ItemStack[] mItemInputs;
+ /**
+ * The outputs of the recipe with the applied parallel
+ */
+ private ItemStack[] mItemOutputs;
+ /**
+ * The inputs of the multiblock for the current recipe check
+ */
+ private FluidStack[] mFluidInputs;
+ /**
+ * The outputs of the recipe with the applied parallel
*/
- private int mCurrentParallel = 0, mMaxParallel = 1, mBatchModifier = 1;
+ private FluidStack[] mFluidOutputs;
/**
- * @mItemInputs The inputs of the multiblock for the current recipe check
- * @mItemOutputs The outputs of the recipe with the applied parallel
+ * Does the multi have void protection enabled
*/
- private ItemStack[] mItemInputs, mItemOutputs;
+ private boolean mVoidProtection;
/**
- * @mFluidInputs The inputs of the multiblock for the current recipe check
- * @mFluidOutputs The outputs of the recipe with the applied parallel
+ * Should the Parallel Helper automatically consume for the multi
*/
- private FluidStack[] mFluidInputs, mFluidOutputs;
+ private boolean mConsume;
/**
- * @mVoidProtection Does the multi have void protection enabled
- * @mConsume Should the Parallel Helper automatically consume for the multi
- * @mBatchMode Is batch mode turned on?
- * @mCalculateOutputs Should the Parallel Helper automatically calculate the outputs of the recipe with current
- * parallel
- * @mBuilt Has the Parallel Helper been built?
+ * Is batch mode turned on?
*/
- private boolean mVoidProtection, mConsume, mBatchMode, mCalculateOutputs, mBuilt;
+ private boolean mBatchMode;
/**
- * @mDurationMultiplier What is the duration multiplier with batch mode enabled
- * @mEUtModifier Modifier which is applied on the recipe eut. Useful for GT++ machines
+ * Should the Parallel Helper automatically calculate the outputs of the recipe with current
+ * parallel
*/
- private float mDurationMultiplier, mEUtModifier = 1;
+ private boolean mCalculateOutputs;
+ /**
+ * Has the Parallel Helper been built?
+ */
+ private boolean mBuilt;
+ /**
+ * What is the duration multiplier with batch mode enabled
+ */
+ private float mDurationMultiplier;
+ /**
+ * Modifier which is applied on the recipe eut. Useful for GT++ machines
+ */
+ private float mEUtModifier = 1;
public GT_ParallelHelper() {}
/**
- * Enables void protection on a metatile multiblock. Experimental! Still needs to be worked on
+ * Enables void protection on a metatile multiblock.
*/
public GT_ParallelHelper enableVoidProtection(GT_MetaTileEntity_MultiBlockBase aMachineMeta) {
mVoidProtection = true;
@@ -86,7 +96,7 @@ public class GT_ParallelHelper {
}
/**
- * Enables void protection on a multitile multiblock. Experimental! Still needs to be worked on
+ * Enables void protection on a multitile multiblock.
*/
public GT_ParallelHelper enableVoidProtection(Controller<?> aMachineMulti) {
mVoidProtection = true;
@@ -235,8 +245,6 @@ public class GT_ParallelHelper {
}
ItemStack[] tItemInputs = null;
FluidStack[] tFluidInputs = null;
- boolean tMEOutputBus = false;
- boolean tMEOutputHatch = false;
long tCurrentUsage = 0;
// see if people want to consume their inputs with the Parallel Helper or not
if (mConsume) {
@@ -266,31 +274,17 @@ public class GT_ParallelHelper {
}
// Let's look at how many parallels we can get with void protection
if (mVoidProtection) {
+ VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper();
if (mMachineMeta != null) {
- for (GT_MetaTileEntity_Hatch tHatch : mMachineMeta.mOutputBusses) {
- if (tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) {
- tMEOutputBus = true;
- break;
- }
- }
-
- for (GT_MetaTileEntity_Hatch tHatch : mMachineMeta.mOutputHatches) {
- if (tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME) {
- tMEOutputHatch = true;
- break;
- }
- }
- if (!tMEOutputBus) {
- mMaxParallel = Math.min(calculateMaxParallelsForBusses(), mMaxParallel);
- }
-
- if (!tMEOutputHatch) {
- mMaxParallel = Math.min(calculateMaxParallelsForHatches(), mMaxParallel);
- }
+ voidProtectionHelper.setController(mMachineMeta);
} else if (mMachineMulti != null) {
- mMaxParallel = Math.min(calculateMaxItemParallelsForMuTEs(), mMaxParallel);
- mMaxParallel = Math.min(calculateMaxFluidParallelsForMuTEs(), mMaxParallel);
+ voidProtectionHelper.setController(mMachineMulti);
}
+ voidProtectionHelper.setItemOutputs(mRecipe.mOutputs)
+ .setFluidOutputs(mRecipe.mFluidOutputs)
+ .setMaxParallel(mMaxParallel)
+ .build();
+ mMaxParallel = Math.min(voidProtectionHelper.getMaxParallel(), mMaxParallel);
}
float tRecipeEUt = mRecipe.mEUt * mEUtModifier;
@@ -348,324 +342,4 @@ public class GT_ParallelHelper {
}
}
}
-
- /**
- * Calculates the max parallel for fluids if void protection is turned on
- */
- private int calculateMaxFluidParallelsForMuTEs() {
- if (mMachineMulti != null && mMachineMulti.getOutputTanks() != null
- && mMachineMulti.getOutputTanks().length >= mRecipe.mFluidOutputs.length) {
- // A map to hold the items we will be 'inputting' into the output hatches. These fluidstacks are actually
- // the
- // recipe outputs.
- Map<FluidStack, Integer> tFluidOutputMap = new HashMap<>();
-
- // Map that keeps track of the number of parallel crafts we can accommodate for each fluid output.
- // In the pair, we keep track of number of full crafts plus mb of fluid in a partial craft, to avoid
- // issues with floating point math not being completely accurate when summing.
- Map<FluidStack, MutablePair<Integer, Integer>> tParallels = new HashMap<>();
-
- // Iterate over the outputs, calculating require stack spacing they will require.
- for (FluidStack aY : mRecipe.mFluidOutputs) {
- if (aY == null) {
- continue;
- }
- tFluidOutputMap.merge(aY, aY.amount, Integer::sum);
- tParallels.put(aY, new MutablePair<>(0, 0));
- }
-
- if (tFluidOutputMap.isEmpty()) {
- // nothing to output, bail early
- return mMaxParallel;
- }
-
- for (FluidTankGT tHatch : mMachineMulti.getOutputTanks()) {
- int tSpaceLeft = tHatch.getCapacity() - tHatch.getFluidAmount();
-
- // check if hatch filled
- if (tSpaceLeft <= 0) continue;
-
- // check if hatch is empty and unrestricted
- if (tHatch.getFluidAmount() == 0) continue;
-
- for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- FluidStack tFluidOutput = entry.getKey();
- // this fluid is not prevented by restrictions on output hatch
- if (tHatch.getFluidAmount() == 0 || GT_Utility.areFluidsEqual(tHatch.getFluid(), tFluidOutput)) {
- MutablePair<Integer, Integer> tParallel = entry.getValue();
- Integer tCraftSize = tFluidOutputMap.get(tFluidOutput);
- tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize;
- tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize;
- }
- }
- }
- // now that all partial/restricted hatches have been counted, create a priority queue for our outputs
- // the lowest priority fluid is the number of complete parallel crafts we can support
- PriorityQueue<MutableTriple<Integer, Integer, FluidStack>> aParallelQueue = new PriorityQueue<>(
- Comparator.comparing(MutableTriple::getLeft));
- for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey()));
- }
- // add extra parallels for open slots as well
- for (FluidTankGT tHatch : mMachineMulti.getOutputTanks()) {
- // partially filled or restricted hatch. done in last pass
- if (tHatch.getFluidAmount() > 0) continue;
-
- MutableTriple<Integer, Integer, FluidStack> tParallel = aParallelQueue.poll();
- assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
- Integer tCraftSize = tFluidOutputMap.get(tParallel.right);
- int tSpaceLeft = tHatch.getCapacity();
- tParallel.left += (tParallel.middle + tSpaceLeft) / tCraftSize;
- tParallel.middle = (tParallel.middle + tSpaceLeft) % tCraftSize;
- aParallelQueue.add(tParallel);
- }
- return aParallelQueue.element().left;
- }
- return 0;
- }
-
- /**
- * Calculates the max parallel for fluids if void protection is turned on
- */
- private int calculateMaxParallelsForHatches() {
- // For now we are gonna ignore MuTEs existence as there are no recipes for them
- if (mMachineMeta != null && mMachineMeta.mOutputHatches.size() >= mRecipe.mFluidOutputs.length) {
- // A map to hold the items we will be 'inputting' into the output hatches. These fluidstacks are actually
- // the
- // recipe outputs.
- Map<FluidStack, Integer> tFluidOutputMap = new HashMap<>();
-
- // Map that keeps track of the number of parallel crafts we can accommodate for each fluid output.
- // In the pair, we keep track of number of full crafts plus mb of fluid in a partial craft, to avoid
- // issues with floating point math not being completely accurate when summing.
- Map<FluidStack, MutablePair<Integer, Integer>> tParallels = new HashMap<>();
-
- // Iterate over the outputs, calculating require stack spacing they will require.
- for (FluidStack aY : mRecipe.mFluidOutputs) {
- if (aY == null) {
- continue;
- }
- tFluidOutputMap.merge(aY, aY.amount, Integer::sum);
- tParallels.put(aY, new MutablePair<>(0, 0));
- }
-
- if (tFluidOutputMap.isEmpty()) {
- // nothing to output, bail early
- return mMaxParallel;
- }
-
- for (GT_MetaTileEntity_Hatch_Output tHatch : mMachineMeta.mOutputHatches) {
- int tSpaceLeft = tHatch.getCapacity() - tHatch.getFluidAmount();
-
- // check if hatch filled
- if (tSpaceLeft <= 0) continue;
-
- // check if hatch is empty and unrestricted
- if (tHatch.mMode == 0 && tHatch.getFluidAmount() == 0) continue;
-
- String tLockedFluidName = tHatch.getLockedFluidName();
- for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- FluidStack tFluidOutput = entry.getKey();
- if (GT_ModHandler.isSteam(tFluidOutput)) {
- if (!tHatch.outputsSteam()) {
- continue;
- }
- } else {
- if (!tHatch.outputsLiquids()) {
- continue;
- }
- if (tHatch.isFluidLocked() && tLockedFluidName != null
- && !tLockedFluidName.equals(
- tFluidOutput.getFluid()
- .getName())) {
- continue;
- }
- }
- // this fluid is not prevented by restrictions on output hatch
- if (tHatch.getFluidAmount() == 0 || GT_Utility.areFluidsEqual(tHatch.getFluid(), tFluidOutput)) {
- MutablePair<Integer, Integer> tParallel = entry.getValue();
- Integer tCraftSize = tFluidOutputMap.get(tFluidOutput);
- tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize;
- tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize;
- }
- }
- }
- // now that all partial/restricted hatches have been counted, create a priority queue for our outputs
- // the lowest priority fluid is the number of complete parallel crafts we can support
- PriorityQueue<MutableTriple<Integer, Integer, FluidStack>> aParallelQueue = new PriorityQueue<>(
- Comparator.comparing(MutableTriple::getLeft));
- for (Entry<FluidStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey()));
- }
- // add extra parallels for open slots as well
- for (GT_MetaTileEntity_Hatch_Output tHatch : mMachineMeta.mOutputHatches) {
- // partially filled or restricted hatch. done in last pass
- if (tHatch.getFluidAmount() > 0 || tHatch.mMode != 0) continue;
-
- MutableTriple<Integer, Integer, FluidStack> tParallel = aParallelQueue.poll();
- assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
- Integer tCraftSize = tFluidOutputMap.get(tParallel.right);
- int tSpaceLeft = tHatch.getCapacity();
- tParallel.left += (tParallel.middle + tSpaceLeft) / tCraftSize;
- tParallel.middle = (tParallel.middle + tSpaceLeft) % tCraftSize;
- aParallelQueue.add(tParallel);
- }
- return aParallelQueue.element().left;
- }
- return 0;
- }
-
- /**
- * Calculates the max parallels one can do with items if void protection is on
- */
- private int calculateMaxItemParallelsForMuTEs() {
-
- // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the
- // recipe outputs.
- Map<ItemStack, Integer> tItemOutputMap = new ItemStackMap<>();
-
- // Map that keeps track of the number of parallel crafts we can accommodate for each item output.
- // In the pair, we keep track of number of full crafts plus number of items in a partial craft, to avoid
- // issues with floating point math not being completely accurate when summing.
- Map<ItemStack, MutablePair<Integer, Integer>> tParallels = new ItemStackMap<>();
- int tSlotsFree = 0;
- for (ItemStack tItem : mRecipe.mOutputs) {
- tItemOutputMap.merge(tItem, tItem.stackSize, Integer::sum);
- tParallels.put(tItem, new MutablePair<>(0, 0));
- }
-
- if (tItemOutputMap.isEmpty()) {
- // nothing to output, bail early
- return mMaxParallel;
- }
-
- if (mRecipe.mOutputs.length > 0 && mMachineMulti != null
- && mMachineMulti.getOutputInventory() != null
- && mMachineMulti.getOutputInventory()
- .getSlots() > 0) {
- for (int i = 0; i < mMachineMulti.getOutputInventory()
- .getSlots(); i++) {
- ItemStack tBusStack = mMachineMulti.getOutputInventory()
- .getStackInSlot(i);
- if (tBusStack == null) {
- tSlotsFree++;
- } else {
- // get the real stack size
- // we ignore the bus inventory stack limit here as no one set it to anything other than 64
- int tMaxBusStackSize = tBusStack.getMaxStackSize();
- if (tBusStack.stackSize >= tMaxBusStackSize)
- // this bus stack is full. no checking
- continue;
- int tSpaceLeft = tMaxBusStackSize - tBusStack.stackSize;
- Integer tCraftSize = tItemOutputMap.get(tBusStack);
- if (tCraftSize == null) {
- // we don't have a matching stack to output, ignore this bus stack
- continue;
- }
- MutablePair<Integer, Integer> tParallel = tParallels.get(tBusStack);
- tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize;
- tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize;
- }
- }
- // now that all partial stacks have been counted, create a priority queue for our outputs
- // the lowest priority item is the number of complete parallel crafts we can support
- PriorityQueue<MutableTriple<Integer, Integer, ItemStack>> aParallelQueue = new PriorityQueue<>(
- Comparator.comparing(MutableTriple::getLeft));
- for (Entry<ItemStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey()));
- }
-
- while (tSlotsFree > 0) {
- MutableTriple<Integer, Integer, ItemStack> tParallel = aParallelQueue.poll();
- assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
- Integer tCraftSize = tItemOutputMap.get(tParallel.right);
- int tStackSize = tParallel.right.getMaxStackSize();
- tParallel.left += (tParallel.middle + tStackSize) / tCraftSize;
- tParallel.middle = (tParallel.middle + tStackSize) % tCraftSize;
- aParallelQueue.add(tParallel);
- --tSlotsFree;
- }
-
- return aParallelQueue.element().left;
- }
- return 0;
- }
-
- /**
- * Calculates the max parallels one can do with items if void protection is on
- */
- private int calculateMaxParallelsForBusses() {
- // Same thing we are gonna ignore MuTEs existence for now. should be in theory the same later
-
- // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the
- // recipe outputs.
- Map<ItemStack, Integer> tItemOutputMap = new ItemStackMap<>();
-
- // Map that keeps track of the number of parallel crafts we can accommodate for each item output.
- // In the pair, we keep track of number of full crafts plus number of items in a partial craft, to avoid
- // issues with floating point math not being completely accurate when summing.
- Map<ItemStack, MutablePair<Integer, Integer>> tParallels = new ItemStackMap<>();
- int tSlotsFree = 0;
- for (ItemStack tItem : mRecipe.mOutputs) {
- tItemOutputMap.merge(tItem, tItem.stackSize, Integer::sum);
- tParallels.put(tItem, new MutablePair<>(0, 0));
- }
-
- if (tItemOutputMap.isEmpty()) {
- // nothing to output, bail early
- return mMaxParallel;
- }
-
- if (mRecipe.mOutputs.length > 0 && mMachineMeta != null) {
- for (final GT_MetaTileEntity_Hatch tBus : mMachineMeta.mOutputBusses) {
- if (!GT_MetaTileEntity_MultiBlockBase.isValidMetaTileEntity(tBus)) {
- continue;
- }
- final IInventory tBusInv = tBus.getBaseMetaTileEntity();
- for (int i = 0; i < tBusInv.getSizeInventory(); i++) {
- ItemStack tBusStack = tBus.getStackInSlot(i);
- if (tBusStack == null) {
- tSlotsFree++;
- } else {
- // get the real stack size
- // we ignore the bus inventory stack limit here as no one set it to anything other than 64
- int tMaxBusStackSize = tBusStack.getMaxStackSize();
- if (tBusStack.stackSize >= tMaxBusStackSize)
- // this bus stack is full. no checking
- continue;
- int tSpaceLeft = tMaxBusStackSize - tBusStack.stackSize;
- Integer tCraftSize = tItemOutputMap.get(tBusStack);
- if (tCraftSize == null) {
- // we don't have a matching stack to output, ignore this bus stack
- continue;
- }
- MutablePair<Integer, Integer> tParallel = tParallels.get(tBusStack);
- tParallel.left += (tParallel.right + tSpaceLeft) / tCraftSize;
- tParallel.right = (tParallel.right + tSpaceLeft) % tCraftSize;
- }
- }
- }
- // now that all partial stacks have been counted, create a priority queue for our outputs
- // the lowest priority item is the number of complete parallel crafts we can support
- PriorityQueue<MutableTriple<Integer, Integer, ItemStack>> aParallelQueue = new PriorityQueue<>(
- Comparator.comparing(MutableTriple::getLeft));
- for (Entry<ItemStack, MutablePair<Integer, Integer>> entry : tParallels.entrySet()) {
- aParallelQueue.add(new MutableTriple<>(entry.getValue().left, entry.getValue().right, entry.getKey()));
- }
-
- while (tSlotsFree > 0) {
- MutableTriple<Integer, Integer, ItemStack> tParallel = aParallelQueue.poll();
- assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
- Integer tCraftSize = tItemOutputMap.get(tParallel.right);
- int tStackSize = tParallel.right.getMaxStackSize();
- tParallel.left += (tParallel.middle + tStackSize) / tCraftSize;
- tParallel.middle = (tParallel.middle + tStackSize) % tCraftSize;
- aParallelQueue.add(tParallel);
- --tSlotsFree;
- }
-
- return aParallelQueue.element().left;
- }
- return 0;
- }
}
diff --git a/src/main/java/gregtech/api/util/ValidationResult.java b/src/main/java/gregtech/api/util/ValidationResult.java
new file mode 100644
index 0000000000..497dfe67e5
--- /dev/null
+++ b/src/main/java/gregtech/api/util/ValidationResult.java
@@ -0,0 +1,24 @@
+package gregtech.api.util;
+
+public class ValidationResult<T> {
+
+ private final ValidationType type;
+ private final T result;
+
+ private ValidationResult(ValidationType type, T result) {
+ this.type = type;
+ this.result = result;
+ }
+
+ public ValidationType getType() {
+ return this.type;
+ }
+
+ public T getResult() {
+ return this.result;
+ }
+
+ public static <T> ValidationResult<T> of(ValidationType result, T value) {
+ return new ValidationResult<>(result, value);
+ }
+}
diff --git a/src/main/java/gregtech/api/util/ValidationType.java b/src/main/java/gregtech/api/util/ValidationType.java
new file mode 100644
index 0000000000..4417834430
--- /dev/null
+++ b/src/main/java/gregtech/api/util/ValidationType.java
@@ -0,0 +1,6 @@
+package gregtech.api.util;
+
+public enum ValidationType {
+ VALID,
+ INVALID
+}
diff --git a/src/main/java/gregtech/api/util/VoidProtectionHelper.java b/src/main/java/gregtech/api/util/VoidProtectionHelper.java
new file mode 100644
index 0000000000..8b09cd5a3d
--- /dev/null
+++ b/src/main/java/gregtech/api/util/VoidProtectionHelper.java
@@ -0,0 +1,402 @@
+package gregtech.api.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import net.minecraft.inventory.IInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.IFluidTank;
+
+import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
+import com.gtnewhorizons.modularui.api.forge.IItemHandler;
+
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase;
+import gregtech.api.multitileentity.multiblock.base.Controller;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME;
+import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME;
+
+/**
+ * Helper class to calculate how many parallels of items / fluids can fit in the output buses / hatches.
+ */
+public class VoidProtectionHelper {
+
+ /**
+ * A MetaTileEntity Controller
+ */
+ private GT_MetaTileEntity_MultiBlockBase machineMeta;
+ /**
+ * A MultiTileEntity Controller
+ */
+ private Controller<?> machineMulti;
+ /**
+ * The maximum possible parallel possible for the multiblock
+ */
+ private int maxParallel = 1;
+ /**
+ * The item outputs to check
+ */
+ private ItemStack[] itemOutputs;
+ /**
+ * The fluid outputs to check
+ */
+ private FluidStack[] fluidOutputs;
+ /**
+ * Has this helper been built?
+ */
+ private boolean built;
+
+ public VoidProtectionHelper() {}
+
+ /**
+ * Sets MetaTE controller to use for calculation
+ */
+ public VoidProtectionHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta) {
+ this.machineMeta = machineMeta;
+ return this;
+ }
+
+ /**
+ * Sets MuTE controller to use for calculation
+ */
+ public VoidProtectionHelper setController(Controller<?> machineMulti) {
+ this.machineMulti = machineMulti;
+ return this;
+ }
+
+ public VoidProtectionHelper setItemOutputs(ItemStack[] itemOutputs) {
+ this.itemOutputs = itemOutputs;
+ return this;
+ }
+
+ public VoidProtectionHelper setFluidOutputs(FluidStack[] fluidOutputs) {
+ this.fluidOutputs = fluidOutputs;
+ return this;
+ }
+
+ /**
+ * Sets the MaxParallel a multi can handle
+ */
+ public VoidProtectionHelper setMaxParallel(int maxParallel) {
+ this.maxParallel = maxParallel;
+ return this;
+ }
+
+ /**
+ * Finishes the VoidProtectionHelper. Anything changed after this will not affect anything
+ */
+ public VoidProtectionHelper build() {
+ if (built) {
+ throw new IllegalStateException("Tried to build twice");
+ }
+ built = true;
+ determineParallel();
+ return this;
+ }
+
+ /**
+ * @return The current parallels possible by the multiblock
+ */
+ public int getMaxParallel() {
+ if (!built) {
+ throw new IllegalStateException("Tried to get parallels before building");
+ }
+ return maxParallel;
+ }
+
+ /**
+ * Called by {@link #build()}. Determines the parallels and everything else that needs to be done at build time
+ */
+ private void determineParallel() {
+ if (itemOutputs == null) {
+ itemOutputs = new ItemStack[0];
+ }
+ if (fluidOutputs == null) {
+ fluidOutputs = new FluidStack[0];
+ }
+
+ if (machineMeta != null) {
+ boolean tMEOutputBus = false;
+ boolean tMEOutputHatch = false;
+ for (GT_MetaTileEntity_Hatch tHatch : machineMeta.mOutputBusses) {
+ if (tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) {
+ tMEOutputBus = true;
+ break;
+ }
+ }
+
+ for (GT_MetaTileEntity_Hatch tHatch : machineMeta.mOutputHatches) {
+ if (tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME) {
+ tMEOutputHatch = true;
+ break;
+ }
+ }
+ if (!tMEOutputBus) {
+ maxParallel = Math.min(calculateMaxItemParallelsForMetaTEs(), maxParallel);
+ }
+
+ if (!tMEOutputHatch) {
+ maxParallel = Math.min(calculateMaxFluidParallelsForMetaTEs(), maxParallel);
+ }
+ } else if (machineMulti != null) {
+ maxParallel = Math.min(calculateMaxItemParallelsForMuTEs(), maxParallel);
+ maxParallel = Math.min(calculateMaxFluidParallelsForMuTEs(), maxParallel);
+ }
+ }
+
+ /**
+ * Calculates the max parallel for fluids if void protection is turned on
+ */
+ private int calculateMaxFluidParallelsForMuTEs() {
+ if (machineMulti == null || machineMulti.getOutputTanks() == null) {
+ return 0;
+ }
+ return calculateMaxFluidParallels(
+ Arrays.asList(machineMulti.getOutputTanks()),
+ tHatch -> tHatch.getFluidAmount() == 0,
+ (tHatch, fluidStack) -> true);
+ }
+
+ /**
+ * Calculates the max parallel for fluids if void protection is turned on
+ */
+ private int calculateMaxFluidParallelsForMetaTEs() {
+ if (machineMeta == null) {
+ return 0;
+ }
+ return calculateMaxFluidParallels(
+ machineMeta.mOutputHatches,
+ tHatch -> tHatch.mMode == 0 && tHatch.getFluidAmount() == 0,
+ (tHatch, fluidStack) -> {
+ if (GT_ModHandler.isSteam(fluidStack)) {
+ return tHatch.outputsSteam();
+ } else {
+ if (!tHatch.outputsLiquids()) {
+ return false;
+ }
+ String tLockedFluidName = tHatch.getLockedFluidName();
+ return !tHatch.isFluidLocked() || tLockedFluidName == null
+ || tLockedFluidName.equals(
+ fluidStack.getFluid()
+ .getName());
+ }
+ });
+ }
+
+ /**
+ * Calculates the max parallel for fluids if void protection is turned on
+ */
+ private <T extends IFluidTank> int calculateMaxFluidParallels(List<T> hatches, Function<T, Boolean> isEmpty,
+ BiFunction<T, FluidStack, Boolean> acceptsFluid) {
+ if (hatches.size() < fluidOutputs.length) {
+ return 0;
+ }
+
+ // A map to hold the items we will be 'inputting' into the output hatches. These fluidstacks are actually
+ // the recipe outputs.
+ Map<FluidStack, Integer> tFluidOutputMap = new HashMap<>();
+
+ // Map that keeps track of the number of parallel crafts we can accommodate for each fluid output.
+ // In the pair, we keep track of number of full crafts plus mb of fluid in a partial craft, to avoid
+ // issues with floating point math not being completely accurate when summing.
+ Map<FluidStack, ParallelData> tParallels = new HashMap<>();
+
+ // Iterate over the outputs, calculating require stack spacing they will require.
+ for (FluidStack aY : fluidOutputs) {
+ if (aY == null) {
+ continue;
+ }
+ tFluidOutputMap.merge(aY, aY.amount, Integer::sum);
+ tParallels.put(aY, new ParallelData(0, 0));
+ }
+
+ if (tFluidOutputMap.isEmpty()) {
+ // nothing to output, bail early
+ return maxParallel;
+ }
+
+ for (T tHatch : hatches) {
+ int tSpaceLeft = tHatch.getCapacity() - tHatch.getFluidAmount();
+
+ // check if hatch filled
+ if (tSpaceLeft <= 0) continue;
+
+ // check if hatch is empty and unrestricted
+ if (isEmpty.apply(tHatch)) continue;
+
+ for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) {
+ FluidStack tFluidOutput = entry.getKey();
+ if (!acceptsFluid.apply(tHatch, tFluidOutput)) continue;
+ // this fluid is not prevented by restrictions on output hatch
+ if (tHatch.getFluidAmount() == 0 || GT_Utility.areFluidsEqual(tHatch.getFluid(), tFluidOutput)) {
+ ParallelData tParallel = entry.getValue();
+ Integer tCraftSize = tFluidOutputMap.get(tFluidOutput);
+ tParallel.batch += (tParallel.partial + tSpaceLeft) / tCraftSize;
+ tParallel.partial = (tParallel.partial + tSpaceLeft) % tCraftSize;
+ }
+ }
+ }
+ // now that all partial/restricted hatches have been counted, create a priority queue for our outputs
+ // the lowest priority fluid is the number of complete parallel crafts we can support
+ PriorityQueue<ParallelStackInfo<FluidStack>> aParallelQueue = new PriorityQueue<>(
+ Comparator.comparing(i -> i.batch));
+ for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) {
+ aParallelQueue
+ .add(new ParallelStackInfo<>(entry.getValue().batch, entry.getValue().partial, entry.getKey()));
+ }
+ // add extra parallels for open slots as well
+ for (T tHatch : hatches) {
+ // partially filled or restricted hatch. done in last pass
+ if (!isEmpty.apply(tHatch)) continue;
+
+ ParallelStackInfo<FluidStack> tParallel = aParallelQueue.poll();
+ assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
+ Integer tCraftSize = tFluidOutputMap.get(tParallel.stack);
+ int tSpaceLeft = tHatch.getCapacity();
+ tParallel.batch += (tParallel.partial + tSpaceLeft) / tCraftSize;
+ tParallel.partial = (tParallel.partial + tSpaceLeft) % tCraftSize;
+ aParallelQueue.add(tParallel);
+ }
+ return aParallelQueue.element().batch;
+ }
+
+ /**
+ * Calculates the max parallels one can do with items if void protection is on
+ */
+ private int calculateMaxItemParallelsForMuTEs() {
+ List<ItemStack> busStacks = new ArrayList<>();
+ if (machineMulti != null) {
+ IItemHandler inv = machineMulti.getOutputInventory();
+ if (inv != null && inv.getSlots() > 0) {
+ for (int i = 0; i < inv.getSlots(); i++) {
+ busStacks.add(inv.getStackInSlot(i));
+ }
+ }
+ }
+ return calculateMaxItemParallels(busStacks);
+ }
+
+ /**
+ * Calculates the max parallels one can do with items if void protection is on
+ */
+ private int calculateMaxItemParallelsForMetaTEs() {
+ List<ItemStack> busStacks = new ArrayList<>();
+ if (machineMeta != null) {
+ for (final GT_MetaTileEntity_Hatch tBus : machineMeta.mOutputBusses) {
+ if (!GT_MetaTileEntity_MultiBlockBase.isValidMetaTileEntity(tBus)) {
+ continue;
+ }
+ final IInventory tBusInv = tBus.getBaseMetaTileEntity();
+ for (int i = 0; i < tBusInv.getSizeInventory(); i++) {
+ busStacks.add(tBus.getStackInSlot(i));
+ }
+ }
+ }
+ return calculateMaxItemParallels(busStacks);
+ }
+
+ /**
+ * Calculates the max parallels one can do with items if void protection is on
+ *
+ * @param busStacks List of itemstacks that are already stored in buses
+ */
+ private int calculateMaxItemParallels(List<ItemStack> busStacks) {
+ // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the
+ // recipe outputs.
+ Map<ItemStack, Integer> tItemOutputMap = new ItemStackMap<>();
+
+ // Map that keeps track of the number of parallel crafts we can accommodate for each item output.
+ // In the pair, we keep track of number of full crafts plus number of items in a partial craft, to avoid
+ // issues with floating point math not being completely accurate when summing.
+ Map<ItemStack, ParallelData> tParallels = new ItemStackMap<>();
+ int tSlotsFree = 0;
+ for (ItemStack tItem : itemOutputs) {
+ tItemOutputMap.merge(tItem, tItem.stackSize, Integer::sum);
+ tParallels.put(tItem, new ParallelData(0, 0));
+ }
+
+ if (tItemOutputMap.isEmpty()) {
+ // nothing to output, bail early
+ return maxParallel;
+ }
+
+ if (itemOutputs.length > 0) {
+ for (ItemStack tBusStack : busStacks) {
+ if (tBusStack == null) {
+ tSlotsFree++;
+ } else {
+ // get the real stack size
+ // we ignore the bus inventory stack limit here as no one set it to anything other than 64
+ int tMaxBusStackSize = tBusStack.getMaxStackSize();
+ if (tBusStack.stackSize >= tMaxBusStackSize)
+ // this bus stack is full. no checking
+ continue;
+ int tSpaceLeft = tMaxBusStackSize - tBusStack.stackSize;
+ Integer tCraftSize = tItemOutputMap.get(tBusStack);
+ if (tCraftSize == null) {
+ // we don't have a matching stack to output, ignore this bus stack
+ continue;
+ }
+ ParallelData tParallel = tParallels.get(tBusStack);
+ tParallel.batch += (tParallel.partial + tSpaceLeft) / tCraftSize;
+ tParallel.partial = (tParallel.partial + tSpaceLeft) % tCraftSize;
+ }
+
+ }
+ // now that all partial stacks have been counted, create a priority queue for our outputs
+ // the lowest priority item is the number of complete parallel crafts we can support
+ PriorityQueue<ParallelStackInfo<ItemStack>> aParallelQueue = new PriorityQueue<>(
+ Comparator.comparing(i -> i.batch));
+ for (Map.Entry<ItemStack, ParallelData> entry : tParallels.entrySet()) {
+ aParallelQueue
+ .add(new ParallelStackInfo<>(entry.getValue().batch, entry.getValue().partial, entry.getKey()));
+ }
+
+ while (tSlotsFree > 0) {
+ ParallelStackInfo<ItemStack> tParallel = aParallelQueue.poll();
+ assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings
+ Integer tCraftSize = tItemOutputMap.get(tParallel.stack);
+ int tStackSize = tParallel.stack.getMaxStackSize();
+ tParallel.batch += (tParallel.partial + tStackSize) / tCraftSize;
+ tParallel.partial = (tParallel.partial + tStackSize) % tCraftSize;
+ aParallelQueue.add(tParallel);
+ --tSlotsFree;
+ }
+
+ return aParallelQueue.element().batch;
+ }
+ return 0;
+ }
+
+ private static class ParallelData {
+
+ private int batch;
+ private int partial;
+
+ private ParallelData(int batch, int partial) {
+ this.batch = batch;
+ this.partial = partial;
+ }
+ }
+
+ private static class ParallelStackInfo<T> {
+
+ private int batch;
+ private int partial;
+ private final T stack;
+
+ private ParallelStackInfo(int batch, int partial, T stack) {
+ this.batch = batch;
+ this.partial = partial;
+ this.stack = stack;
+ }
+ }
+}
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java
index 1e7f683bc5..9cab5b4ec6 100644
--- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java
@@ -14,6 +14,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import javax.annotation.Nonnegative;
+
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -37,6 +39,8 @@ import gregtech.api.render.TextureFactory;
import gregtech.api.util.GT_Log;
import gregtech.api.util.GT_Multiblock_Tooltip_Builder;
import gregtech.api.util.GT_Utility;
+import gregtech.api.util.ValidationResult;
+import gregtech.api.util.ValidationType;
public abstract class GT_MetaTileEntity_OilDrillBase extends GT_MetaTileEntity_DrillerBase {
@@ -195,7 +199,13 @@ public abstract class GT_MetaTileEntity_OilDrillBase extends GT_MetaTileEntity_D
mWorkChunkNeedsReload = false;
}
float speed = computeSpeed();
- FluidStack tFluid = pumpOil(speed);
+ ValidationResult<FluidStack> pumpResult = tryPumpOil(speed);
+ if (pumpResult.getType() != ValidationType.VALID) {
+ mEUt = 0;
+ mMaxProgresstime = 0;
+ return false;
+ }
+ FluidStack tFluid = pumpResult.getResult();
if (tFluid != null && tFluid.amount > getTotalConfigValue()) {
this.mOutputFluids = new FluidStack[] { tFluid };
return true;
@@ -265,37 +275,69 @@ public abstract class GT_MetaTileEntity_OilDrillBase extends GT_MetaTileEntity_D
return !mOilFieldChunks.isEmpty();
}
- protected FluidStack pumpOil(float speed) {
+ /**
+ * Tries to pump oil, accounting for output space if void protection is enabled.
+ * <p>
+ * If pumped fluid will not fit in output hatches, it returns a result with INVALID.
+ * <p>
+ * If vein is depleted, it returns a result with VALID and null fluid.
+ */
+ protected ValidationResult<FluidStack> tryPumpOil(float speed) {
if (mOilId <= 0) return null;
- FluidStack tFluid, tOil;
- tOil = new FluidStack(FluidRegistry.getFluid(mOilId), 0);
if (debugDriller) {
GT_Log.out.println(" pump speed = " + speed);
}
+ if (!voidExcess) {
+ FluidStack simulatedOil = pumpOil(speed, true);
+ if (!canFitOutput(new FluidStack[] { simulatedOil })) {
+ return ValidationResult.of(ValidationType.INVALID, null);
+ }
+ }
+
+ FluidStack pumpedOil = pumpOil(speed, false);
+ mOilFlow = pumpedOil.amount;
+ return ValidationResult.of(ValidationType.VALID, pumpedOil.amount == 0 ? null : pumpedOil);
+ }
+
+ /**
+ * @param speed Speed to pump oil
+ * @param simulate If true, it actually does not consume vein
+ * @return Fluid pumped
+ */
+ protected FluidStack pumpOil(@Nonnegative float speed, boolean simulate) {
+ if (speed < 0) {
+ throw new IllegalArgumentException("Don't pass negative speed");
+ }
+
ArrayList<Chunk> emptyChunks = new ArrayList<>();
+ FluidStack returnOil = new FluidStack(FluidRegistry.getFluid(mOilId), 0);
for (Chunk tChunk : mOilFieldChunks) {
- tFluid = undergroundOil(tChunk, speed);
+ FluidStack pumped = undergroundOil(tChunk, simulate ? -speed : speed);
if (debugDriller) {
GT_Log.out.println(
" chunkX = " + tChunk.getChunkCoordIntPair().chunkXPos
+ " chunkZ = "
+ tChunk.getChunkCoordIntPair().chunkZPos);
- if (tFluid != null) {
- GT_Log.out.println(" Fluid pumped = " + tFluid.amount);
+ if (pumped != null) {
+ GT_Log.out.println(" Fluid pumped = " + pumped.amount);
} else {
GT_Log.out.println(" No fluid pumped ");
}
}
- if (tFluid == null || tFluid.amount < 1) emptyChunks.add(tChunk);
- if (tOil.isFluidEqual(tFluid)) tOil.amount += tFluid.amount;
+ if (pumped == null || pumped.amount < 1) {
+ emptyChunks.add(tChunk);
+ continue;
+ }
+ if (returnOil.isFluidEqual(pumped)) {
+ returnOil.amount += pumped.amount;
+ }
}
for (Chunk tChunk : emptyChunks) {
mOilFieldChunks.remove(tChunk);
}
- mOilFlow = tOil.amount;
- return tOil.amount == 0 ? null : tOil;
+ return returnOil;
}
@Override
@@ -328,4 +370,9 @@ public abstract class GT_MetaTileEntity_OilDrillBase extends GT_MetaTileEntity_D
l.addAll(Arrays.asList(super.getInfoData()));
return l.toArray(new String[0]);
}
+
+ @Override
+ protected boolean isVoidExcessButtonEnabled() {
+ return true;
+ }
}
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java
index 2c86218bfb..1146c39f21 100644
--- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java
@@ -50,8 +50,9 @@ public class GT_MetaTileEntity_OilDrillInfinite extends GT_MetaTileEntity_OilDri
}
@Override
- protected FluidStack pumpOil(float speed) {
- return super.pumpOil(-speed);
+ protected FluidStack pumpOil(float speed, boolean simulate) {
+ // always simulate to not deplete vein
+ return super.pumpOil(speed, true);
}
@Override
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java
index 8e8f16d111..b6a0d92f42 100644
--- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java
@@ -41,7 +41,7 @@ import gregtech.common.blocks.GT_TileEntity_Ores;
public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTileEntity_DrillerBase {
- private final ArrayList<ChunkPosition> oreBlockPositions = new ArrayList<>();
+ private final List<ChunkPosition> oreBlockPositions = new ArrayList<>();
protected int mTier = 1;
private int chunkRadiusConfig = getRadiusInChunks();
private boolean replaceWithCobblestone = true;
@@ -130,11 +130,31 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
// new layer - fill again
fillMineListIfEmpty(xDrill, yDrill, zDrill, xPipe, zPipe, yHead);
}
- return processOreList();
+ return tryProcessOreList();
}
- private boolean processOreList() {
+ private boolean tryProcessOreList() {
+ if (!voidExcess) {
+ boolean simulateResult = processOreList(true);
+ if (!simulateResult) {
+ mEUt = 0;
+ mMaxProgresstime = 0;
+ return false;
+ }
+ }
+ boolean result = processOreList(false);
+ if (!result) {
+ mEUt = 0;
+ mMaxProgresstime = 0;
+ return false;
+ }
+ return true;
+ }
+
+ private boolean processOreList(boolean simulate) {
ChunkPosition oreBlockPos = null;
+ List<ChunkPosition> oreBlockPositions = simulate ? copyOreBlockPositions(this.oreBlockPositions)
+ : this.oreBlockPositions;
int x = 0, y = 0, z = 0;
Block oreBlock = null;
int oreBlockMetadata = 0;
@@ -150,7 +170,7 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
.getBlockMetadata(x, y, z);
}
- if (!tryConsumeDrillingFluid()) {
+ if (!tryConsumeDrillingFluid(simulate)) {
oreBlockPositions.add(0, oreBlockPos);
return false;
}
@@ -163,18 +183,32 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
Collection<ItemStack> oreBlockDrops = getBlockDrops(oreBlock, x, y, z);
ItemStack cobble = GT_Utility.getCobbleForOre(oreBlock, metaData);
- if (replaceWithCobblestone) {
- getBaseMetaTileEntity().getWorld()
- .setBlock(x, y, z, Block.getBlockFromItem(cobble.getItem()), cobble.getItemDamage(), 3);
- } else {
- getBaseMetaTileEntity().getWorld()
- .setBlockToAir(oreBlockPos.chunkPosX, oreBlockPos.chunkPosY, oreBlockPos.chunkPosZ);
+ if (!simulate) {
+ if (replaceWithCobblestone) {
+ getBaseMetaTileEntity().getWorld()
+ .setBlock(x, y, z, Block.getBlockFromItem(cobble.getItem()), cobble.getItemDamage(), 3);
+ } else {
+ getBaseMetaTileEntity().getWorld()
+ .setBlockToAir(oreBlockPos.chunkPosX, oreBlockPos.chunkPosY, oreBlockPos.chunkPosZ);
+ }
}
- mOutputItems = getOutputByDrops(oreBlockDrops);
+ ItemStack[] toOutput = getOutputByDrops(oreBlockDrops);
+ if (simulate && !canFitOutput(toOutput)) {
+ return false;
+ }
+ mOutputItems = toOutput;
}
return true;
}
+ private static List<ChunkPosition> copyOreBlockPositions(List<ChunkPosition> oreBlockPositions) {
+ List<ChunkPosition> ret = new ArrayList<>();
+ for (ChunkPosition chunkPosition : oreBlockPositions) {
+ ret.add(new ChunkPosition(chunkPosition.chunkPosX, chunkPosition.chunkPosY, chunkPosition.chunkPosZ));
+ }
+ return ret;
+ }
+
@Override
protected boolean workingAtBottom(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe,
int yHead, int oldYHead) {
@@ -199,7 +233,7 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
return true;
}
}
- return processOreList();
+ return tryProcessOreList();
}
private void createInitialWorkingChunk() {
@@ -220,7 +254,7 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
int yHead, int oldYHead) {
if (!mChunkLoadingEnabled || oreBlockPositions.isEmpty())
return super.workingUpward(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead);
- boolean result = processOreList();
+ boolean result = tryProcessOreList();
if (oreBlockPositions.isEmpty()) GT_ChunkManager.releaseTicket((TileEntity) getBaseMetaTileEntity());
return result;
}
@@ -331,12 +365,8 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
} else return oreBlock.getDrops(getBaseMetaTileEntity().getWorld(), posX, posY, posZ, blockMeta, mTier + 3);
}
- private boolean tryConsumeDrillingFluid() {
- if (!depleteInput(new FluidStack(ItemList.sDrillingFluid, 2000))) {
- mMaxProgresstime = 0;
- return false;
- }
- return true;
+ private boolean tryConsumeDrillingFluid(boolean simulate) {
+ return depleteInput(new FluidStack(ItemList.sDrillingFluid, 2000), simulate);
}
private void fillChunkMineList(int yHead, int yDrill) {
@@ -433,4 +463,9 @@ public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTile
+ " "
+ StatCollector.translateToLocal("GT5U.machines.chunks") };
}
+
+ @Override
+ protected boolean isVoidExcessButtonEnabled() {
+ return true;
+ }
}