diff options
author | miozune <miozune@gmail.com> | 2023-06-04 19:54:11 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-04 12:54:11 +0200 |
commit | f046db94220c1b582175f858f07fd64e81e6e864 (patch) | |
tree | 217d79501c31b76db9d38a75ccaa1ee09d96117e /src/main/java/gregtech/api | |
parent | 9e4456e39709d815ba28064620ff0290ac14151b (diff) | |
download | GT5-Unofficial-f046db94220c1b582175f858f07fd64e81e6e864.tar.gz GT5-Unofficial-f046db94220c1b582175f858f07fd64e81e6e864.tar.bz2 GT5-Unofficial-f046db94220c1b582175f858f07fd64e81e6e864.zip |
Fix void protection not working with MB with custom output hatch field (#2051)
* Fix void protection not working with MB with custom output hatch field
* forgot to filter
* Add util method for DT-like structure
Diffstat (limited to 'src/main/java/gregtech/api')
14 files changed, 358 insertions, 218 deletions
diff --git a/src/main/java/gregtech/api/fluid/FluidTankGT.java b/src/main/java/gregtech/api/fluid/FluidTankGT.java index 2102f725ae..0c224985e6 100644 --- a/src/main/java/gregtech/api/fluid/FluidTankGT.java +++ b/src/main/java/gregtech/api/fluid/FluidTankGT.java @@ -6,15 +6,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; + import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidTank; +import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.util.GT_Utility; -public class FluidTankGT implements IFluidTank { +public class FluidTankGT implements IFluidTank, IFluidStore { public final FluidTankGT[] AS_ARRAY = new FluidTankGT[] { this }; private FluidStack mFluid; @@ -469,4 +472,14 @@ public class FluidTankGT implements IFluidTank { } return fluidStacks.toArray(new FluidStack[0]); } + + @Override + public boolean isEmptyAndAcceptsAnyFluid() { + return getFluidAmount() == 0; + } + + @Override + public boolean canStoreFluid(@Nonnull FluidStack fluidStack) { + return GT_Utility.areFluidsEqual(mFluid, fluidStack); + } } diff --git a/src/main/java/gregtech/api/interfaces/fluid/IFluidStore.java b/src/main/java/gregtech/api/interfaces/fluid/IFluidStore.java new file mode 100644 index 0000000000..047cf4df5b --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/fluid/IFluidStore.java @@ -0,0 +1,22 @@ +package gregtech.api.interfaces.fluid; + +import javax.annotation.Nonnull; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; + +/** + * Objects implementing this interface can be used for storing certain fluid, especially for recipe output. + */ +public interface IFluidStore extends IFluidTank { + + /** + * @return If this does not have partially filled fluid nor have restriction on what fluid to accept. + */ + boolean isEmptyAndAcceptsAnyFluid(); + + /** + * @return Whether to allow given fluid to be inserted into this. + */ + boolean canStoreFluid(@Nonnull FluidStack fluidStack); +} diff --git a/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java b/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java index cf740a6bc6..04b6b4e6a9 100644 --- a/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java +++ b/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java @@ -19,6 +19,7 @@ import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; import gregtech.api.enums.SoundResource; import gregtech.api.enums.VoidingMode; import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.tileentity.IVoidable; /** * Machines implementing this interface can have logic and GUI buttons @@ -31,7 +32,7 @@ import gregtech.api.gui.modularui.GT_UITextures; * <li>Recipe locking</li> * </ul> */ -public interface ControllerWithOptionalFeatures { +public interface ControllerWithOptionalFeatures extends IVoidable { boolean isAllowedToWork(); @@ -72,29 +73,6 @@ public interface ControllerWithOptionalFeatures { return (ButtonWidget) button; } - /** - * @return if this machine can prevent excess item and fluid from voiding. - */ - boolean supportsVoidProtection(); - - /** - * @return if this machine is configured to not void excess item. - */ - default boolean protectsExcessItem() { - return supportsVoidProtection() && getVoidingMode().protectItem; - } - - /** - * @return if this machine is configured to not void excess fluid. - */ - default boolean protectsExcessFluid() { - return supportsVoidProtection() && getVoidingMode().protectFluid; - } - - VoidingMode getVoidingMode(); - - void setVoidingMode(VoidingMode mode); - Pos2d getVoidingModeButtonPos(); default ButtonWidget createVoidExcessButton(IWidgetBuilder<?> builder) { diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IVoidable.java b/src/main/java/gregtech/api/interfaces/tileentity/IVoidable.java new file mode 100644 index 0000000000..d6325e8597 --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/tileentity/IVoidable.java @@ -0,0 +1,64 @@ +package gregtech.api.interfaces.tileentity; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.VoidingMode; +import gregtech.api.interfaces.fluid.IFluidStore; + +/** + * Machines implementing this interface can have logic to configure whether to void excess output or not. + */ +public interface IVoidable { + + /** + * @return if this machine can prevent excess item and fluid from voiding. + */ + boolean supportsVoidProtection(); + + /** + * @return if this machine is configured to not void excess item. + */ + default boolean protectsExcessItem() { + return supportsVoidProtection() && getVoidingMode().protectItem; + } + + /** + * @return if this machine is configured to not void excess fluid. + */ + default boolean protectsExcessFluid() { + return supportsVoidProtection() && getVoidingMode().protectFluid; + } + + VoidingMode getVoidingMode(); + + void setVoidingMode(VoidingMode mode); + + /** + * @param toOutput List of items this machine is going to output. + * @return List of slots available for item outputs. Null element represents empty slot. + */ + List<ItemStack> getItemOutputSlots(ItemStack[] toOutput); + + /** + * @param toOutput List of fluids this machine is going to output. + * @return List of slots available for fluid outputs. + */ + List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput); + + /** + * @return If this machine has ability to dump item outputs to ME network. + * This doesn't need to check if it can actually dump to ME, + * as this might be called every tick and cause lag. + */ + boolean canDumpItemToME(); + + /** + * @return If this machine has ability to dump fluid outputs to ME network. + * This doesn't need to check if it can actually dump to ME, + * as this might be called every tick and cause lag. + */ + boolean canDumpFluidToME(); +} diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index bb3095084a..a6c5497e8e 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -173,6 +173,11 @@ public abstract class MetaTileEntity implements IMetaTileEntity, IMachineCallbac } } + public boolean isValid() { + return getBaseMetaTileEntity() != null && getBaseMetaTileEntity().getMetaTileEntity() == this + && !getBaseMetaTileEntity().isDead(); + } + @Override public ItemStack getStackForm(long aAmount) { return new ItemStack(GregTech_API.sBlockMachines, (int) aAmount, getBaseMetaTileEntity().getMetaTileID()); diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java index fe3144f3a3..d488eaae3e 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java @@ -5,6 +5,8 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; import java.lang.ref.WeakReference; +import javax.annotation.Nonnull; + import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -24,6 +26,7 @@ import gregtech.GT_Mod; import gregtech.api.gui.modularui.GT_UIInfos; import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.metatileentity.IFluidLockable; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; @@ -33,7 +36,8 @@ import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Utility; import gregtech.common.gui.modularui.widget.FluidLockWidget; -public class GT_MetaTileEntity_Hatch_Output extends GT_MetaTileEntity_Hatch implements IFluidLockable, IAddUIWidgets { +public class GT_MetaTileEntity_Hatch_Output extends GT_MetaTileEntity_Hatch + implements IFluidStore, IFluidLockable, IAddUIWidgets { private String lockedFluidName = null; private WeakReference<EntityPlayer> playerThatLockedfluid = null; @@ -403,12 +407,27 @@ public class GT_MetaTileEntity_Hatch_Output extends GT_MetaTileEntity_Hatch impl return true; } - public boolean canStoreFluid(Fluid fluid) { + @Override + public boolean isEmptyAndAcceptsAnyFluid() { + return mMode == 0 && getFluidAmount() == 0; + } + + @Override + public boolean canStoreFluid(@Nonnull FluidStack fluidStack) { + if (mFluid != null && !GT_Utility.areFluidsEqual(mFluid, fluidStack)) { + return false; + } if (isFluidLocked()) { - if (lockedFluidName == null) return true; - return lockedFluidName.equals(fluid.getName()); + if (lockedFluidName == null) { + return true; + } + return lockedFluidName.equals( + fluidStack.getFluid() + .getName()); + } + if (GT_ModHandler.isSteam(fluidStack)) { + return outputsSteam(); } - if (GT_ModHandler.isSteam(new FluidStack(fluid, 0))) return outputsSteam(); return outputsLiquids(); } 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 a60f9b1cd2..7884301e97 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 @@ -6,7 +6,9 @@ import static mcp.mobius.waila.api.SpecialChars.RED; import static mcp.mobius.waila.api.SpecialChars.RESET; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -14,6 +16,7 @@ import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -43,6 +46,7 @@ import gregtech.api.enums.SoundResource; import gregtech.api.enums.VoidingMode; import gregtech.api.gui.modularui.GT_UIInfos; import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.modularui.ControllerWithOptionalFeatures; import gregtech.api.interfaces.modularui.IAddGregtechLogo; @@ -57,6 +61,8 @@ import gregtech.api.util.GT_Recipe.GT_Recipe_Map; import gregtech.client.GT_SoundLoop; import gregtech.common.GT_Pollution; import gregtech.common.items.GT_MetaGenerated_Tool_01; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_DrillerBase; import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_LargeTurbine; import mcp.mobius.waila.api.IWailaConfigHandler; @@ -126,11 +132,15 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity voidingMode = supportsVoidProtection() ? VoidingMode.VOID_NONE : VoidingMode.VOID_ALL; } + // maybe remove this at some point? public static boolean isValidMetaTileEntity(MetaTileEntity aMetaTileEntity) { - return aMetaTileEntity.getBaseMetaTileEntity() != null && aMetaTileEntity.getBaseMetaTileEntity() - .getMetaTileEntity() == aMetaTileEntity - && !aMetaTileEntity.getBaseMetaTileEntity() - .isDead(); + return aMetaTileEntity.isValid(); + } + + public static <T extends MetaTileEntity> List<T> filterValidMetaTileEntities(Collection<T> metaTileEntities) { + return metaTileEntities.stream() + .filter(MetaTileEntity::isValid) + .collect(Collectors.toList()); } @Override @@ -907,7 +917,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity if (!isValidMetaTileEntity(tHatch) || (restrictiveHatchesOnly && tHatch.mMode == 0)) { continue; } - if (!tHatch.canStoreFluid(copiedFluidStack.getFluid())) continue; + if (!tHatch.canStoreFluid(copiedFluidStack)) continue; int tAmount = tHatch.fill(copiedFluidStack, false); if (tAmount >= copiedFluidStack.amount) { boolean filled = tHatch.fill(copiedFluidStack, true) >= copiedFluidStack.amount; @@ -1560,7 +1570,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return true; } - VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper().setController(this) + VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper().setMachine(this) .setItemOutputs(items) .setFluidOutputs(fluids) .build(); @@ -1603,6 +1613,66 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } @Override + public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) { + List<ItemStack> ret = new ArrayList<>(); + for (final GT_MetaTileEntity_Hatch tBus : filterValidMetaTileEntities(mOutputBusses)) { + final IInventory tBusInv = tBus.getBaseMetaTileEntity(); + for (int i = 0; i < tBusInv.getSizeInventory(); i++) { + ret.add(tBus.getStackInSlot(i)); + } + } + return ret; + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + return filterValidMetaTileEntities(mOutputHatches); + } + + /** + * Util method for DT-like structure to collect list of output hatches. + */ + protected <T extends GT_MetaTileEntity_Hatch_Output> List<? extends IFluidStore> getFluidOutputSlotsByLayer( + FluidStack[] toOutput, List<List<T>> hatchesByLayer) { + List<IFluidStore> ret = new ArrayList<>(); + for (int i = 0; i < toOutput.length; i++) { + if (i >= hatchesByLayer.size()) { + break; + } + FluidStack fluidOutputForLayer = toOutput[i]; + for (GT_MetaTileEntity_Hatch_Output hatch : hatchesByLayer.get(i)) { + if (!hatch.isValid()) continue; + if (fluidOutputForLayer != null) { + ret.add(new OutputHatchWrapper(hatch, f -> GT_Utility.areFluidsEqual(f, fluidOutputForLayer))); + } else { + ret.add(hatch); + } + } + } + return ret; + } + + @Override + public boolean canDumpItemToME() { + for (GT_MetaTileEntity_Hatch tHatch : filterValidMetaTileEntities(mOutputBusses)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) { + return true; + } + } + return false; + } + + @Override + public boolean canDumpFluidToME() { + for (IFluidStore tHatch : getFluidOutputSlots(new FluidStack[0])) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME) { + return true; + } + } + return false; + } + + @Override public Pos2d getVoidingModeButtonPos() { return new Pos2d(8, 91); } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java index afc456f41a..14e7883398 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java @@ -52,6 +52,7 @@ import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; import com.gtnewhorizon.structurelib.util.Vec3Impl; import com.gtnewhorizons.modularui.api.ModularUITextures; import com.gtnewhorizons.modularui.api.drawable.ItemDrawable; +import com.gtnewhorizons.modularui.api.forge.IItemHandler; import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; import com.gtnewhorizons.modularui.api.forge.ListItemHandler; @@ -78,6 +79,7 @@ import gregtech.api.enums.VoidingMode; import gregtech.api.fluid.FluidTankGT; import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.IDescribable; +import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.modularui.ControllerWithOptionalFeatures; import gregtech.api.logic.PowerLogic; import gregtech.api.logic.ProcessingLogic; @@ -1978,6 +1980,33 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override + public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) { + List<ItemStack> ret = new ArrayList<>(); + IItemHandler inv = getOutputInventory(); + if (inv != null && inv.getSlots() > 0) { + for (int i = 0; i < inv.getSlots(); i++) { + ret.add(inv.getStackInSlot(i)); + } + } + return ret; + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + return Arrays.asList(getOutputTanks()); + } + + @Override + public boolean canDumpItemToME() { + return false; + } + + @Override + public boolean canDumpFluidToME() { + return false; + } + + @Override public Pos2d getVoidingModeButtonPos() { return new Pos2d(54, 0); } diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java index ff45f8213b..66f1bac8b8 100644 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -299,9 +299,9 @@ public class GT_ParallelHelper { if (protectExcessItem || protectExcessFluid) { VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper(); if (mMachineMeta != null) { - voidProtectionHelper.setController(mMachineMeta, protectExcessItem, protectExcessFluid); + voidProtectionHelper.setMachine(mMachineMeta, protectExcessItem, protectExcessFluid); } else if (mMachineMulti != null) { - voidProtectionHelper.setController(mMachineMulti, protectExcessItem, protectExcessFluid); + voidProtectionHelper.setMachine(mMachineMulti, protectExcessItem, protectExcessFluid); } voidProtectionHelper.setItemOutputs(mRecipe.mOutputs) .setFluidOutputs(mRecipe.mFluidOutputs) diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index 6f0c7c403e..43dfd0c5b2 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -172,8 +172,8 @@ public class GT_Recipe implements Comparable<GT_Recipe> { public List<List<StackTraceElement>> stackTraces = new ArrayList<>(); private GT_Recipe(GT_Recipe aRecipe, boolean shallow) { - mInputs = shallow ? aRecipe.mInputs : GT_Utility.copyStackArray((Object[]) aRecipe.mInputs); - mOutputs = shallow ? aRecipe.mOutputs : GT_Utility.copyStackArray((Object[]) aRecipe.mOutputs); + mInputs = shallow ? aRecipe.mInputs : GT_Utility.copyItemArray(aRecipe.mInputs); + mOutputs = shallow ? aRecipe.mOutputs : GT_Utility.copyItemArray(aRecipe.mOutputs); mSpecialItems = aRecipe.mSpecialItems; mChances = aRecipe.mChances; mFluidInputs = shallow ? aRecipe.mFluidInputs : GT_Utility.copyFluidArray(aRecipe.mFluidInputs); diff --git a/src/main/java/gregtech/api/util/GT_RecipeBuilder.java b/src/main/java/gregtech/api/util/GT_RecipeBuilder.java index 41ad02e242..e05798479e 100644 --- a/src/main/java/gregtech/api/util/GT_RecipeBuilder.java +++ b/src/main/java/gregtech/api/util/GT_RecipeBuilder.java @@ -1,5 +1,8 @@ package gregtech.api.util; +import static gregtech.api.util.GT_Utility.copyFluidArray; +import static gregtech.api.util.GT_Utility.copyItemArray; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -378,26 +381,6 @@ public class GT_RecipeBuilder { return metadata(GT_RecipeConstants.LOW_GRAVITY, true); } - private static ItemStack[] copy(ItemStack[] arr) { - if (arr == null) return null; - ItemStack[] ret = new ItemStack[arr.length]; - for (int i = 0; i < arr.length; i++) { - if (arr[i] == null) continue; - ret[i] = arr[i].copy(); - } - return ret; - } - - private static FluidStack[] copy(FluidStack[] arr) { - if (arr == null) return null; - FluidStack[] ret = new FluidStack[arr.length]; - for (int i = 0; i < arr.length; i++) { - if (arr[i] == null) continue; - ret[i] = arr[i].copy(); - } - return ret; - } - private static <T> T[] copy(T[] arr) { return arr == null ? null : arr.clone(); } @@ -414,12 +397,12 @@ public class GT_RecipeBuilder { */ public GT_RecipeBuilder copy() { return new GT_RecipeBuilder( - copy(inputsBasic), + copyItemArray(inputsBasic), copy(inputsOreDict), - copy(outputs), + copyItemArray(outputs), copy(alts), - copy(fluidInputs), - copy(fluidOutputs), + copyFluidArray(fluidInputs), + copyFluidArray(fluidOutputs), copy(chances), special, duration, @@ -441,12 +424,12 @@ public class GT_RecipeBuilder { */ public GT_RecipeBuilder copyNoMetadata() { return new GT_RecipeBuilder( - copy(inputsBasic), + copyItemArray(inputsBasic), copy(inputsOreDict), - copy(outputs), + copyItemArray(outputs), copy(alts), - copy(fluidInputs), - copy(fluidOutputs), + copyFluidArray(fluidInputs), + copyFluidArray(fluidOutputs), copy(chances), special, duration, diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java index 5e8e9efbca..7f423e0c19 100644 --- a/src/main/java/gregtech/api/util/GT_Utility.java +++ b/src/main/java/gregtech/api/util/GT_Utility.java @@ -2816,12 +2816,14 @@ public class GT_Utility { } public static FluidStack[] copyFluidArray(FluidStack... aStacks) { + if (aStacks == null) return null; FluidStack[] rStacks = new FluidStack[aStacks.length]; for (int i = 0; i < aStacks.length; i++) if (aStacks[i] != null) rStacks[i] = aStacks[i].copy(); return rStacks; } - public static ItemStack[] copyStackArray(Object... aStacks) { + public static ItemStack[] copyItemArray(ItemStack... aStacks) { + if (aStacks == null) return null; ItemStack[] rStacks = new ItemStack[aStacks.length]; for (int i = 0; i < aStacks.length; i++) rStacks[i] = copy(aStacks[i]); return rStacks; diff --git a/src/main/java/gregtech/api/util/OutputHatchWrapper.java b/src/main/java/gregtech/api/util/OutputHatchWrapper.java new file mode 100644 index 0000000000..b2e74d24cf --- /dev/null +++ b/src/main/java/gregtech/api/util/OutputHatchWrapper.java @@ -0,0 +1,65 @@ +package gregtech.api.util; + +import java.util.function.Predicate; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; + +/** + * Wrapper for output hatch to allow multiblocks to apply specific filter. + */ +public class OutputHatchWrapper implements IFluidStore { + + private final GT_MetaTileEntity_Hatch_Output outputHatch; + private final Predicate<FluidStack> filter; + + public OutputHatchWrapper(GT_MetaTileEntity_Hatch_Output outputHatch, Predicate<FluidStack> filter) { + this.outputHatch = outputHatch; + this.filter = filter; + } + + @Override + public FluidStack getFluid() { + return outputHatch.getFluid(); + } + + @Override + public int getFluidAmount() { + return outputHatch.getFluidAmount(); + } + + @Override + public int getCapacity() { + return outputHatch.getCapacity(); + } + + @Override + public FluidTankInfo getInfo() { + return outputHatch.getInfo(); + } + + @Override + public int fill(FluidStack resource, boolean doFill) { + return outputHatch.fill(resource, doFill); + } + + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + return outputHatch.drain(maxDrain, doDrain); + } + + @Override + public boolean isEmptyAndAcceptsAnyFluid() { + return outputHatch.isEmptyAndAcceptsAnyFluid(); + } + + @Override + public boolean canStoreFluid(@NotNull FluidStack fluidStack) { + return outputHatch.canStoreFluid(fluidStack) && filter.test(fluidStack); + } +} diff --git a/src/main/java/gregtech/api/util/VoidProtectionHelper.java b/src/main/java/gregtech/api/util/VoidProtectionHelper.java index 9a66a55874..fe80bc97b4 100644 --- a/src/main/java/gregtech/api/util/VoidProtectionHelper.java +++ b/src/main/java/gregtech/api/util/VoidProtectionHelper.java @@ -1,28 +1,19 @@ 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.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.tileentity.IVoidable; 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. @@ -30,13 +21,9 @@ import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; public class VoidProtectionHelper { /** - * A MetaTileEntity Controller + * Machine used for calculation */ - private GT_MetaTileEntity_MultiBlockBase machineMeta; - /** - * A MultiTileEntity Controller - */ - private Controller<?> machineMulti; + private IVoidable machine; /** * Does void protection enabled for items */ @@ -66,37 +53,39 @@ public class VoidProtectionHelper { /** * Sets MetaTE controller, with current configuration for void protection mode. + * + * @deprecated Use {@link #setMachine(IVoidable)} */ + @Deprecated public VoidProtectionHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta) { return setController(machineMeta, machineMeta.protectsExcessItem(), machineMeta.protectsExcessFluid()); } /** * Sets MetaTE controller, with void protection mode forcibly. + * + * @deprecated Use {@link #setMachine(IVoidable, boolean, boolean)} */ + @Deprecated public VoidProtectionHelper setController(GT_MetaTileEntity_MultiBlockBase machineMeta, boolean protectExcessItem, boolean protectExcessFluid) { - this.protectExcessItem = protectExcessItem; - this.protectExcessFluid = protectExcessFluid; - this.machineMeta = machineMeta; - return this; + return setMachine(machineMeta, protectExcessItem, protectExcessFluid); } /** - * Sets MuTE controller, with current configuration for void protection mode. + * Sets machine, with current configuration for void protection mode. */ - public VoidProtectionHelper setController(Controller<?> machineMulti) { - return setController(machineMulti, machineMulti.protectsExcessItem(), machineMulti.protectsExcessFluid()); + public VoidProtectionHelper setMachine(IVoidable machine) { + return setMachine(machine, machine.protectsExcessItem(), machine.protectsExcessFluid()); } /** - * Sets MuTE controller, with void protection mode forcibly. + * Sets machine, with void protection mode forcibly. */ - public VoidProtectionHelper setController(Controller<?> machineMulti, boolean protectExcessItem, - boolean protectExcessFluid) { + public VoidProtectionHelper setMachine(IVoidable machine, boolean protectExcessItem, boolean protectExcessFluid) { this.protectExcessItem = protectExcessItem; this.protectExcessFluid = protectExcessFluid; - this.machineMulti = machineMulti; + this.machine = machine; return this; } @@ -125,6 +114,9 @@ public class VoidProtectionHelper { if (built) { throw new IllegalStateException("Tried to build twice"); } + if (machine == null) { + throw new IllegalStateException("Machine is not set"); + } built = true; determineParallel(); return this; @@ -151,85 +143,21 @@ public class VoidProtectionHelper { fluidOutputs = new FluidStack[0]; } - // Don't check ControllerWithOptionalFeatures#protectsExcessItem nor #protectsExcessFluid here, + // Don't check IVoidable#protectsExcessItem nor #protectsExcessFluid here, // to allow more involved setting for void protections (see ComplexParallelProcessingLogic) - 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 (protectExcessItem && itemOutputs.length > 0 && !tMEOutputBus) { - maxParallel = Math.min(calculateMaxItemParallelsForMetaTEs(), maxParallel); - } - if (protectExcessFluid && fluidOutputs.length > 0 && !tMEOutputHatch) { - maxParallel = Math.min(calculateMaxFluidParallelsForMetaTEs(), maxParallel); - } - } else if (machineMulti != null) { - if (protectExcessItem && itemOutputs.length > 0) { - maxParallel = Math.min(calculateMaxItemParallelsForMuTEs(), maxParallel); - } - if (protectExcessFluid && fluidOutputs.length > 0) { - 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; + if (protectExcessItem && itemOutputs.length > 0 && !machine.canDumpItemToME()) { + maxParallel = Math.min(calculateMaxItemParallels(), maxParallel); } - 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; + if (protectExcessFluid && fluidOutputs.length > 0 && !machine.canDumpFluidToME()) { + maxParallel = Math.min(calculateMaxFluidParallels(), maxParallel); } - 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) { + private int calculateMaxFluidParallels() { + List<? extends IFluidStore> hatches = machine.getFluidOutputSlots(fluidOutputs); if (hatches.size() < fluidOutputs.length) { return 0; } @@ -257,25 +185,23 @@ public class VoidProtectionHelper { return maxParallel; } - for (T tHatch : hatches) { + for (IFluidStore 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; + if (tHatch.isEmptyAndAcceptsAnyFluid()) continue; for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) { FluidStack tFluidOutput = entry.getKey(); - if (!acceptsFluid.apply(tHatch, tFluidOutput)) continue; + if (!tHatch.canStoreFluid(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; - } + 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 @@ -287,9 +213,9 @@ public class VoidProtectionHelper { .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; + for (IFluidStore tHatch : hatches) { + // partially filled or restricted hatch. done in the last pass + if (!tHatch.isEmptyAndAcceptsAnyFluid()) continue; ParallelStackInfo<FluidStack> tParallel = aParallelQueue.poll(); assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings @@ -305,44 +231,8 @@ public class VoidProtectionHelper { /** * 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) { + private int calculateMaxItemParallels() { + List<ItemStack> 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<>(); |