Skip to content

Commit

Permalink
Fix void protection for mutes (#2298)
Browse files Browse the repository at this point in the history
* initial variables

* implement working void protection on items and fluids
  • Loading branch information
BlueWeabo authored Sep 25, 2023
1 parent ce26555 commit 360a84b
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 9 deletions.
32 changes: 29 additions & 3 deletions src/main/java/gregtech/api/util/GT_ParallelHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public class GT_ParallelHelper {
* The inputs of the machine for current recipe check
*/
private ItemInventoryLogic itemInputInventory;
/**
* The output item inventory of the machine
*/
private ItemInventoryLogic itemOutputInventory;
/**
* The outputs of the recipe with the applied parallel
*/
Expand All @@ -75,6 +79,10 @@ public class GT_ParallelHelper {
* The inputs of the machine for the current recipe check
*/
private FluidInventoryLogic fluidInputInventory;
/**
* The output fluid inventory of the machine;
*/
private FluidInventoryLogic fluidOutputInventory;
/**
* The outputs of the recipe with the applied parallel
*/
Expand Down Expand Up @@ -117,7 +125,7 @@ public class GT_ParallelHelper {
* Calculator to use for overclocking
*/
private GT_OverclockCalculator calculator;

@Nonnull
private CheckRecipeResult result = CheckRecipeResultRegistry.NONE;

private Function<Integer, ItemStack[]> customItemOutputCalculation;
Expand Down Expand Up @@ -330,6 +338,21 @@ public GT_ParallelHelper setFluidInputInventory(FluidInventoryLogic fluidInputIn
return this;
}

/**
*
*/
@Nonnull
public GT_ParallelHelper setItemOutputInventory(ItemInventoryLogic itemOutputInventory) {
this.itemOutputInventory = itemOutputInventory;
return this;
}

@Nonnull
public GT_ParallelHelper setFluidOutputInventory(FluidInventoryLogic fluidOutputInventory) {
this.fluidOutputInventory = fluidOutputInventory;
return this;
}

/**
* Finishes the GT_ParallelHelper. Anything changed after this will not effect anything
*/
Expand Down Expand Up @@ -493,14 +516,17 @@ protected void determineParallel() {

// Let's look at how many parallels we can get with void protection
if (protectExcessItem || protectExcessFluid) {
if (machine == null) {
if (machine == null && !muteMode) {
throw new IllegalStateException("Tried to calculate void protection, but machine is not set");
}
VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper();
voidProtectionHelper.setMachine(machine)
voidProtectionHelper.setMachine(machine, protectExcessItem, protectExcessFluid)
.setItemOutputs(recipe.mOutputs)
.setFluidOutputs(recipe.mFluidOutputs)
.setMaxParallel(maxParallel)
.setItemOutputInventory(itemOutputInventory)
.setFluidOutputInventory(fluidOutputInventory)
.setMuTEMode(muteMode)
.build();
maxParallel = Math.min(voidProtectionHelper.getMaxParallel(), maxParallel);
if (maxParallel <= 0) {
Expand Down
127 changes: 121 additions & 6 deletions src/main/java/gregtech/api/util/VoidProtectionHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
import net.minecraftforge.fluids.FluidStack;

import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
import com.gtnewhorizons.modularui.api.fluids.IFluidTankLong;

import gregtech.api.interfaces.fluid.IFluidStore;
import gregtech.api.interfaces.tileentity.IVoidable;
import gregtech.api.logic.FluidInventoryLogic;
import gregtech.api.logic.ItemInventoryLogic;
import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase;

/**
Expand Down Expand Up @@ -44,10 +47,22 @@ public class VoidProtectionHelper {
* The fluid outputs to check
*/
private FluidStack[] fluidOutputs;
/**
* The item output inventory
*/
private ItemInventoryLogic itemOutputInventory;
/**
* The fluid output inventory
*/
private FluidInventoryLogic fluidOutputInventory;
/**
* Has this helper been built?
*/
private boolean built;
/**
* Is this helper working for a MuTE?
*/
private boolean muteMode;

public VoidProtectionHelper() {}

Expand Down Expand Up @@ -107,6 +122,21 @@ public VoidProtectionHelper setMaxParallel(int maxParallel) {
return this;
}

public VoidProtectionHelper setItemOutputInventory(ItemInventoryLogic itemOutputInventory) {
this.itemOutputInventory = itemOutputInventory;
return this;
}

public VoidProtectionHelper setFluidOutputInventory(FluidInventoryLogic fluidOutputInventory) {
this.fluidOutputInventory = fluidOutputInventory;
return this;
}

public VoidProtectionHelper setMuTEMode(boolean muteMode) {
this.muteMode = muteMode;
return this;
}

/**
* Finishes the VoidProtectionHelper. Anything changed after this will not affect anything
*/
Expand Down Expand Up @@ -149,7 +179,8 @@ private void determineParallel() {
maxParallel = Math.min(calculateMaxItemParallels(), maxParallel);
}
if (protectExcessFluid && fluidOutputs.length > 0 && !machine.canDumpFluidToME()) {
maxParallel = Math.min(calculateMaxFluidParallels(), maxParallel);
maxParallel = Math
.min(muteMode ? calculateMaxFluidParallelsMuTE() : calculateMaxFluidParallels(), maxParallel);
}
}

Expand Down Expand Up @@ -228,11 +259,95 @@ private int calculateMaxFluidParallels() {
return aParallelQueue.element().batch;
}

private int calculateMaxFluidParallelsMuTE() {
if (fluidOutputs.length > fluidOutputInventory.getInventory()
.getTanks()) {
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 || aY.amount <= 0) {
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 (int i = 0; i < fluidOutputInventory.getInventory()
.getTanks(); i++) {
IFluidTankLong tank = fluidOutputInventory.getInventory()
.getFluidTank(i);
long tSpaceLeft = tank.getCapacityLong() - tank.getFluidAmountLong();
// check if hatch filled
if (tSpaceLeft <= 0) continue;
// check if hatch is empty and unrestricted
if (tank.getStoredFluid() == null) continue;

for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) {
FluidStack tFluidOutput = entry.getKey();
if (tank.fill(tFluidOutput.getFluid(), tFluidOutput.amount, false) == tFluidOutput.amount) continue;
// this fluid is not prevented by restrictions on output hatch
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 (int i = 0; i < fluidOutputInventory.getInventory()
.getTanks(); i++) {
IFluidTankLong tank = fluidOutputInventory.getInventory()
.getFluidTank(i);
// partially filled or restricted hatch. done in the last pass
if (tank.getStoredFluid() != null) 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);
long tSpaceLeft = tank.getCapacityLong();
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 calculateMaxItemParallels() {
List<ItemStack> busStacks = machine.getItemOutputSlots(itemOutputs);
List<ItemStack> busStacks;

if (muteMode) {
busStacks = itemOutputInventory.getInventory()
.getStacks();
} else {
busStacks = machine.getItemOutputSlots(itemOutputs);
}
// 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<>();
Expand Down Expand Up @@ -307,9 +422,9 @@ private int calculateMaxItemParallels() {
private static class ParallelData {

private int batch;
private int partial;
private long partial;

private ParallelData(int batch, int partial) {
private ParallelData(int batch, long partial) {
this.batch = batch;
this.partial = partial;
}
Expand All @@ -318,10 +433,10 @@ private ParallelData(int batch, int partial) {
private static class ParallelStackInfo<T> {

private int batch;
private int partial;
private long partial;
private final T stack;

private ParallelStackInfo(int batch, int partial, T stack) {
private ParallelStackInfo(int batch, long partial, T stack) {
this.batch = batch;
this.partial = partial;
this.stack = stack;
Expand Down

0 comments on commit 360a84b

Please sign in to comment.