diff --git a/src/main/java/gregtech/api/capability/IFilter.java b/src/main/java/gregtech/api/capability/IFilter.java
new file mode 100644
index 00000000000..9d7463b9a3a
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/IFilter.java
@@ -0,0 +1,163 @@
+package gregtech.api.capability;
+
+import javax.annotation.Nonnull;
+import java.util.Comparator;
+import java.util.function.Predicate;
+
+/**
+ * Base type for generic filters. In addition to the predicate method, this interface provides priority primarily used
+ * in insertion logic.
+ *
+ * Although this class can be used as lambda interface, it is strongly encouraged to define priority according to
+ * criteria specified in javadocs on {@link #getPriority()}.
+ *
+ * @param type of the instance for filtering
+ */
+@FunctionalInterface
+public interface IFilter extends Predicate {
+
+ /**
+ * Compare logic for filter instances.
+ */
+ Comparator> FILTER_COMPARATOR = Comparator
+ .>comparingInt(IFilter::getPriority)
+ .reversed();
+
+ /**
+ * Test if this filter accepts the instance. If the parameter is {@code null}, then the behavior of this method is
+ * undefined.
+ *
+ * @param t instance to be tested
+ * @return if this filter accepts the instance
+ */
+ @Override
+ boolean test(@Nonnull T t);
+
+ /**
+ * Return insertion priority for this filter. The priority is applied on some insertion logics, to prioritize
+ * certain filters from others. The priority system uses reverse ordering; higher priority values have
+ * precedence over lower ones.
+ *
+ * - Whitelist filters have {@code Integer.MAX_VALUE - whitelistSize} as their default priority. The highest
+ * possible number for whitelist priority is {@code Integer.MAX_VALUE - 1}, where only one entry is
+ * whitelisted. The priority can be computed using {@link #whitelistPriority(int)}.
+ * - Blacklist filters have {@code Integer.MIN_VALUE + 1 + blacklistSize} as their default priority. The
+ * lowest possible number for blacklist priority is {@code Integer.MIN_VALUE + 2}, where only one entry is
+ * blacklisted. The priority can be computed using {@link #blacklistPriority(int)}.
+ * - Filters with unspecified priority have {@code 0} as their priority.
+ * - Two values, {@link #firstPriority()}, and {@link #lastPriority()}, can be used to create filter
+ * with highest/lowest possible priority respectively.
+ * - For custom filter implementations, it is expected to have at least positive priority for whitelist-like
+ * filters, and negative priority for blacklist-like filters. Methods {@link #whitelistLikePriority()} and
+ * {@link #blacklistLikePriority()} are available as standard priority.
+ * - {@link #noPriority()} is reserved for 'no-priority' filters; it's applicable to no-op filters and
+ * its reverse (everything filter).
+ *
+ * Although the priority is not a strict requirement, it is strongly encouraged to specify priority according to
+ * these criteria.
+ *
+ * @return insertion priority
+ */
+ default int getPriority() {
+ return 0;
+ }
+
+ /**
+ * Return the reverse of this filter. The resulting filter returns the opposite of what the original filter would,
+ * has priority of inverse of the original.
+ *
+ * @return reverse of this filter
+ */
+ @Override
+ @Nonnull
+ default IFilter negate() {
+ return new IFilter<>() {
+ @Override
+ public boolean test(@Nonnull T t) {
+ return !IFilter.this.test(t);
+ }
+
+ @Override
+ public int getPriority() {
+ return -IFilter.this.getPriority();
+ }
+
+ @Override
+ @Nonnull
+ public IFilter negate() {
+ return IFilter.this;
+ }
+ };
+ }
+
+ /**
+ * Default priority logic for all whitelist filters.
+ *
+ * Whitelist filters have {@code Integer.MAX_VALUE - whitelistSize} as their default priority. The highest possible
+ * number for whitelist priority is {@code Integer.MAX_VALUE - 1}, where only one entry is whitelisted.
+ *
+ * @param whitelistSize the size of whitelist entries
+ * @return default priority logic for all whitelist filters
+ */
+ static int whitelistPriority(int whitelistSize) {
+ return Integer.MAX_VALUE - whitelistSize;
+ }
+
+ /**
+ * Default priority logic for all blacklist filters.
+ *
+ * Blacklist filters have {@code Integer.MIN_VALUE + 1 + blacklistSize} as their default priority. The lowest
+ * possible number for blacklist priority is {@code Integer.MIN_VALUE + 2}, where only one entry is blacklisted.
+ *
+ * @param blacklistSize the size of whitelist entries
+ * @return default priority logic for all blacklist filters
+ */
+ static int blacklistPriority(int blacklistSize) {
+ return Integer.MIN_VALUE + 1 + blacklistSize;
+ }
+
+ /**
+ * Recommended priority for 'whitelist-like' filters; can be adjusted.
+ *
+ * @return recommended priority for 'whitelist-like' filters
+ */
+ static int whitelistLikePriority() {
+ return 1000;
+ }
+
+ /**
+ * Recommended priority for 'blacklist-like' filters; can be adjusted.
+ *
+ * @return recommended priority for 'blacklist-like' filters
+ */
+ static int blacklistLikePriority() {
+ return -1000;
+ }
+
+ /**
+ * Highest possible priority for filters.
+ *
+ * @return highest possible priority
+ */
+ static int firstPriority() {
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Lowest possible priority for filters.
+ *
+ * @return lowest possible priority
+ */
+ static int lastPriority() {
+ return Integer.MIN_VALUE + 1;
+ }
+
+ /**
+ * Special priority for 'no-priority' filters; applicable to no-op filters and its reverse (everything filter).
+ *
+ * @return special priority for 'no-priority' filters
+ */
+ static int noPriority() {
+ return Integer.MIN_VALUE;
+ }
+}
diff --git a/src/main/java/gregtech/api/capability/IFilteredFluidContainer.java b/src/main/java/gregtech/api/capability/IFilteredFluidContainer.java
new file mode 100644
index 00000000000..ca35dc0b32b
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/IFilteredFluidContainer.java
@@ -0,0 +1,27 @@
+package gregtech.api.capability;
+
+import net.minecraftforge.fluids.FluidStack;
+
+import javax.annotation.Nullable;
+import java.util.Comparator;
+
+/**
+ * Interface for fluid containers ({@link net.minecraftforge.fluids.IFluidTank IFluidTank} or
+ * {@link net.minecraftforge.fluids.capability.IFluidHandler IFluidHandler}) associated with {@link IFilter}.
+ */
+public interface IFilteredFluidContainer {
+
+ /**
+ * Compare logic for filtered instances.
+ */
+ Comparator COMPARATOR = Comparator.nullsLast(
+ Comparator.comparing(IFilteredFluidContainer::getFilter, IFilter.FILTER_COMPARATOR)
+ );
+
+ /**
+ * @return instance of {@link IFilter} associated to this object, or {@code null} if there's no filter
+ * associated.
+ */
+ @Nullable
+ IFilter getFilter();
+}
diff --git a/src/main/java/gregtech/api/capability/IMultipleTankHandler.java b/src/main/java/gregtech/api/capability/IMultipleTankHandler.java
index eae6890271b..eaf5ae04cf4 100644
--- a/src/main/java/gregtech/api/capability/IMultipleTankHandler.java
+++ b/src/main/java/gregtech/api/capability/IMultipleTankHandler.java
@@ -1,21 +1,248 @@
package gregtech.api.capability;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTank;
+import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
+import net.minecraftforge.fluids.capability.IFluidTankProperties;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
-public interface IMultipleTankHandler extends IFluidHandler, Iterable {
+/**
+ * Base class for multi-tank fluid handlers. Handles insertion logic, along with other standard
+ * {@link IFluidHandler} functionalities.
+ *
+ * @see gregtech.api.capability.impl.FluidTankList FluidTankList
+ */
+public interface IMultipleTankHandler extends IFluidHandler, Iterable {
- List getFluidTanks();
+ /**
+ * Comparator for entries that can be used in insertion logic
+ */
+ Comparator ENTRY_COMPARATOR = (o1, o2) -> {
+ // #1: non-empty tank first
+ boolean empty1 = o1.getFluidAmount() <= 0;
+ boolean empty2 = o2.getFluidAmount() <= 0;
+ if (empty1 != empty2) return empty1 ? 1 : -1;
- int getTanks();
+ // #2: filter priority
+ IFilter filter1 = o1.getFilter();
+ IFilter filter2 = o2.getFilter();
+ if (filter1 == null) return filter2 == null ? 0 : 1;
+ if (filter2 == null) return -1;
+ return IFilter.FILTER_COMPARATOR.compare(filter1, filter2);
+ };
+
+ /**
+ * @return unmodifiable view of {@code MultiFluidTankEntry}s. Note that it's still possible to access
+ * and modify inner contents of the tanks.
+ */
+ @Nonnull
+ List getFluidTanks();
- IFluidTank getTankAt(int index);
+ /**
+ * @return Number of tanks in this tank handler
+ */
+ int getTanks();
- int getIndexOfFluid(FluidStack other);
+ @Nonnull
+ MultiFluidTankEntry getTankAt(int index);
+ /**
+ * @return {@code false} if insertion to this fluid handler enforces input to be
+ * filled in one slot at max. {@code true} if it bypasses the rule.
+ */
boolean allowSameFluidFill();
+
+ /**
+ * Tries to search tank with contents equal to {@code fluidStack}. If {@code fluidStack} is
+ * {@code null}, an empty tank is searched instead.
+ *
+ * @param fluidStack Fluid stack to search index
+ * @return Index corresponding to tank at {@link #getFluidTanks()} with matching
+ */
+ default int getIndexOfFluid(@Nullable FluidStack fluidStack) {
+ List fluidTanks = getFluidTanks();
+ for (int i = 0; i < fluidTanks.size(); i++) {
+ FluidStack tankStack = fluidTanks.get(i).getFluid();
+ if (fluidStack == tankStack || tankStack != null && tankStack.isFluidEqual(fluidStack)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ default Iterator iterator() {
+ return getFluidTanks().iterator();
+ }
+
+ /**
+ * Entry of multi fluid tanks. Retains reference to original {@link IMultipleTankHandler} for accessing
+ * information such as {@link IMultipleTankHandler#allowSameFluidFill()}.
+ */
+ final class MultiFluidTankEntry implements IFluidTank, IFluidHandler, IFilteredFluidContainer {
+
+ private final IMultipleTankHandler tank;
+ private final IFluidTank delegate;
+
+ public MultiFluidTankEntry(@Nonnull IMultipleTankHandler tank, @Nonnull IFluidTank delegate) {
+ this.tank = tank;
+ this.delegate = delegate;
+ }
+
+ @Nonnull
+ public IMultipleTankHandler getTank() {
+ return tank;
+ }
+
+ @Nonnull
+ public IFluidTank getDelegate() {
+ return delegate;
+ }
+
+ public boolean allowSameFluidFill() {
+ return tank.allowSameFluidFill();
+ }
+
+ @Nullable
+ @Override
+ public IFilter getFilter() {
+ return this.delegate instanceof IFilteredFluidContainer filtered ? filtered.getFilter() : null;
+ }
+
+ @Nonnull
+ public IFluidTankProperties[] getTankProperties() {
+ return delegate instanceof IFluidHandler fluidHandler ?
+ fluidHandler.getTankProperties() :
+ new IFluidTankProperties[]{new FallbackTankProperty()};
+ }
+
+ public NBTTagCompound trySerialize() {
+ if (delegate instanceof FluidTank fluidTank) {
+ return fluidTank.writeToNBT(new NBTTagCompound());
+ } else if (delegate instanceof INBTSerializable serializable) {
+ try {
+ return (NBTTagCompound) serializable.serializeNBT();
+ } catch (ClassCastException ignored) {}
+ }
+ return new NBTTagCompound();
+ }
+
+ @SuppressWarnings({"unchecked"})
+ public void tryDeserialize(NBTTagCompound tag) {
+ if (delegate instanceof FluidTank fluidTank) {
+ fluidTank.readFromNBT(tag);
+ } else if (delegate instanceof INBTSerializable serializable) {
+ try {
+ serializable.deserializeNBT(tag);
+ } catch (ClassCastException ignored) {}
+ }
+ }
+
+ @Nullable
+ @Override
+ public FluidStack getFluid() {
+ return delegate.getFluid();
+ }
+
+ @Override
+ public int getFluidAmount() {
+ return delegate.getFluidAmount();
+ }
+
+ @Override
+ public int getCapacity() {
+ return delegate.getCapacity();
+ }
+
+ @Override
+ public FluidTankInfo getInfo() {
+ return delegate.getInfo();
+ }
+
+ @Override
+ public int fill(FluidStack resource, boolean doFill) {
+ return delegate.fill(resource, doFill);
+ }
+
+ @Nullable
+ @Override
+ public FluidStack drain(FluidStack resource, boolean doDrain) {
+ if (resource == null || resource.amount <= 0) {
+ return null;
+ }
+ if (delegate instanceof IFluidHandler fluidHandler) {
+ return fluidHandler.drain(resource, doDrain);
+ }
+ // just imitate the logic
+ FluidStack fluid = delegate.getFluid();
+ return fluid != null && fluid.isFluidEqual(resource) ? drain(resource.amount, doDrain) : null;
+ }
+
+ @Nullable
+ @Override
+ public FluidStack drain(int maxDrain, boolean doDrain) {
+ return delegate.drain(maxDrain, doDrain);
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ @Override
+ @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+ public boolean equals(Object obj) {
+ return this == obj || delegate.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+
+ private final class FallbackTankProperty implements IFluidTankProperties {
+
+ @Nullable
+ @Override
+ public FluidStack getContents() {
+ return delegate.getFluid();
+ }
+
+ @Override
+ public int getCapacity() {
+ return delegate.getCapacity();
+ }
+
+ @Override
+ public boolean canFill() {
+ return true;
+ }
+
+ @Override
+ public boolean canDrain() {
+ return true;
+ }
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluidStack) {
+ IFilter filter = getFilter();
+ return filter == null || filter.test(fluidStack);
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluidStack) {
+ return true;
+ }
+ }
+ }
}
diff --git a/src/main/java/gregtech/api/capability/IPropertyFluidFilter.java b/src/main/java/gregtech/api/capability/IPropertyFluidFilter.java
new file mode 100644
index 00000000000..52a1e3d5627
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/IPropertyFluidFilter.java
@@ -0,0 +1,80 @@
+package gregtech.api.capability;
+
+import gregtech.api.fluids.MaterialFluid;
+import gregtech.api.fluids.fluidType.FluidType;
+import gregtech.api.fluids.fluidType.FluidTypes;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Fluid filter based on fluid properties; i.e. temperature, fluid state, and various material flags such as acid
+ * and plasma.
+ *
+ * @see FluidType
+ * @see FluidTypes
+ * @see MaterialFluid
+ */
+public interface IPropertyFluidFilter extends IFilter {
+
+ /**
+ * Minimum temperature of the fluid in kelvin before it starts being considered 'cryogenic'; if a fluid has lower
+ * temperature than this, it's considered cryogenic.
+ */
+ int CRYOGENIC_TEMPERATURE_THRESHOLD = 120;
+
+ @Override
+ default boolean test(@Nonnull FluidStack stack) {
+ Fluid fluid = stack.getFluid();
+ if (fluid.getTemperature() < CRYOGENIC_TEMPERATURE_THRESHOLD && !isCryoProof()) return false;
+ if (fluid.isGaseous() && !isGasProof()) return false;
+
+ if (fluid instanceof MaterialFluid materialFluid) {
+ FluidType fluidType = materialFluid.getFluidType();
+ if (fluidType == FluidTypes.ACID) {
+ if (!isAcidProof()) return false;
+ } else if (fluidType == FluidTypes.PLASMA) {
+ return isPlasmaProof(); // bypass max temperature check below
+ }
+ }
+ return fluid.getTemperature() <= getMaxFluidTemperature();
+ }
+
+ @Override
+ default int getPriority() {
+ return IFilter.blacklistLikePriority();
+ }
+
+ /**
+ * This is always checked, regardless of the contained fluid being a {@link MaterialFluid} or not
+ *
+ * @return the maximum allowed temperature for a fluid
+ */
+ int getMaxFluidTemperature();
+
+ /**
+ * This is always checked, regardless of the contained fluid being a {@link MaterialFluid} or not
+ *
+ * @return whether this filter allows gases
+ */
+ boolean isGasProof();
+
+ /**
+ * @return whether this filter allows acids
+ * @see FluidTypes
+ */
+ boolean isAcidProof();
+
+ /**
+ * @return whether this filter allows cryogenic fluids
+ * @see FluidTypes
+ */
+ boolean isCryoProof();
+
+ /**
+ * @return whether this filter allows plasmas
+ * @see FluidTypes
+ */
+ boolean isPlasmaProof();
+}
diff --git a/src/main/java/gregtech/api/capability/IThermalFluidHandlerItemStack.java b/src/main/java/gregtech/api/capability/IThermalFluidHandlerItemStack.java
index d3e005d592f..95eec218209 100644
--- a/src/main/java/gregtech/api/capability/IThermalFluidHandlerItemStack.java
+++ b/src/main/java/gregtech/api/capability/IThermalFluidHandlerItemStack.java
@@ -6,20 +6,24 @@
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
+import javax.annotation.Nullable;
+
/**
* Interface for FluidHandlerItemStacks which handle GT's unique fluid mechanics
+ *
* @see FluidType
* @see FluidTypes
* @see MaterialFluid
+ * @deprecated use {@link IPropertyFluidFilter}
*/
+@Deprecated
public interface IThermalFluidHandlerItemStack {
/**
- *
* @param stack the {@link FluidStack} to check
* @return whether the FluidStack can be used to fill this fluid container
*/
- default boolean canFillFluidType(FluidStack stack) {
+ default boolean canFillFluidType(@Nullable FluidStack stack) {
if (stack == null || stack.getFluid() == null) return false;
Fluid fluid = stack.getFluid();
@@ -51,23 +55,20 @@ default boolean canFillFluidType(FluidStack stack) {
boolean isGasProof();
/**
- * @see FluidTypes
- *
* @return true if this fluid container allows acids, otherwise false
+ * @see FluidTypes
*/
boolean isAcidProof();
/**
- * @see FluidTypes
- *
* @return true if this fluid container allows cryogenics, otherwise false
+ * @see FluidTypes
*/
boolean isCryoProof();
/**
- * @see FluidTypes
- *
* @return true if this fluid container allows plasmas, otherwise false
+ * @see FluidTypes
*/
boolean isPlasmaProof();
}
diff --git a/src/main/java/gregtech/api/capability/impl/BoilerRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/BoilerRecipeLogic.java
index 3f99bdc1f8f..e799e5e913c 100644
--- a/src/main/java/gregtech/api/capability/impl/BoilerRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/BoilerRecipeLogic.java
@@ -3,7 +3,6 @@
import gregtech.api.GTValues;
import gregtech.api.capability.IMultiblockController;
import gregtech.api.capability.IMultipleTankHandler;
-import gregtech.api.recipes.ModHandler;
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.unification.material.Materials;
@@ -13,6 +12,7 @@
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
+import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.NonNullList;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.IFluidHandler;
@@ -72,7 +72,7 @@ protected void trySearchNewRecipe() {
for (IFluidTank fluidTank : importFluids.getFluidTanks()) {
FluidStack fuelStack = fluidTank.drain(Integer.MAX_VALUE, false);
- if (fuelStack == null || ModHandler.isWater(fuelStack)) continue;
+ if (fuelStack == null || CommonFluidFilters.BOILER_FLUID.test(fuelStack)) continue;
Recipe dieselRecipe = RecipeMaps.COMBUSTION_GENERATOR_FUELS.findRecipe(
GTValues.V[GTValues.MAX], dummyList, Collections.singletonList(fuelStack));
@@ -101,7 +101,7 @@ protected void trySearchNewRecipe() {
IItemHandlerModifiable importItems = boiler.getImportItems();
for (int i = 0; i < importItems.getSlots(); i++) {
ItemStack stack = importItems.getStackInSlot(i);
- int fuelBurnTime = (int) Math.ceil(ModHandler.getFuelValue(stack));
+ int fuelBurnTime = (int) Math.ceil(TileEntityFurnace.getItemBurnTime(stack));
if (fuelBurnTime / 80 > 0) { // try to ensure this fuel can burn for at least 1 tick
if (FluidUtil.getFluidHandler(stack) != null) continue;
this.excessFuel += fuelBurnTime % 80;
@@ -143,7 +143,7 @@ protected void updateRecipeProgress() {
getMetaTileEntity().explodeMultiblock((currentHeat / getMaximumHeat()) * 8);
} else {
setLastTickSteam(generatedSteam);
- getOutputTank().fill(ModHandler.getSteam(generatedSteam), true);
+ getOutputTank().fill(Materials.Steam.getFluid(generatedSteam), true);
}
}
if (currentHeat < getMaximumHeat()) {
diff --git a/src/main/java/gregtech/api/capability/impl/CommonFluidFilters.java b/src/main/java/gregtech/api/capability/impl/CommonFluidFilters.java
new file mode 100644
index 00000000000..8a2b633df16
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/impl/CommonFluidFilters.java
@@ -0,0 +1,114 @@
+package gregtech.api.capability.impl;
+
+import gregtech.api.capability.IFilter;
+import gregtech.api.unification.material.Material;
+import gregtech.api.unification.material.Materials;
+import gregtech.common.ConfigHolder;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidRegistry;
+import net.minecraftforge.fluids.FluidStack;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Common fluid filter implementations.
+ */
+public enum CommonFluidFilters implements IFilter {
+ ALLOW_ALL {
+ @Override
+ public boolean test(@Nonnull FluidStack fluid) {
+ return true;
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.noPriority();
+ }
+
+ @Override
+ public IFilter negate() {
+ return DISALLOW_ALL;
+ }
+ },
+ DISALLOW_ALL {
+ @Override
+ public boolean test(@Nonnull FluidStack fluid) {
+ return false;
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.noPriority();
+ }
+
+ @Override
+ public IFilter negate() {
+ return ALLOW_ALL;
+ }
+ },
+ BOILER_FLUID {
+ @Override
+ public boolean test(@Nonnull FluidStack fluid) {
+ if (matchesFluid(fluid, FluidRegistry.WATER) || matchesFluid(fluid, Materials.DistilledWater)) {
+ return true;
+ }
+
+ for (String fluidName : ConfigHolder.machines.boilerFluids) {
+ Fluid boilerFluid = FluidRegistry.getFluid(fluidName);
+ if (boilerFluid != null && matchesFluid(fluid, boilerFluid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.whitelistLikePriority();
+ }
+ },
+ STEAM {
+ @Override
+ public boolean test(@Nonnull FluidStack fluid) {
+ return matchesFluid(fluid, Materials.Steam);
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.whitelistPriority(1);
+ }
+ },
+ LIGHTER_FUEL {
+ @Override
+ public boolean test(@Nonnull FluidStack fluidStack) {
+ return matchesFluid(fluidStack, Materials.Butane) || matchesFluid(fluidStack, Materials.Propane);
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.whitelistPriority(2);
+ }
+ };
+
+ /**
+ * Comparison logic identical to {@link FluidStack#isFluidEqual}, without instantiation of FluidStack instance
+ *
+ * @param fluidStack fluid stack
+ * @param fluidMaterial material with fluid
+ * @return whether the fluid in fluid stack and fluid associated with the material are equal
+ */
+ public static boolean matchesFluid(@Nonnull FluidStack fluidStack, @Nonnull Material fluidMaterial) {
+ return fluidStack.tag == null && fluidStack.getFluid() == fluidMaterial.getFluid();
+ }
+
+ /**
+ * Comparison logic identical to {@link FluidStack#isFluidEqual}, without instantiation of FluidStack instance
+ *
+ * @param fluidStack fluid stack
+ * @param fluid fluid
+ * @return whether the fluid in fluid stack and fluid parameter are equal
+ */
+ public static boolean matchesFluid(@Nonnull FluidStack fluidStack, @Nonnull Fluid fluid) {
+ return fluidStack.tag == null && fluidStack.getFluid() == fluid;
+ }
+}
diff --git a/src/main/java/gregtech/api/capability/impl/FilteredFluidHandler.java b/src/main/java/gregtech/api/capability/impl/FilteredFluidHandler.java
index ab87ac7dcba..702cf794578 100644
--- a/src/main/java/gregtech/api/capability/impl/FilteredFluidHandler.java
+++ b/src/main/java/gregtech/api/capability/impl/FilteredFluidHandler.java
@@ -1,15 +1,19 @@
package gregtech.api.capability.impl;
+import gregtech.api.capability.IFilter;
+import gregtech.api.capability.IFilteredFluidContainer;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Predicate;
-public class FilteredFluidHandler extends FluidTank {
+public class FilteredFluidHandler extends FluidTank implements IFilteredFluidContainer {
- private Predicate fillPredicate;
+ @Nullable
+ private IFilter filter;
public FilteredFluidHandler(int capacity) {
super(capacity);
@@ -23,13 +27,34 @@ public FilteredFluidHandler(Fluid fluid, int amount, int capacity) {
super(fluid, amount, capacity);
}
- public FilteredFluidHandler setFillPredicate(Predicate predicate) {
- this.fillPredicate = predicate;
+ @Nullable
+ @Override
+ public IFilter getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * Set filter instance. If {@code null} is given, then the filter is set to be
+ *
+ * @param filter new filter instance
+ * @return this
+ */
+ @Nonnull
+ public FilteredFluidHandler setFilter(@Nullable IFilter filter) {
+ this.filter = filter;
return this;
}
+ /**
+ * @deprecated Use {@link #setFilter(IFilter)} with new filter API.
+ */
+ @Deprecated
+ public FilteredFluidHandler setFillPredicate(Predicate predicate) {
+ return setFilter(predicate::test);
+ }
+
@Override
public boolean canFillFluidType(FluidStack fluid) {
- return canFill() && (fillPredicate == null || fillPredicate.test(fluid));
+ return canFill() && (this.filter == null || this.filter.test(fluid));
}
}
diff --git a/src/main/java/gregtech/api/capability/impl/FluidTankList.java b/src/main/java/gregtech/api/capability/impl/FluidTankList.java
index d8eeff3d058..79425f9731a 100644
--- a/src/main/java/gregtech/api/capability/impl/FluidTankList.java
+++ b/src/main/java/gregtech/api/capability/impl/FluidTankList.java
@@ -1,130 +1,149 @@
package gregtech.api.capability.impl;
import gregtech.api.capability.IMultipleTankHandler;
-import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.fluids.FluidStack;
-import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.IFluidTank;
-import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
-/**
- * Recommended to use this with {@link NotifiableFluidTankFromList} to ensure
- * proper behavior of the "allowSameFluidFill" setting, but not required.
- */
-public class FluidTankList implements IFluidHandler, IMultipleTankHandler, INBTSerializable {
+public class FluidTankList implements IMultipleTankHandler, INBTSerializable {
- protected final List fluidTanks;
- protected IFluidTankProperties[] properties;
+ private final MultiFluidTankEntry[] fluidTanks;
private final boolean allowSameFluidFill;
+
private IFluidTankProperties[] fluidTankProperties;
- private final int hashCode;
public FluidTankList(boolean allowSameFluidFill, IFluidTank... fluidTanks) {
- this.fluidTanks = Arrays.asList(fluidTanks);
+ ArrayList list = new ArrayList<>();
+ for (IFluidTank tank : fluidTanks) list.add(wrapIntoEntry(tank));
+ this.fluidTanks = list.toArray(new MultiFluidTankEntry[0]);
this.allowSameFluidFill = allowSameFluidFill;
- this.hashCode = Arrays.hashCode(fluidTanks);
}
- public FluidTankList(boolean allowSameFluidFill, List extends IFluidTank> fluidTanks) {
- this.fluidTanks = new ArrayList<>(fluidTanks);
+ public FluidTankList(boolean allowSameFluidFill, @Nonnull List extends IFluidTank> fluidTanks) {
+ ArrayList list = new ArrayList<>();
+ for (IFluidTank tank : fluidTanks) list.add(wrapIntoEntry(tank));
+ this.fluidTanks = list.toArray(new MultiFluidTankEntry[0]);
this.allowSameFluidFill = allowSameFluidFill;
- this.hashCode = Arrays.hashCode(fluidTanks.toArray());
}
- public FluidTankList(boolean allowSameFluidFill, FluidTankList parent, IFluidTank... additionalTanks) {
- this.fluidTanks = new ArrayList<>();
- this.fluidTanks.addAll(parent.fluidTanks);
- this.fluidTanks.addAll(Arrays.asList(additionalTanks));
+ public FluidTankList(boolean allowSameFluidFill, @Nonnull IMultipleTankHandler parent, IFluidTank... additionalTanks) {
+ ArrayList list = new ArrayList<>(parent.getFluidTanks());
+ for (IFluidTank tank : additionalTanks) list.add(wrapIntoEntry(tank));
+ this.fluidTanks = list.toArray(new MultiFluidTankEntry[0]);
this.allowSameFluidFill = allowSameFluidFill;
- int hash = Objects.hash(parent);
- hash = 31 * hash + Arrays.hashCode(additionalTanks);
- this.hashCode = hash;
}
- @Override
- public int hashCode() {
- return hashCode;
- }
-
- public List getFluidTanks() {
- return Collections.unmodifiableList(fluidTanks);
+ private MultiFluidTankEntry wrapIntoEntry(IFluidTank tank) {
+ return tank instanceof MultiFluidTankEntry entry ? entry : new MultiFluidTankEntry(this, tank);
}
@Nonnull
@Override
- public Iterator iterator() {
- return getFluidTanks().iterator();
+ public List getFluidTanks() {
+ return Collections.unmodifiableList(Arrays.asList(fluidTanks));
}
@Override
public int getTanks() {
- return fluidTanks.size();
+ return fluidTanks.length;
}
+ @Nonnull
@Override
- public IFluidTank getTankAt(int index) {
- return fluidTanks.get(index);
+ public MultiFluidTankEntry getTankAt(int index) {
+ return fluidTanks[index];
}
+ @Nonnull
@Override
public IFluidTankProperties[] getTankProperties() {
if (fluidTankProperties == null) {
ArrayList propertiesList = new ArrayList<>();
- for (IFluidTank fluidTank : fluidTanks) {
- if (fluidTank instanceof IFluidHandler) {
- IFluidHandler fluidHandler = (IFluidHandler) fluidTank;
- propertiesList.addAll(Arrays.asList(fluidHandler.getTankProperties()));
- }
+ for (MultiFluidTankEntry fluidTank : fluidTanks) {
+ Collections.addAll(propertiesList, fluidTank.getTankProperties());
}
this.fluidTankProperties = propertiesList.toArray(new IFluidTankProperties[0]);
}
return fluidTankProperties;
}
+ @Override
+ public boolean allowSameFluidFill() {
+ return allowSameFluidFill;
+ }
+
@Override
public int fill(FluidStack resource, boolean doFill) {
if (resource == null || resource.amount <= 0) {
return 0;
}
- return fillTanksImpl(resource.copy(), doFill);
- }
-
- //fills exactly one tank if multi-filling is not allowed
- //and as much tanks as possible otherwise
- //note that it will always try to fill tanks with same fluid first
- private int fillTanksImpl(FluidStack resource, boolean doFill) {
- int totalFilled = 0;
- //first, try to fill tanks that already have same fluid type
- for (IFluidTank handler : fluidTanks) {
- if (resource.isFluidEqual(handler.getFluid())) {
- int filledAmount = handler.fill(resource, doFill);
- totalFilled += filledAmount;
- resource.amount -= filledAmount;
- //if filling multiple tanks is not allowed, or resource is empty, return now
- if (!allowSameFluidFill() || resource.amount == 0)
- return totalFilled;
+ int totalInserted = 0;
+ boolean inputFluidCopied = false;
+ // flag value indicating whether the fluid was stored in 'distinct' slot at least once
+ boolean distinctSlotVisited = false;
+
+ MultiFluidTankEntry[] fluidTanks = this.fluidTanks.clone();
+ Arrays.sort(fluidTanks, IMultipleTankHandler.ENTRY_COMPARATOR);
+
+ // search for tanks with same fluid type first
+ for (MultiFluidTankEntry tank : fluidTanks) {
+ // if the fluid to insert matches the tank, insert the fluid
+ if (resource.isFluidEqual(tank.getFluid())) {
+ int inserted = tank.fill(resource, doFill);
+ if (inserted > 0) {
+ totalInserted += inserted;
+ if (resource.amount - inserted <= 0) {
+ return totalInserted;
+ }
+ if (!inputFluidCopied) {
+ inputFluidCopied = true;
+ resource = resource.copy();
+ }
+ resource.amount -= inserted;
+ }
+ // regardless of whether the insertion succeeded, presence of identical fluid in
+ // a slot prevents distinct fill to other slots
+ if (!tank.allowSameFluidFill()) {
+ distinctSlotVisited = true;
+ }
}
}
- //otherwise, try to fill empty tanks
- for (IFluidTank handler : fluidTanks) {
- if (handler.getFluidAmount() == 0) {
- int filledAmount = handler.fill(resource, doFill);
- totalFilled += filledAmount;
- resource.amount -= filledAmount;
- if (!allowSameFluidFill() || resource.amount == 0)
- return totalFilled;
+ // if we still have fluid to insert, loop through empty tanks until we find one that can accept the fluid
+ for (MultiFluidTankEntry tank : fluidTanks) {
+ // if the tank uses distinct fluid fill (allowSameFluidFill disabled) and another distinct tank had
+ // received the fluid, skip this tank
+ boolean usesDistinctFluidFill = tank.allowSameFluidFill();
+ if ((usesDistinctFluidFill || !distinctSlotVisited) && tank.getFluidAmount() == 0) {
+ int inserted = tank.fill(resource, doFill);
+ if (inserted > 0) {
+ totalInserted += inserted;
+ if (resource.amount - inserted <= 0) {
+ return totalInserted;
+ }
+ if (!inputFluidCopied) {
+ inputFluidCopied = true;
+ resource = resource.copy();
+ }
+ resource.amount -= inserted;
+ if (!usesDistinctFluidFill) {
+ distinctSlotVisited = true;
+ }
+ }
}
}
- return totalFilled;
+ // return the amount of fluid that was inserted
+ return totalInserted;
}
@Nullable
@@ -133,22 +152,24 @@ public FluidStack drain(FluidStack resource, boolean doDrain) {
if (resource == null || resource.amount <= 0) {
return null;
}
- resource = resource.copy();
+ int amountLeft = resource.amount;
FluidStack totalDrained = null;
for (IFluidTank handler : fluidTanks) {
if (!resource.isFluidEqual(handler.getFluid())) {
continue;
}
- FluidStack drain = handler.drain(resource.amount, doDrain);
- if (drain == null) {
- continue;
+ FluidStack drain = handler.drain(amountLeft, doDrain);
+ if (drain != null) {
+ if (totalDrained == null) {
+ totalDrained = drain;
+ } else {
+ totalDrained.amount += drain.amount;
+ }
+ amountLeft -= drain.amount;
+ if (amountLeft <= 0) {
+ return totalDrained;
+ }
}
- if (totalDrained == null) {
- totalDrained = drain;
- } else totalDrained.amount += drain.amount;
-
- resource.amount -= drain.amount;
- if (resource.amount == 0) break;
}
return totalDrained;
}
@@ -156,26 +177,29 @@ public FluidStack drain(FluidStack resource, boolean doDrain) {
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain) {
- if (maxDrain == 0) {
+ if (maxDrain <= 0) {
return null;
}
FluidStack totalDrained = null;
for (IFluidTank handler : fluidTanks) {
if (totalDrained == null) {
totalDrained = handler.drain(maxDrain, doDrain);
- if (totalDrained != null)
+ if (totalDrained != null) {
maxDrain -= totalDrained.amount;
+ }
} else {
- FluidStack copy = totalDrained.copy();
- copy.amount = maxDrain;
- if (!copy.isFluidEqual(handler.getFluid())) continue;
- FluidStack drain = handler.drain(copy.amount, doDrain);
+ if (!totalDrained.isFluidEqual(handler.getFluid())) {
+ continue;
+ }
+ FluidStack drain = handler.drain(maxDrain, doDrain);
if (drain != null) {
totalDrained.amount += drain.amount;
maxDrain -= drain.amount;
}
}
- if (maxDrain <= 0) break;
+ if (maxDrain <= 0) {
+ return totalDrained;
+ }
}
return totalDrained;
}
@@ -183,19 +207,9 @@ public FluidStack drain(int maxDrain, boolean doDrain) {
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound fluidInventory = new NBTTagCompound();
- fluidInventory.setInteger("TankAmount", this.getTanks());
-
NBTTagList tanks = new NBTTagList();
for (int i = 0; i < this.getTanks(); i++) {
- NBTBase writeTag;
- IFluidTank fluidTank = fluidTanks.get(i);
- if (fluidTank instanceof FluidTank) {
- writeTag = ((FluidTank) fluidTank).writeToNBT(new NBTTagCompound());
- } else if (fluidTank instanceof INBTSerializable) {
- writeTag = ((INBTSerializable>) fluidTank).serializeNBT();
- } else writeTag = new NBTTagCompound();
-
- tanks.appendTag(writeTag);
+ tanks.appendTag(this.fluidTanks[i].trySerialize());
}
fluidInventory.setTag("Tanks", tanks);
return fluidInventory;
@@ -204,35 +218,31 @@ public NBTTagCompound serializeNBT() {
@Override
public void deserializeNBT(NBTTagCompound nbt) {
NBTTagList tanks = nbt.getTagList("Tanks", Constants.NBT.TAG_COMPOUND);
- for (int i = 0; i < Math.min(fluidTanks.size(), nbt.getInteger("TankAmount")); i++) {
- NBTBase nbtTag = tanks.get(i);
- IFluidTank fluidTank = fluidTanks.get(i);
- if (fluidTank instanceof FluidTank) {
- ((FluidTank) fluidTank).readFromNBT((NBTTagCompound) nbtTag);
- } else if (fluidTank instanceof INBTSerializable) {
- ((INBTSerializable) fluidTank).deserializeNBT(nbtTag);
- }
+ for (int i = 0; i < Math.min(fluidTanks.length, tanks.tagCount()); i++) {
+ this.fluidTanks[i].tryDeserialize(tanks.getCompoundTagAt(i));
}
}
- protected void validateTankIndex(int tank) {
- if (tank < 0 || tank >= fluidTanks.size())
- throw new RuntimeException("Tank " + tank + " not in valid range - (0," + fluidTanks.size() + "]");
+ @Override
+ public String toString() {
+ return toString(false);
}
- @Override
- public int getIndexOfFluid(FluidStack fluidStack) {
- for (int i = 0; i < fluidTanks.size(); i++) {
- FluidStack tankStack = fluidTanks.get(i).getFluid();
- if (tankStack != null && tankStack.isFluidEqual(fluidStack)) {
- return i;
+ public String toString(boolean lineBreak) {
+ StringBuilder stb = new StringBuilder("FluidTankList[").append(this.fluidTanks.length).append(";");
+ for (int i = 0; i < this.fluidTanks.length; i++) {
+ if (i != 0) stb.append(',');
+ stb.append(lineBreak ? "\n " : " ");
+
+ FluidStack fluid = this.fluidTanks[i].getFluid();
+ if (fluid == null || fluid.amount == 0) {
+ stb.append("None 0 / ").append(this.fluidTanks[i].getCapacity());
+ } else {
+ stb.append(fluid.getFluid().getName()).append(' ').append(fluid.amount)
+ .append(" / ").append(this.fluidTanks[i].getCapacity());
}
}
- return -1;
- }
-
- @Override
- public boolean allowSameFluidFill() {
- return allowSameFluidFill;
+ if (lineBreak) stb.append('\n');
+ return stb.append(']').toString();
}
}
diff --git a/src/main/java/gregtech/api/capability/impl/GTFluidHandlerItemStack.java b/src/main/java/gregtech/api/capability/impl/GTFluidHandlerItemStack.java
index 2562acabc2c..dabb85647cb 100644
--- a/src/main/java/gregtech/api/capability/impl/GTFluidHandlerItemStack.java
+++ b/src/main/java/gregtech/api/capability/impl/GTFluidHandlerItemStack.java
@@ -1,12 +1,25 @@
package gregtech.api.capability.impl;
+import gregtech.api.capability.IFilter;
+import gregtech.api.capability.IFilteredFluidContainer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
-public class GTFluidHandlerItemStack extends FluidHandlerItemStack {
+public class GTFluidHandlerItemStack extends FluidHandlerItemStack implements IFilteredFluidContainer {
+
+ @Nullable
+ private IFilter filter;
+
+ private boolean canFill = true;
+ private boolean canDrain = true;
+
+ @Nullable
+ private IFluidTankProperties[] properties;
/**
* @param container The container itemStack, data is stored on it directly as NBT.
@@ -16,6 +29,44 @@ public GTFluidHandlerItemStack(@Nonnull ItemStack container, int capacity) {
super(container, capacity);
}
+ @Nullable
+ @Override
+ public IFilter getFilter() {
+ return this.filter;
+ }
+
+ @Nonnull
+ public GTFluidHandlerItemStack setFilter(@Nullable IFilter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ public boolean canFill() {
+ return canFill;
+ }
+
+ public GTFluidHandlerItemStack setCanFill(boolean canFill) {
+ this.canFill = canFill;
+ return this;
+ }
+
+ public boolean canDrain() {
+ return canDrain;
+ }
+
+ public GTFluidHandlerItemStack setCanDrain(boolean canDrain) {
+ this.canDrain = canDrain;
+ return this;
+ }
+
+ @Override
+ public IFluidTankProperties[] getTankProperties() {
+ if (properties == null) {
+ return properties = new IFluidTankProperties[]{new TankProperties()};
+ }
+ return properties;
+ }
+
@Override
public FluidStack drain(FluidStack resource, boolean doDrain) {
FluidStack drained = super.drain(resource, doDrain);
@@ -35,4 +86,48 @@ private void removeTagWhenEmpty(boolean doDrain) {
this.container.setTagCompound(null);
}
}
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluid) {
+ return canFill() && (this.filter == null || this.filter.test(fluid));
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluid) {
+ return canDrain();
+ }
+
+ private final class TankProperties implements IFluidTankProperties {
+
+ @Nullable
+ @Override
+ public FluidStack getContents() {
+ return GTFluidHandlerItemStack.this.getFluid();
+ }
+
+ @Override
+ public int getCapacity() {
+ return GTFluidHandlerItemStack.this.capacity;
+ }
+
+ @Override
+ public boolean canFill() {
+ return GTFluidHandlerItemStack.this.canFill();
+ }
+
+ @Override
+ public boolean canDrain() {
+ return GTFluidHandlerItemStack.this.canDrain();
+ }
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluidStack) {
+ return GTFluidHandlerItemStack.this.canFillFluidType(fluidStack);
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluidStack) {
+ return GTFluidHandlerItemStack.this.canDrainFluidType(fluidStack);
+ }
+ }
}
diff --git a/src/main/java/gregtech/api/capability/impl/GTSimpleFluidHandlerItemStack.java b/src/main/java/gregtech/api/capability/impl/GTSimpleFluidHandlerItemStack.java
index eeab6c9694d..86bb0457652 100644
--- a/src/main/java/gregtech/api/capability/impl/GTSimpleFluidHandlerItemStack.java
+++ b/src/main/java/gregtech/api/capability/impl/GTSimpleFluidHandlerItemStack.java
@@ -1,12 +1,26 @@
package gregtech.api.capability.impl;
+import gregtech.api.capability.IFilter;
+import gregtech.api.capability.IFilteredFluidContainer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.capability.FluidTankProperties;
+import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStackSimple;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
-public class GTSimpleFluidHandlerItemStack extends FluidHandlerItemStackSimple {
+public class GTSimpleFluidHandlerItemStack extends FluidHandlerItemStackSimple implements IFilteredFluidContainer {
+
+ @Nullable
+ private IFilter filter;
+
+ private boolean canFill = true;
+ private boolean canDrain = true;
+
+ @Nullable
+ private IFluidTankProperties[] properties;
/**
* @param container The container itemStack, data is stored on it directly as NBT.
@@ -16,6 +30,44 @@ public GTSimpleFluidHandlerItemStack(@Nonnull ItemStack container, int capacity)
super(container, capacity);
}
+ @Nullable
+ @Override
+ public IFilter getFilter() {
+ return this.filter;
+ }
+
+ @Nonnull
+ public GTSimpleFluidHandlerItemStack setFilter(@Nullable IFilter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ public boolean canFill() {
+ return canFill;
+ }
+
+ public GTSimpleFluidHandlerItemStack setCanFill(boolean canFill) {
+ this.canFill = canFill;
+ return this;
+ }
+
+ public boolean canDrain() {
+ return canDrain;
+ }
+
+ public GTSimpleFluidHandlerItemStack setCanDrain(boolean canDrain) {
+ this.canDrain = canDrain;
+ return this;
+ }
+
+ @Override
+ public IFluidTankProperties[] getTankProperties() {
+ if (properties == null) {
+ return properties = new IFluidTankProperties[]{new GTSimpleFluidHandlerItemStack.TankProperties()};
+ }
+ return properties;
+ }
+
@Override
public FluidStack drain(FluidStack resource, boolean doDrain) {
FluidStack drained = super.drain(resource, doDrain);
@@ -35,4 +87,48 @@ private void removeTagWhenEmpty(boolean doDrain) {
this.container.setTagCompound(null);
}
}
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluid) {
+ return canFill() && (this.filter == null || this.filter.test(fluid));
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluid) {
+ return canDrain();
+ }
+
+ private final class TankProperties implements IFluidTankProperties {
+
+ @Nullable
+ @Override
+ public FluidStack getContents() {
+ return GTSimpleFluidHandlerItemStack.this.getFluid();
+ }
+
+ @Override
+ public int getCapacity() {
+ return GTSimpleFluidHandlerItemStack.this.capacity;
+ }
+
+ @Override
+ public boolean canFill() {
+ return GTSimpleFluidHandlerItemStack.this.canFill();
+ }
+
+ @Override
+ public boolean canDrain() {
+ return GTSimpleFluidHandlerItemStack.this.canDrain();
+ }
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluidStack) {
+ return GTSimpleFluidHandlerItemStack.this.canFillFluidType(fluidStack);
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluidStack) {
+ return GTSimpleFluidHandlerItemStack.this.canDrainFluidType(fluidStack);
+ }
+ }
}
diff --git a/src/main/java/gregtech/api/capability/impl/MultiFluidFilter.java b/src/main/java/gregtech/api/capability/impl/MultiFluidFilter.java
new file mode 100644
index 00000000000..0e0c4d599e0
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/impl/MultiFluidFilter.java
@@ -0,0 +1,71 @@
+package gregtech.api.capability.impl;
+
+import com.google.common.collect.Iterables;
+import gregtech.api.capability.IFilter;
+import net.minecraftforge.fluids.FluidStack;
+
+import javax.annotation.Nonnull;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Basic filter with multiple fluid templates. Can be either whitelist or blacklist.
+ */
+public final class MultiFluidFilter implements IFilter {
+
+ private final boolean blacklist;
+ private final FluidStack[] fluids;
+
+ public MultiFluidFilter(boolean blacklist, @Nonnull FluidStack... fluids) {
+ this.blacklist = blacklist;
+ this.fluids = fluids;
+ }
+
+ public MultiFluidFilter(boolean blacklist, Iterable fluids) {
+ this.blacklist = blacklist;
+ this.fluids = Iterables.toArray(fluids, FluidStack.class);
+ }
+
+ @Nonnull
+ public List getFluids() {
+ return Collections.unmodifiableList(Arrays.asList(fluids));
+ }
+
+ public boolean isWhitelist() {
+ return !blacklist;
+ }
+
+ public boolean isBlacklist() {
+ return blacklist;
+ }
+
+ @Override
+ public boolean test(@Nonnull FluidStack fluidStack) {
+ for (FluidStack fluid : this.fluids) {
+ if (fluid.isFluidEqual(fluid)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int getPriority() {
+ return this.fluids.length == 0 ? IFilter.noPriority() :
+ this.blacklist ? IFilter.blacklistPriority(this.fluids.length) :
+ IFilter.whitelistPriority(this.fluids.length);
+ }
+
+ @Nonnull
+ @Override
+ public IFilter negate() {
+ return new MultiFluidFilter(!this.blacklist, this.fluids);
+ }
+
+ @Override
+ public String toString() {
+ return "MultiFluidFilter{" +
+ "blacklist=" + blacklist +
+ ", fluids=" + Arrays.toString(fluids) +
+ '}';
+ }
+}
diff --git a/src/main/java/gregtech/api/capability/impl/NotifiableFluidTankFromList.java b/src/main/java/gregtech/api/capability/impl/NotifiableFluidTankFromList.java
index 6ca99a05c21..19cb8c1ea5f 100644
--- a/src/main/java/gregtech/api/capability/impl/NotifiableFluidTankFromList.java
+++ b/src/main/java/gregtech/api/capability/impl/NotifiableFluidTankFromList.java
@@ -6,6 +6,11 @@
import java.util.function.Supplier;
+/**
+ * @deprecated Distinct insertion logic should be handled by {@link FluidTankList}s.
+ * Use other fluid tank implementations.
+ */
+@Deprecated
public abstract class NotifiableFluidTankFromList extends NotifiableFluidTank {
private final int index;
diff --git a/src/main/java/gregtech/api/capability/impl/PropertyFluidFilter.java b/src/main/java/gregtech/api/capability/impl/PropertyFluidFilter.java
new file mode 100644
index 00000000000..4309cbfc793
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/impl/PropertyFluidFilter.java
@@ -0,0 +1,60 @@
+package gregtech.api.capability.impl;
+
+import gregtech.api.capability.IPropertyFluidFilter;
+
+public class PropertyFluidFilter implements IPropertyFluidFilter {
+
+ private final int maxFluidTemperature;
+ private final boolean gasProof;
+ private final boolean acidProof;
+ private final boolean cryoProof;
+ private final boolean plasmaProof;
+
+ public PropertyFluidFilter(int maxFluidTemperature,
+ boolean gasProof,
+ boolean acidProof,
+ boolean cryoProof,
+ boolean plasmaProof) {
+ this.maxFluidTemperature = maxFluidTemperature;
+ this.gasProof = gasProof;
+ this.acidProof = acidProof;
+ this.cryoProof = cryoProof;
+ this.plasmaProof = plasmaProof;
+ }
+
+ @Override
+ public int getMaxFluidTemperature() {
+ return this.maxFluidTemperature;
+ }
+
+ @Override
+ public boolean isGasProof() {
+ return this.gasProof;
+ }
+
+ @Override
+ public boolean isAcidProof() {
+ return this.acidProof;
+ }
+
+ @Override
+ public boolean isCryoProof() {
+ return this.cryoProof;
+ }
+
+ @Override
+ public boolean isPlasmaProof() {
+ return this.plasmaProof;
+ }
+
+ @Override
+ public String toString() {
+ return "SimplePropertyFluidFilter{" +
+ "maxFluidTemperature=" + maxFluidTemperature +
+ ", gasProof=" + gasProof +
+ ", acidProof=" + acidProof +
+ ", cryoProof=" + cryoProof +
+ ", plasmaProof=" + plasmaProof +
+ '}';
+ }
+}
diff --git a/src/main/java/gregtech/api/capability/impl/SimpleThermalFluidHandlerItemStack.java b/src/main/java/gregtech/api/capability/impl/SimpleThermalFluidHandlerItemStack.java
index a0f6bbc073e..aed9d5a5e04 100644
--- a/src/main/java/gregtech/api/capability/impl/SimpleThermalFluidHandlerItemStack.java
+++ b/src/main/java/gregtech/api/capability/impl/SimpleThermalFluidHandlerItemStack.java
@@ -6,6 +6,10 @@
import javax.annotation.Nonnull;
+/**
+ * @deprecated use {@link gregtech.api.capability.IFilter} API
+ */
+@Deprecated
public class SimpleThermalFluidHandlerItemStack extends GTSimpleFluidHandlerItemStack implements IThermalFluidHandlerItemStack {
public final int maxFluidTemperature;
diff --git a/src/main/java/gregtech/api/capability/impl/SingleFluidFilter.java b/src/main/java/gregtech/api/capability/impl/SingleFluidFilter.java
new file mode 100644
index 00000000000..f1d3a4622f8
--- /dev/null
+++ b/src/main/java/gregtech/api/capability/impl/SingleFluidFilter.java
@@ -0,0 +1,56 @@
+package gregtech.api.capability.impl;
+
+import gregtech.api.capability.IFilter;
+import net.minecraftforge.fluids.FluidStack;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Basic filter with one fluid template. Can be either whitelist or blacklist.
+ */
+public final class SingleFluidFilter implements IFilter {
+
+ private final FluidStack fluid;
+ private final boolean blacklist;
+
+ public SingleFluidFilter(@Nonnull FluidStack fluid, boolean blacklist) {
+ this.fluid = fluid;
+ this.blacklist = blacklist;
+ }
+
+ @Nonnull
+ public FluidStack getFluid() {
+ return fluid;
+ }
+
+ public boolean isWhitelist() {
+ return !blacklist;
+ }
+
+ public boolean isBlacklist() {
+ return blacklist;
+ }
+
+ @Override
+ public boolean test(@Nonnull FluidStack fluid) {
+ return this.fluid.isFluidEqual(fluid) != this.blacklist;
+ }
+
+ @Override
+ public int getPriority() {
+ return this.blacklist ? IFilter.blacklistPriority(1) : IFilter.whitelistPriority(1);
+ }
+
+ @Override
+ public IFilter negate() {
+ return new SingleFluidFilter(this.fluid, !this.blacklist);
+ }
+
+ @Override
+ public String toString() {
+ return "SingleFluidFilter{" +
+ "fluid=" + fluid +
+ ", blacklist=" + blacklist +
+ '}';
+ }
+}
diff --git a/src/main/java/gregtech/api/capability/impl/ThermalFluidHandlerItemStack.java b/src/main/java/gregtech/api/capability/impl/ThermalFluidHandlerItemStack.java
index a812a95d558..07a85e14ef8 100644
--- a/src/main/java/gregtech/api/capability/impl/ThermalFluidHandlerItemStack.java
+++ b/src/main/java/gregtech/api/capability/impl/ThermalFluidHandlerItemStack.java
@@ -6,6 +6,10 @@
import javax.annotation.Nonnull;
+/**
+ * @deprecated use {@link gregtech.api.capability.IFilter} API
+ */
+@Deprecated
public class ThermalFluidHandlerItemStack extends GTFluidHandlerItemStack implements IThermalFluidHandlerItemStack {
private final int maxFluidTemperature;
diff --git a/src/main/java/gregtech/api/cover/CoverBehavior.java b/src/main/java/gregtech/api/cover/CoverBehavior.java
index b934cb93240..ca2cbe365ba 100644
--- a/src/main/java/gregtech/api/cover/CoverBehavior.java
+++ b/src/main/java/gregtech/api/cover/CoverBehavior.java
@@ -25,6 +25,8 @@
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
@@ -181,7 +183,8 @@ public EnumActionResult onSoftMalletClick(EntityPlayer playerIn, EnumHand hand,
* @param defaultValue value of the capability from meta tile entity itself
* @return result capability value external caller will receive
*/
- public T getCapability(Capability capability, T defaultValue) {
+ @Nullable
+ public T getCapability(@Nonnull Capability capability, @Nullable T defaultValue) {
return defaultValue;
}
diff --git a/src/main/java/gregtech/api/items/metaitem/FilteredFluidStats.java b/src/main/java/gregtech/api/items/metaitem/FilteredFluidStats.java
index 1f09ea0bbab..50bfeec74be 100644
--- a/src/main/java/gregtech/api/items/metaitem/FilteredFluidStats.java
+++ b/src/main/java/gregtech/api/items/metaitem/FilteredFluidStats.java
@@ -1,42 +1,47 @@
package gregtech.api.items.metaitem;
+import gregtech.api.capability.IFilter;
import gregtech.api.capability.impl.GTFluidHandlerItemStack;
import gregtech.api.capability.impl.GTSimpleFluidHandlerItemStack;
+import gregtech.api.capability.impl.PropertyFluidFilter;
import gregtech.api.items.metaitem.stats.IItemCapabilityProvider;
import gregtech.api.items.metaitem.stats.IItemComponent;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
+import javax.annotation.Nullable;
import java.util.function.Function;
public class FilteredFluidStats implements IItemComponent, IItemCapabilityProvider {
public final int capacity;
public final boolean allowPartialFill;
- private final Function fillPredicate;
+ @Nullable
+ public final IFilter filter;
+ @Deprecated
public FilteredFluidStats(int capacity, boolean allowPartialFill, Function fillPredicate) {
this.capacity = capacity;
this.allowPartialFill = allowPartialFill;
- this.fillPredicate = fillPredicate;
+ this.filter = fillPredicate::apply;
+ }
+
+ public FilteredFluidStats(int capacity, boolean allowPartialFill, @Nullable IFilter filter) {
+ this.capacity = capacity;
+ this.allowPartialFill = allowPartialFill;
+ this.filter = filter;
+ }
+
+ public FilteredFluidStats(int capacity, int maxFluidTemperature, boolean gasProof, boolean acidProof,
+ boolean cryoProof, boolean plasmaProof, boolean allowPartialFill) {
+ this(capacity, allowPartialFill, new PropertyFluidFilter(maxFluidTemperature, gasProof, acidProof, cryoProof, plasmaProof));
}
@Override
public ICapabilityProvider createProvider(ItemStack itemStack) {
- if (allowPartialFill) {
- return new GTFluidHandlerItemStack(itemStack, capacity) {
- @Override
- public boolean canFillFluidType(FluidStack fluid) {
- return super.canFillFluidType(fluid) && fillPredicate.apply(fluid);
- }
- };
- }
- return new GTSimpleFluidHandlerItemStack(itemStack, capacity) {
- @Override
- public boolean canFillFluidType(FluidStack fluid) {
- return super.canFillFluidType(fluid) && fillPredicate.apply(fluid);
- }
- };
+ return allowPartialFill ?
+ new GTFluidHandlerItemStack(itemStack, this.capacity).setFilter(this.filter) :
+ new GTSimpleFluidHandlerItemStack(itemStack, this.capacity).setFilter(this.filter);
}
}
diff --git a/src/main/java/gregtech/api/items/metaitem/MetaItem.java b/src/main/java/gregtech/api/items/metaitem/MetaItem.java
index e66c77ca12f..11b2c0c4e69 100644
--- a/src/main/java/gregtech/api/items/metaitem/MetaItem.java
+++ b/src/main/java/gregtech/api/items/metaitem/MetaItem.java
@@ -8,7 +8,8 @@
import gregtech.api.GregTechAPI;
import gregtech.api.capability.GregtechCapabilities;
import gregtech.api.capability.IElectricItem;
-import gregtech.api.capability.IThermalFluidHandlerItemStack;
+import gregtech.api.capability.IFilteredFluidContainer;
+import gregtech.api.capability.IPropertyFluidFilter;
import gregtech.api.capability.impl.CombinedCapabilityProvider;
import gregtech.api.capability.impl.ElectricItem;
import gregtech.api.gui.ModularUI;
@@ -257,8 +258,7 @@ public ICapabilityProvider initCapabilities(@Nonnull ItemStack stack, @Nullable
}
ArrayList providers = new ArrayList<>();
for (IItemComponent itemComponent : metaValueItem.getAllStats()) {
- if (itemComponent instanceof IItemCapabilityProvider) {
- IItemCapabilityProvider provider = (IItemCapabilityProvider) itemComponent;
+ if (itemComponent instanceof IItemCapabilityProvider provider) {
providers.add(provider.createProvider(stack));
}
}
@@ -569,15 +569,15 @@ public void addInformation(@Nonnull ItemStack itemStack, @Nullable World worldIn
fluidTankProperties.getCapacity(),
fluid == null ? "" : fluid.getLocalizedName()));
- if (fluidHandler instanceof IThermalFluidHandlerItemStack) {
- IThermalFluidHandlerItemStack thermalFluidHandler = (IThermalFluidHandlerItemStack) fluidHandler;
+ if (fluidHandler instanceof IFilteredFluidContainer filtered &&
+ filtered.getFilter() instanceof IPropertyFluidFilter propertyFilter) {
if (TooltipHelper.isShiftDown()) {
- lines.add(I18n.format("gregtech.fluid_pipe.max_temperature", thermalFluidHandler.getMaxFluidTemperature()));
- if (thermalFluidHandler.isGasProof()) lines.add(I18n.format("gregtech.fluid_pipe.gas_proof"));
- if (thermalFluidHandler.isAcidProof()) lines.add(I18n.format("gregtech.fluid_pipe.acid_proof"));
- if (thermalFluidHandler.isCryoProof()) lines.add(I18n.format("gregtech.fluid_pipe.cryo_proof"));
- if (thermalFluidHandler.isPlasmaProof()) lines.add(I18n.format("gregtech.fluid_pipe.plasma_proof"));
- } else if (thermalFluidHandler.isGasProof() || thermalFluidHandler.isAcidProof() || thermalFluidHandler.isCryoProof() || thermalFluidHandler.isPlasmaProof()) {
+ lines.add(I18n.format("gregtech.fluid_pipe.max_temperature", propertyFilter.getMaxFluidTemperature()));
+ if (propertyFilter.isGasProof()) lines.add(I18n.format("gregtech.fluid_pipe.gas_proof"));
+ if (propertyFilter.isAcidProof()) lines.add(I18n.format("gregtech.fluid_pipe.acid_proof"));
+ if (propertyFilter.isCryoProof()) lines.add(I18n.format("gregtech.fluid_pipe.cryo_proof"));
+ if (propertyFilter.isPlasmaProof()) lines.add(I18n.format("gregtech.fluid_pipe.plasma_proof"));
+ } else if (propertyFilter.isGasProof() || propertyFilter.isAcidProof() || propertyFilter.isCryoProof() || propertyFilter.isPlasmaProof()) {
lines.add(I18n.format("gregtech.tooltip.fluid_pipe_hold_shift"));
}
}
diff --git a/src/main/java/gregtech/api/items/metaitem/ThermalFluidStats.java b/src/main/java/gregtech/api/items/metaitem/ThermalFluidStats.java
index 5c018d71d2e..a2ee753e777 100644
--- a/src/main/java/gregtech/api/items/metaitem/ThermalFluidStats.java
+++ b/src/main/java/gregtech/api/items/metaitem/ThermalFluidStats.java
@@ -1,37 +1,11 @@
package gregtech.api.items.metaitem;
-import gregtech.api.capability.impl.SimpleThermalFluidHandlerItemStack;
-import gregtech.api.capability.impl.ThermalFluidHandlerItemStack;
-import gregtech.api.items.metaitem.stats.IItemCapabilityProvider;
-import gregtech.api.items.metaitem.stats.IItemComponent;
-import net.minecraft.item.ItemStack;
-import net.minecraftforge.common.capabilities.ICapabilityProvider;
-
-public class ThermalFluidStats implements IItemComponent, IItemCapabilityProvider {
-
- public final int capacity;
- public final int maxFluidTemperature;
- private final boolean gasProof;
- private final boolean acidProof;
- private final boolean cryoProof;
- private final boolean plasmaProof;
- public final boolean allowPartialFill;
-
+/**
+ * @deprecated use {@link FilteredFluidStats#FilteredFluidStats(int, int, boolean, boolean, boolean, boolean, boolean)}
+ */
+@Deprecated
+public class ThermalFluidStats extends FilteredFluidStats {
public ThermalFluidStats(int capacity, int maxFluidTemperature, boolean gasProof, boolean acidProof, boolean cryoProof, boolean plasmaProof, boolean allowPartialFill) {
- this.capacity = capacity;
- this.maxFluidTemperature = maxFluidTemperature;
- this.gasProof = gasProof;
- this.acidProof = acidProof;
- this.cryoProof = cryoProof;
- this.plasmaProof = plasmaProof;
- this.allowPartialFill = allowPartialFill;
- }
-
- @Override
- public ICapabilityProvider createProvider(ItemStack itemStack) {
- if (allowPartialFill) {
- return new ThermalFluidHandlerItemStack(itemStack, capacity, maxFluidTemperature, gasProof, acidProof, cryoProof, plasmaProof);
- }
- return new SimpleThermalFluidHandlerItemStack(itemStack, capacity, maxFluidTemperature, gasProof, acidProof, cryoProof, plasmaProof);
+ super(capacity, maxFluidTemperature, gasProof, acidProof, cryoProof, plasmaProof, allowPartialFill);
}
}
diff --git a/src/main/java/gregtech/api/metatileentity/SteamMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/SteamMetaTileEntity.java
index 746f68aec5a..59b9d1ba1b7 100644
--- a/src/main/java/gregtech/api/metatileentity/SteamMetaTileEntity.java
+++ b/src/main/java/gregtech/api/metatileentity/SteamMetaTileEntity.java
@@ -6,13 +6,13 @@
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
import gregtech.api.GTValues;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.capability.impl.RecipeLogicSteam;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
import gregtech.api.gui.widgets.ImageWidget;
-import gregtech.api.recipes.ModHandler;
import gregtech.api.recipes.RecipeMap;
import gregtech.api.util.GTUtility;
import gregtech.client.renderer.ICubeRenderer;
@@ -23,8 +23,8 @@
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.item.ItemStack;
import net.minecraft.init.SoundEvents;
+import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -36,6 +36,7 @@
import javax.annotation.Nullable;
import java.util.List;
+import java.util.Objects;
public abstract class SteamMetaTileEntity extends MetaTileEntity {
@@ -113,8 +114,7 @@ protected boolean isBrickedCasing() {
@Override
public FluidTankList createImportFluidHandler() {
- this.steamFluidTank = new FilteredFluidHandler(STEAM_CAPACITY)
- .setFillPredicate(ModHandler::isSteam);
+ this.steamFluidTank = new FilteredFluidHandler(STEAM_CAPACITY).setFilter(CommonFluidFilters.STEAM);
return new FluidTankList(false, steamFluidTank);
}
@@ -128,7 +128,7 @@ public ModularUI.Builder createUITemplate(EntityPlayer player) {
@Override
public SoundEvent getSound() {
- return workableHandler.getRecipeMap().getSound();
+ return Objects.requireNonNull(workableHandler.getRecipeMap()).getSound();
}
@SideOnly(Side.CLIENT)
diff --git a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
index 23ffdfcfc9d..5113badee97 100644
--- a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
+++ b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
@@ -58,8 +58,8 @@ public void transferDataFrom(IPipeTile tileEntity) {
this.pipeType = tileEntity.getPipeType();
this.paintingColor = tileEntity.getPaintingColor();
this.connections = tileEntity.getConnections();
- if (tileEntity instanceof TileEntityPipeBase) {
- this.updates.putAll(((TileEntityPipeBase, ?>) tileEntity).updates);
+ if (tileEntity instanceof TileEntityPipeBase pipeBase) {
+ this.updates.putAll(pipeBase.updates);
}
tileEntity.getCoverableImplementation().transferDataTo(coverableImplementation);
setFrameMaterial(tileEntity.getFrameMaterial());
@@ -111,9 +111,9 @@ public IPipeTile setSupportsTicking() {
return this;
}
//create new tickable tile entity, transfer data, and replace it
- IPipeTile newTile = getPipeBlock().createNewTileEntity(true);
+ TileEntityPipeBase newTile = getPipeBlock().createNewTileEntity(true);
newTile.transferDataFrom(this);
- getWorld().setTileEntity(getPos(), (TileEntity) newTile);
+ getWorld().setTileEntity(getPos(), newTile);
return newTile;
}
@@ -122,7 +122,7 @@ public IPipeTile setSupportsTicking() {
if (pipeBlock == null) {
Block block = getBlockState().getBlock();
//noinspection unchecked
- this.pipeBlock = block instanceof BlockPipe ? (BlockPipe) block : null;
+ this.pipeBlock = block instanceof BlockPipe blockPipe ? blockPipe : null;
}
return pipeBlock;
}
@@ -176,7 +176,9 @@ public void setConnection(EnumFacing side, boolean connected, boolean fromNeighb
}
TileEntity tile = getWorld().getTileEntity(getPos().offset(side));
// block connections if Pipe Types do not match
- if (connected && tile instanceof IPipeTile && ((IPipeTile, ?>) tile).getPipeType().getClass() != this.getPipeType().getClass()) {
+ if (connected &&
+ tile instanceof IPipeTile pipeTile &&
+ pipeTile.getPipeType().getClass() != this.getPipeType().getClass()) {
return;
}
connections = withSideConnection(connections, side, connected);
@@ -187,8 +189,8 @@ public void setConnection(EnumFacing side, boolean connected, boolean fromNeighb
});
markDirty();
- if (!fromNeighbor && tile instanceof IPipeTile) {
- syncPipeConnections(side, (IPipeTile, ?>) tile);
+ if (!fromNeighbor && tile instanceof IPipeTile pipeTile) {
+ syncPipeConnections(side, pipeTile);
}
}
}
@@ -266,12 +268,10 @@ public int getVisualConnections() {
float selfThickness = getPipeType().getThickness();
for (EnumFacing facing : EnumFacing.values()) {
if (isConnected(facing)) {
- TileEntity neighbourTile = world.getTileEntity(pos.offset(facing));
- if (neighbourTile instanceof IPipeTile) {
- IPipeTile, ?> pipeTile = (IPipeTile, ?>) neighbourTile;
- if (pipeTile.isConnected(facing.getOpposite()) && pipeTile.getPipeType().getThickness() < selfThickness) {
- connections |= 1 << (facing.getIndex() + 6);
- }
+ if (world.getTileEntity(pos.offset(facing)) instanceof IPipeTile, ?> pipeTile &&
+ pipeTile.isConnected(facing.getOpposite()) &&
+ pipeTile.getPipeType().getThickness() < selfThickness) {
+ connections |= 1 << (facing.getIndex() + 6);
}
if (getCoverableImplementation().getCoverAtSide(facing) != null) {
connections |= 1 << (facing.getIndex() + 12);
@@ -342,7 +342,7 @@ public void readFromNBT(@Nonnull NBTTagCompound compound) {
if (compound.hasKey("PipeBlock", NBT.TAG_STRING)) {
Block block = Block.REGISTRY.getObject(new ResourceLocation(compound.getString("PipeBlock")));
//noinspection unchecked
- this.pipeBlock = block instanceof BlockPipe ? (BlockPipe) block : null;
+ this.pipeBlock = block instanceof BlockPipe blockPipe ? blockPipe : null;
}
this.pipeType = getPipeTypeClass().getEnumConstants()[compound.getInteger("PipeType")];
diff --git a/src/main/java/gregtech/api/recipes/ModHandler.java b/src/main/java/gregtech/api/recipes/ModHandler.java
index 951fbd9a66b..34acaa150f1 100644
--- a/src/main/java/gregtech/api/recipes/ModHandler.java
+++ b/src/main/java/gregtech/api/recipes/ModHandler.java
@@ -3,6 +3,7 @@
import crafttweaker.mc1120.actions.ActionAddFurnaceRecipe;
import crafttweaker.mc1120.furnace.MCFurnaceManager;
import gregtech.api.GTValues;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.items.metaitem.MetaItem;
import gregtech.api.items.toolitem.IGTTool;
import gregtech.api.items.toolitem.ToolHelper;
@@ -37,11 +38,8 @@
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
-import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
-import net.minecraftforge.fluids.Fluid;
-import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
@@ -62,19 +60,8 @@ public final class ModHandler {
public static final boolean ERROR_ON_INVALID_RECIPE = GTValues.isDeobfEnvironment() || !ConfigHolder.misc.ignoreErrorOrInvalidRecipes;
public static boolean hasInvalidRecipe = false;
- private static FluidStack WATER;
- private static FluidStack DISTILLED_WATER;
- private static FluidStack LAVA;
- private static FluidStack STEAM;
- private ModHandler() {/**/}
-
- public static void init() {
- WATER = new FluidStack(FluidRegistry.WATER, 1);
- DISTILLED_WATER = Materials.DistilledWater.getFluid(1);
- LAVA = new FluidStack(FluidRegistry.LAVA, 0);
- STEAM = Materials.Steam.getFluid(1);
- }
+ private ModHandler() {}
public static void postInit() {
if (ERROR_ON_INVALID_RECIPE && hasInvalidRecipe) {
@@ -87,52 +74,29 @@ public static void postInit() {
/**
* @param stack the fluid to check
* @return if the fluid is a valid water fluid
+ * @deprecated use {@link CommonFluidFilters#BOILER_FLUID}
*/
+ @Deprecated
public static boolean isWater(@Nullable FluidStack stack) {
- if (stack == null) return false;
- if (WATER.isFluidEqual(stack)) return true;
- if (DISTILLED_WATER.isFluidEqual(stack)) return true;
-
- for (String fluidName : ConfigHolder.machines.boilerFluids) {
- Fluid fluid = FluidRegistry.getFluid(fluidName);
- if (fluid == null) continue;
- if (stack.isFluidEqual(new FluidStack(fluid, 1))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @param stack the fluid to check
- * @return if the fluid is a valid lava fluid
- */
- @SuppressWarnings("unused")
- public static boolean isLava(FluidStack stack) {
- return LAVA.isFluidEqual(stack);
- }
-
- /**
- * @param amount the amount of fluid
- * @return a FluidStack of lava
- */
- @SuppressWarnings("unused")
- @Nonnull
- public static FluidStack getLava(int amount) {
- return new FluidStack(FluidRegistry.LAVA, amount);
+ return stack != null && CommonFluidFilters.BOILER_FLUID.test(stack);
}
/**
* @param stack the fluid to check
* @return if the fluid is a valid steam fluid
+ * @deprecated use {@link CommonFluidFilters#STEAM}
*/
+ @Deprecated
public static boolean isSteam(FluidStack stack) {
- return STEAM.isFluidEqual(stack);
+ return CommonFluidFilters.STEAM.test(stack);
}
/**
- * Returns a Liquid Stack with given amount of Steam.
+ * @param amount amount of steam in mb
+ * @return a Liquid Stack with given amount of Steam.
+ * @deprecated make it yourself
*/
+ @Deprecated
public static FluidStack getSteam(int amount) {
return Materials.Steam.getFluid(amount);
}
@@ -147,14 +111,6 @@ public static boolean isMaterialWood(@Nullable Material material) {
// Furnace Smelting
- /**
- * @param stack the stack to check
- * @return the furnace fuel value for the stack
- */
- public static int getFuelValue(@Nonnull ItemStack stack) {
- return TileEntityFurnace.getItemBurnTime(stack);
- }
-
/**
* @param fuelStack the stack to check
* @return the remainder item for a burnt fuel in a boiler
@@ -453,14 +409,13 @@ public static Object[] finalizeShapedRecipeInput(Object... recipe) {
*/
@Nonnull
public static Object finalizeIngredient(@Nonnull Object ingredient) {
- if (ingredient instanceof MetaItem.MetaValueItem) {
- ingredient = ((MetaItem>.MetaValueItem) ingredient).getStackForm();
- } else if (ingredient instanceof Enum) {
- ingredient = ((Enum>) ingredient).name();
- } else if (ingredient instanceof OrePrefix) {
- ingredient = ((OrePrefix) ingredient).name();
- } else if (ingredient instanceof UnificationEntry) {
- UnificationEntry entry = (UnificationEntry) ingredient;
+ if (ingredient instanceof MetaItem.MetaValueItem metaValueItem) {
+ ingredient = metaValueItem.getStackForm();
+ } else if (ingredient instanceof Enum anEnum) {
+ ingredient = anEnum.name();
+ } else if (ingredient instanceof OrePrefix orePrefix) {
+ ingredient = orePrefix.name();
+ } else if (ingredient instanceof UnificationEntry entry) {
if (ConfigHolder.misc.debug && entry.material != null && !entry.orePrefix.isIgnored(entry.material) &&
!entry.orePrefix.doGenerateItem(entry.material)) {
logInvalidRecipe("Attempted to create recipe for invalid/missing Unification Entry " + ingredient);
@@ -489,8 +444,7 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @Nonnull
Object2LongMap materialStacksExploded = new Object2LongOpenHashMap<>();
int itr = 0;
- while (recipe[itr] instanceof String) {
- String s = (String) recipe[itr];
+ while (recipe[itr] instanceof String s) {
for (char c : s.toCharArray()) {
if (ToolHelper.getToolFromSymbol(c) != null) continue; // skip tools
int count = inputCountMap.getOrDefault(c, 0);
diff --git a/src/main/java/gregtech/api/recipes/logic/ParallelLogic.java b/src/main/java/gregtech/api/recipes/logic/ParallelLogic.java
index 27361c08abf..23312592384 100644
--- a/src/main/java/gregtech/api/recipes/logic/ParallelLogic.java
+++ b/src/main/java/gregtech/api/recipes/logic/ParallelLogic.java
@@ -240,21 +240,20 @@ public static int limitParallelByFluids(@Nonnull Recipe recipe, @Nonnull Overlay
int minMultiplier = 0;
int maxMultiplier = multiplier;
- Map recipeFluidOutputs = GTHashMaps.fromFluidCollection(recipe.getFluidOutputs());
-
while (minMultiplier != maxMultiplier) {
overlayedFluidHandler.reset();
int amountLeft = 0;
- for (Map.Entry entry : recipeFluidOutputs.entrySet()) {
+ for (FluidStack fluidStack : recipe.getFluidOutputs()) {
+ if (fluidStack.amount <= 0) continue;
// Since multiplier starts at Int.MAX, check here for integer overflow
- if (entry.getValue() != 0 && multiplier > Integer.MAX_VALUE / entry.getValue()) {
+ if (multiplier > Integer.MAX_VALUE / fluidStack.amount) {
amountLeft = Integer.MAX_VALUE;
} else {
- amountLeft = entry.getValue() * multiplier;
+ amountLeft = fluidStack.amount * multiplier;
}
- int inserted = overlayedFluidHandler.insertStackedFluidKey(entry.getKey(), amountLeft);
+ int inserted = overlayedFluidHandler.insertFluid(fluidStack, amountLeft);
if (inserted > 0) {
amountLeft -= inserted;
}
diff --git a/src/main/java/gregtech/api/unification/material/properties/FluidPipeProperties.java b/src/main/java/gregtech/api/unification/material/properties/FluidPipeProperties.java
index 56aed87e0c6..3eb852dc427 100644
--- a/src/main/java/gregtech/api/unification/material/properties/FluidPipeProperties.java
+++ b/src/main/java/gregtech/api/unification/material/properties/FluidPipeProperties.java
@@ -1,8 +1,10 @@
package gregtech.api.unification.material.properties;
+import gregtech.api.capability.IPropertyFluidFilter;
+
import java.util.Objects;
-public class FluidPipeProperties implements IMaterialProperty {
+public class FluidPipeProperties implements IMaterialProperty, IPropertyFluidFilter {
private int throughput;
private final int tanks;
@@ -62,6 +64,7 @@ public void setThroughput(int throughput) {
this.throughput = throughput;
}
+ @Override
public int getMaxFluidTemperature() {
return maxFluidTemperature;
}
@@ -70,6 +73,7 @@ public void setMaxFluidTemperature(int maxFluidTemperature) {
this.maxFluidTemperature = maxFluidTemperature;
}
+ @Override
public boolean isGasProof() {
return gasProof;
}
@@ -78,6 +82,7 @@ public void setGasProof(boolean gasProof) {
this.gasProof = gasProof;
}
+ @Override
public boolean isAcidProof() {
return acidProof;
}
@@ -86,6 +91,7 @@ public void setAcidProof(boolean acidProof) {
this.acidProof = acidProof;
}
+ @Override
public boolean isCryoProof() {
return cryoProof;
}
@@ -94,6 +100,7 @@ public void setCryoProof(boolean cryoProof) {
this.cryoProof = cryoProof;
}
+ @Override
public boolean isPlasmaProof() {
return plasmaProof;
}
@@ -105,27 +112,31 @@ public void setPlasmaProof(boolean plasmaProof) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (!(o instanceof FluidPipeProperties)) return false;
- FluidPipeProperties that = (FluidPipeProperties) o;
- return maxFluidTemperature == that.maxFluidTemperature &&
- throughput == that.throughput && gasProof == that.gasProof && tanks == that.tanks;
+ if (!(o instanceof FluidPipeProperties that)) return false;
+ return getThroughput() == that.getThroughput() &&
+ getTanks() == that.getTanks() &&
+ getMaxFluidTemperature() == that.getMaxFluidTemperature() &&
+ isGasProof() == that.isGasProof() &&
+ isAcidProof() == that.isAcidProof() &&
+ isCryoProof() == that.isCryoProof() &&
+ isPlasmaProof() == that.isPlasmaProof();
}
@Override
public int hashCode() {
- return Objects.hash(maxFluidTemperature, throughput, gasProof, tanks);
+ return Objects.hash(getThroughput(), getTanks(), getMaxFluidTemperature(), isGasProof(), isAcidProof(), isCryoProof(), isPlasmaProof());
}
@Override
public String toString() {
return "FluidPipeProperties{" +
- "maxFluidTemperature=" + maxFluidTemperature +
- ", throughput=" + throughput +
+ "throughput=" + throughput +
+ ", tanks=" + tanks +
+ ", maxFluidTemperature=" + maxFluidTemperature +
", gasProof=" + gasProof +
", acidProof=" + acidProof +
", cryoProof=" + cryoProof +
", plasmaProof=" + plasmaProof +
- ", tanks=" + tanks +
'}';
}
}
diff --git a/src/main/java/gregtech/api/util/GTTransferUtils.java b/src/main/java/gregtech/api/util/GTTransferUtils.java
index c1b4f24d992..eec4eefdeda 100644
--- a/src/main/java/gregtech/api/util/GTTransferUtils.java
+++ b/src/main/java/gregtech/api/util/GTTransferUtils.java
@@ -1,7 +1,6 @@
package gregtech.api.util;
import gregtech.api.capability.IMultipleTankHandler;
-import gregtech.api.recipes.FluidKey;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
@@ -17,7 +16,6 @@
import javax.annotation.Nonnull;
import java.util.List;
-import java.util.Map;
import java.util.function.Predicate;
public class GTTransferUtils {
@@ -148,18 +146,18 @@ public static boolean addFluidsToFluidHandler(IMultipleTankHandler fluidHandler,
List fluidStacks) {
if (simulate) {
OverlayedFluidHandler overlayedFluidHandler = new OverlayedFluidHandler(fluidHandler);
- Map fluidKeyMap = GTHashMaps.fromFluidCollection(fluidStacks);
- for (Map.Entry entry : fluidKeyMap.entrySet()) {
- int amountToInsert = entry.getValue();
- int inserted = overlayedFluidHandler.insertStackedFluidKey(entry.getKey(), amountToInsert);
- if (inserted != amountToInsert) {
+ for (FluidStack fluidStack : fluidStacks) {
+ int inserted = overlayedFluidHandler.insertFluid(fluidStack, fluidStack.amount);
+ if (inserted != fluidStack.amount) {
return false;
}
}
return true;
}
- fluidStacks.forEach(fluidStack -> fluidHandler.fill(fluidStack, true));
+ for (FluidStack fluidStack : fluidStacks) {
+ fluidHandler.fill(fluidStack, true);
+ }
return true;
}
diff --git a/src/main/java/gregtech/api/util/GTUtility.java b/src/main/java/gregtech/api/util/GTUtility.java
index 4d21aee5643..337ffe5ff58 100644
--- a/src/main/java/gregtech/api/util/GTUtility.java
+++ b/src/main/java/gregtech/api/util/GTUtility.java
@@ -356,15 +356,15 @@ public int size() {
* modifications in list will reflect on fluid handler and wise-versa
*/
public static List fluidHandlerToList(IMultipleTankHandler fluidInputs) {
- List backedList = fluidInputs.getFluidTanks();
+ List backedList = fluidInputs.getFluidTanks();
return new AbstractList() {
@Override
public FluidStack set(int index, FluidStack element) {
- IFluidTank fluidTank = backedList.get(index);
+ IFluidTank fluidTank = backedList.get(index).getDelegate();
FluidStack oldStack = fluidTank.getFluid();
- if (!(fluidTank instanceof FluidTank))
- return oldStack;
- ((FluidTank) backedList.get(index)).setFluid(element);
+ if (fluidTank instanceof FluidTank) {
+ ((FluidTank) fluidTank).setFluid(element);
+ }
return oldStack;
}
diff --git a/src/main/java/gregtech/api/util/OverlayedFluidHandler.java b/src/main/java/gregtech/api/util/OverlayedFluidHandler.java
index 6bb0e9b2046..309371a0286 100644
--- a/src/main/java/gregtech/api/util/OverlayedFluidHandler.java
+++ b/src/main/java/gregtech/api/util/OverlayedFluidHandler.java
@@ -1,185 +1,171 @@
package gregtech.api.util;
import gregtech.api.capability.IMultipleTankHandler;
-import gregtech.api.capability.impl.NotifiableFluidTankFromList;
-import gregtech.api.recipes.FluidKey;
-import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
-import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import gregtech.api.capability.IMultipleTankHandler.MultiFluidTankEntry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+/**
+ * Simulates consecutive fills to {@link IMultipleTankHandler} instance.
+ */
public class OverlayedFluidHandler {
- private final OverlayedTank[] overlayedTanks;
- private final OverlayedTank[] originalTanks;
- private final IMultipleTankHandler overlayed;
+ private final List overlayedTanks;
- private final ObjectOpenCustomHashSet tankDeniesSameFluidFill = new ObjectOpenCustomHashSet<>(IFluidTankPropertiesHashStrategy.create());
- private final Map> uniqueFluidMap = new Object2ObjectOpenHashMap<>();
-
- public OverlayedFluidHandler(IMultipleTankHandler toOverlay) {
- this.overlayedTanks = new OverlayedTank[toOverlay.getTankProperties().length];
- this.originalTanks = new OverlayedTank[toOverlay.getTankProperties().length];
- this.overlayed = toOverlay;
+ public OverlayedFluidHandler(@Nonnull IMultipleTankHandler tank) {
+ this.overlayedTanks = new ArrayList<>();
+ MultiFluidTankEntry[] entries = tank.getFluidTanks().toArray(new MultiFluidTankEntry[0]);
+ Arrays.sort(entries, IMultipleTankHandler.ENTRY_COMPARATOR);
+ for (MultiFluidTankEntry fluidTank : entries) {
+ for (IFluidTankProperties property : fluidTank.getTankProperties()) {
+ this.overlayedTanks.add(new OverlayedTank(property, fluidTank.allowSameFluidFill()));
+ }
+ }
}
/**
- * Resets the {slots} array to the state when the handler was
- * first mirrored
+ * Resets the internal state back to the state when the handler was
+ * first mirrored.
*/
public void reset() {
- for (int i = 0; i < this.originalTanks.length; i++) {
- if (this.originalTanks[i] != null) {
- this.overlayedTanks[i] = this.originalTanks[i].copy();
- }
- }
- uniqueFluidMap.forEach((k, v) -> v.clear());
- }
-
- public IFluidTankProperties[] getTankProperties() {
- return overlayed.getTankProperties();
- }
-
- private void initTank(int tank) {
- if (this.overlayedTanks[tank] == null) {
- IFluidTankProperties fluidTankProperties = overlayed.getTankProperties()[tank];
- this.originalTanks[tank] = new OverlayedTank(fluidTankProperties);
- this.overlayedTanks[tank] = new OverlayedTank(fluidTankProperties);
-
- if (overlayed.getTankAt(tank) instanceof NotifiableFluidTankFromList) {
- NotifiableFluidTankFromList nftfl = (NotifiableFluidTankFromList) overlayed.getTankAt(tank);
- if (!nftfl.getFluidTankList().get().allowSameFluidFill()) {
- this.tankDeniesSameFluidFill.add(overlayed.getTankProperties()[tank]);
- }
- }
+ for (OverlayedTank overlayedTank : this.overlayedTanks) {
+ overlayedTank.reset();
}
}
- public int insertStackedFluidKey(@Nonnull FluidKey toInsert, int amountToInsert) {
+ /**
+ * Simulate fluid insertion to the fluid tanks.
+ *
+ * @param fluid Fluid
+ * @param amountToInsert Amount of the fluid to insert
+ * @return Amount of fluid inserted into tanks
+ */
+ public int insertFluid(@Nonnull FluidStack fluid, int amountToInsert) {
if (amountToInsert <= 0) {
return 0;
}
- int insertedAmount = 0;
+ int totalInserted = 0;
+ // flag value indicating whether the fluid was stored in 'distinct' slot at least once
+ boolean distinctFillPerformed = false;
+
// search for tanks with same fluid type first
- for (int i = 0; i < this.overlayedTanks.length; i++) {
- // initialize the tanks if they are not already populated
- initTank(i);
- OverlayedTank overlayedTank = this.overlayedTanks[i];
- // if the fluid key matches the tank, insert the fluid
- if (toInsert.equals(overlayedTank.fluidKey)) {
- if (!markFluidAsUnique(toInsert, i)) continue;
- int canInsertUpTo = overlayedTank.tryInsert(toInsert, amountToInsert);
- if (canInsertUpTo > 0) {
- insertedAmount += canInsertUpTo;
- amountToInsert -= canInsertUpTo;
+ for (OverlayedTank overlayedTank : this.overlayedTanks) {
+ // if the fluid to insert matches the tank, insert the fluid
+ if (fluid.isFluidEqual(overlayedTank.fluid)) {
+ int inserted = overlayedTank.tryInsert(fluid, amountToInsert);
+ if (inserted > 0) {
+ totalInserted += inserted;
+ amountToInsert -= inserted;
if (amountToInsert <= 0) {
- return insertedAmount;
+ return totalInserted;
}
}
+ // regardless of whether the insertion succeeded, presence of identical fluid in
+ // a slot prevents distinct fill to other slots
+ if (!overlayedTank.allowSameFluidFill) {
+ distinctFillPerformed = true;
+ }
}
}
// if we still have fluid to insert, loop through empty tanks until we find one that can accept the fluid
- for (int i = 0; i < this.overlayedTanks.length; i++) {
- OverlayedTank overlayedTank = this.overlayedTanks[i];
- // if the tank is empty
- if (overlayedTank.fluidKey == null) {
- if (!markFluidAsUnique(toInsert, i)) continue;
- //check if this tanks accepts the fluid we're simulating
- if (overlayed.getTankProperties()[i].canFillFluidType(new FluidStack(toInsert.getFluid(), amountToInsert))) {
- int inserted = overlayedTank.tryInsert(toInsert, amountToInsert);
- if (inserted > 0) {
- insertedAmount += inserted;
- amountToInsert -= inserted;
- if (amountToInsert <= 0) {
- return insertedAmount;
- }
+ for (OverlayedTank overlayedTank : this.overlayedTanks) {
+ // if the tank uses distinct fluid fill (allowSameFluidFill disabled) and another distinct tank had
+ // received the fluid, skip this tank
+ if ((!distinctFillPerformed || overlayedTank.allowSameFluidFill) &&
+ overlayedTank.isEmpty() &&
+ overlayedTank.property.canFillFluidType(fluid)) {
+ int inserted = overlayedTank.tryInsert(fluid, amountToInsert);
+ if (inserted > 0) {
+ totalInserted += inserted;
+ amountToInsert -= inserted;
+ if (amountToInsert <= 0) {
+ return totalInserted;
+ }
+ if (!overlayedTank.allowSameFluidFill) {
+ distinctFillPerformed = true;
}
}
}
}
// return the amount of fluid that was inserted
- return insertedAmount;
+ return totalInserted;
}
- /**
- * Marks the fluid as unique, to prevent further insertions in other tank slots.
- * If the fluid is already marked as unique in previous calls to this method,
- * this method fails and returns {@code false}.
- *
- * If {@link IMultipleTankHandler#allowSameFluidFill()} is {@code false} for
- * {@link #overlayed} field or tank provider returned by {@link
- * NotifiableFluidTankFromList#getFluidTankList()}, this method gets bypassed
- * and {@code true} is returned without modifying any state.
- *
- * @param fluid the fluid to mark
- * @param tankIndex the index of the tank
- * @return {@code true} if the fluid is not marked as unique in previous calls,
- * or the tank allows same fluids to be filled in multiple slots
- */
- private boolean markFluidAsUnique(@Nonnull FluidKey fluid, int tankIndex) {
- if (overlayed.getTankAt(tankIndex) instanceof NotifiableFluidTankFromList) {
- if (!overlayed.allowSameFluidFill() || tankDeniesSameFluidFill.contains(overlayed.getTankProperties()[tankIndex])) {
- NotifiableFluidTankFromList nftfl = (NotifiableFluidTankFromList) overlayed.getTankAt(tankIndex);
- return this.uniqueFluidMap
- .computeIfAbsent(nftfl.getFluidTankList().get(), t -> new ObjectOpenHashSet<>())
- .add(fluid);
+ @Override
+ public String toString() {
+ return toString(false);
+ }
+
+ public String toString(boolean lineBreak) {
+ StringBuilder stb = new StringBuilder("OverlayedFluidHandler[").append(this.overlayedTanks.size()).append(";");
+ if (lineBreak) stb.append("\n ");
+ for (int i = 0; i < this.overlayedTanks.size(); i++) {
+ if (i != 0) stb.append(',');
+ if (lineBreak) stb.append("\n ");
+
+ OverlayedTank overlayedTank = this.overlayedTanks.get(i);
+ FluidStack fluid = overlayedTank.fluid;
+ if (fluid == null || fluid.amount == 0) {
+ stb.append("None 0 / ").append(overlayedTank.property.getCapacity());
+ } else {
+ stb.append(fluid.getFluid().getName()).append(' ').append(fluid.amount)
+ .append(" / ").append(overlayedTank.property.getCapacity());
}
- } else if (!overlayed.allowSameFluidFill()) {
- return this.uniqueFluidMap
- .computeIfAbsent(overlayed, t -> new ObjectOpenHashSet<>())
- .add(fluid);
}
- return true;
+ if (lineBreak) stb.append('\n');
+ return stb.append(']').toString();
}
private static class OverlayedTank {
- private final int capacity;
+ private final IFluidTankProperties property;
+ private final boolean allowSameFluidFill;
@Nullable
- private FluidKey fluidKey = null;
- private int fluidAmount = 0;
-
- OverlayedTank(IFluidTankProperties property) {
- FluidStack stackToMirror = property.getContents();
- if (stackToMirror != null) {
- this.fluidKey = new FluidKey(stackToMirror);
- this.fluidAmount = stackToMirror.amount;
- }
- this.capacity = property.getCapacity();
+ private FluidStack fluid;
+
+ OverlayedTank(@Nonnull IFluidTankProperties property, boolean allowSameFluidFill) {
+ this.property = property;
+ this.allowSameFluidFill = allowSameFluidFill;
+ reset();
}
- OverlayedTank(@Nullable FluidKey fluidKey, int fluidAmount, int capacity) {
- this.fluidKey = fluidKey;
- this.fluidAmount = fluidAmount;
- this.capacity = capacity;
+ public boolean isEmpty() {
+ return fluid == null || fluid.amount <= 0;
}
/**
* Tries to insert set amount of fluid into this tank. If operation succeeds,
- * the fluid key of this tank will be set to {@code fluid} and the {@code
- * fluidAmount} will be changed to reflect the state after insertion.
+ * the content of this tank will be updated.
+ *
+ * Note that this method does not check preexisting fluids for insertion.
*
- * @param fluid Fluid key
- * @param amountToInsert Amount of the fluid to insert
+ * @param fluid Fluid
+ * @param amount Amount of the fluid to insert
* @return Amount of fluid inserted into this tank
*/
- public int tryInsert(@Nonnull FluidKey fluid, int amountToInsert) {
- int maxInsert = Math.min(this.capacity - this.fluidAmount, amountToInsert);
- if (maxInsert > 0) {
- this.fluidKey = fluid;
- this.fluidAmount += maxInsert;
- return maxInsert;
- } else return 0;
+ public int tryInsert(@Nonnull FluidStack fluid, int amount) {
+ if (this.fluid == null) {
+ this.fluid = fluid.copy();
+ return this.fluid.amount = Math.min(this.property.getCapacity(), amount);
+ } else {
+ int maxInsert = Math.min(this.property.getCapacity() - this.fluid.amount, amount);
+ if (maxInsert > 0) {
+ this.fluid.amount += maxInsert;
+ return maxInsert;
+ } else return 0;
+ }
}
- public OverlayedTank copy() {
- return new OverlayedTank(this.fluidKey, this.fluidAmount, this.capacity);
+ public void reset() {
+ FluidStack fluid = this.property.getContents();
+ this.fluid = fluid != null ? fluid.copy() : null;
}
}
}
diff --git a/src/main/java/gregtech/common/items/MetaItem1.java b/src/main/java/gregtech/common/items/MetaItem1.java
index 290a2d40d2f..aac893968e7 100644
--- a/src/main/java/gregtech/common/items/MetaItem1.java
+++ b/src/main/java/gregtech/common/items/MetaItem1.java
@@ -2,6 +2,7 @@
import gregtech.api.GTValues;
import gregtech.api.GregTechAPI;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.items.metaitem.*;
import gregtech.api.items.metaitem.stats.IItemComponent;
import gregtech.api.items.metaitem.stats.IItemContainerItemProvider;
@@ -121,41 +122,41 @@ public void registerSubItems() {
// Fluid Cells: ID 78-88
FLUID_CELL = addItem(78, "fluid_cell")
- .addComponents(new ThermalFluidStats(1000, 1800, true, false, false, false, false), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, false), new ItemFluidContainer())
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_UNIVERSAL = addItem(79, "fluid_cell.universal")
- .addComponents(new ThermalFluidStats(1000, 1800, true, false, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(1000, 1800, true, false, false, false, true), new ItemFluidContainer())
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_LARGE_STEEL = addItem(80, "large_fluid_cell.steel")
- .addComponents(new ThermalFluidStats(8000, Materials.Steel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(8000, Materials.Steel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Steel, M * 4))) // ingot * 4
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_LARGE_ALUMINIUM = addItem(81, "large_fluid_cell.aluminium")
- .addComponents(new ThermalFluidStats(32000, Materials.Aluminium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(32000, Materials.Aluminium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Aluminium, M * 4))) // ingot * 4
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_LARGE_STAINLESS_STEEL = addItem(82, "large_fluid_cell.stainless_steel")
- .addComponents(new ThermalFluidStats(64000, Materials.StainlessSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, true, true, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(64000, Materials.StainlessSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, true, true, false, true), new ItemFluidContainer())
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.StainlessSteel, M * 6))) // ingot * 6
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_LARGE_TITANIUM = addItem(83, "large_fluid_cell.titanium")
- .addComponents(new ThermalFluidStats(128000, Materials.Titanium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(128000, Materials.Titanium.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Titanium, M * 6))) // ingot * 6
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_LARGE_TUNGSTEN_STEEL = addItem(84, "large_fluid_cell.tungstensteel")
- .addComponents(new ThermalFluidStats(512000, Materials.TungstenSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(512000, Materials.TungstenSteel.getProperty(PropertyKey.FLUID_PIPE).getMaxFluidTemperature(), true, false, false, false, true), new ItemFluidContainer())
.setMaxStackSize(32)
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.TungstenSteel, M * 8))) // ingot * 8
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
FLUID_CELL_GLASS_VIAL = addItem(85, "fluid_cell.glass_vial")
- .addComponents(new ThermalFluidStats(1000, 1200, false, true, false, false, true), new ItemFluidContainer())
+ .addComponents(new FilteredFluidStats(1000, 1200, false, true, false, false, true), new ItemFluidContainer())
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Glass, M / 4))) // small dust
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
@@ -171,13 +172,13 @@ public void registerSubItems() {
TOOL_LIGHTER_INVAR = addItem(91, "tool.lighter.invar")
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Invar, M * 2)))
.addComponents(new LighterBehaviour(new ResourceLocation(GTValues.MODID, "lighter_open"), true, true, true))
- .addComponents(new FilteredFluidStats(100, true, fs -> fs.getFluid().equals(Materials.Butane.getFluid()) || fs.getFluid().equals(Materials.Propane.getFluid())))
+ .addComponents(new FilteredFluidStats(100, true, CommonFluidFilters.LIGHTER_FUEL))
.setMaxStackSize(1)
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
TOOL_LIGHTER_PLATINUM = addItem(92, "tool.lighter.platinum")
.setMaterialInfo(new ItemMaterialInfo(new MaterialStack(Materials.Platinum, M * 2)))
.addComponents(new LighterBehaviour(new ResourceLocation(GTValues.MODID, "lighter_open"), true, true, true))
- .addComponents(new FilteredFluidStats(1000, true, fs -> fs.getFluid().equals(Materials.Butane.getFluid()) || fs.getFluid().equals(Materials.Propane.getFluid())))
+ .addComponents(new FilteredFluidStats(1000, true, CommonFluidFilters.LIGHTER_FUEL))
.setMaxStackSize(1)
.setRarity(EnumRarity.UNCOMMON)
.setCreativeTabs(GregTechAPI.TAB_GREGTECH_TOOLS);
diff --git a/src/main/java/gregtech/common/items/armor/PowerlessJetpack.java b/src/main/java/gregtech/common/items/armor/PowerlessJetpack.java
index 908d4f376e7..8af4658cc18 100644
--- a/src/main/java/gregtech/common/items/armor/PowerlessJetpack.java
+++ b/src/main/java/gregtech/common/items/armor/PowerlessJetpack.java
@@ -1,5 +1,7 @@
package gregtech.common.items.armor;
+import gregtech.api.capability.IFilter;
+import gregtech.api.capability.impl.GTFluidHandlerItemStack;
import gregtech.api.items.armor.ArmorMetaItem;
import gregtech.api.items.armor.ArmorMetaItem.ArmorMetaValueItem;
import gregtech.api.items.armor.ArmorUtils;
@@ -26,10 +28,8 @@
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
-import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
-import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.tuple.Pair;
@@ -192,7 +192,7 @@ public void findNewRecipe(@Nonnull ItemStack stack) {
return;
} else if (fluidStack != null) {
Recipe recipe = RecipeMaps.COMBUSTION_GENERATOR_FUELS.find(Collections.emptyList(), Collections.singletonList(fluidStack), (Objects::nonNull));
- if (recipe != null) {
+ if (recipe != null) {
previousRecipe = recipe;
currentRecipe = previousRecipe;
return;
@@ -237,6 +237,18 @@ public int getArmorDisplay(EntityPlayer player, @Nonnull ItemStack armor, int sl
public class Behaviour implements IItemDurabilityManager, IItemCapabilityProvider, IItemBehaviour, ISubItemHandler {
+ private static final IFilter JETPACK_FUEL_FILTER = new IFilter<>() {
+ @Override
+ public boolean test(@Nonnull FluidStack fluidStack) {
+ return RecipeMaps.COMBUSTION_GENERATOR_FUELS.find(Collections.emptyList(), Collections.singletonList(fluidStack), (Objects::nonNull)) != null;
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.whitelistLikePriority();
+ }
+ };
+
public final int maxCapacity;
private final Pair durabilityBarColors;
@@ -262,17 +274,9 @@ public Pair getDurabilityColorsForDisplay(ItemStack itemStack) {
@Override
public ICapabilityProvider createProvider(ItemStack itemStack) {
- return new FluidHandlerItemStack(itemStack, maxCapacity) {
- @Override
- public boolean canFillFluidType(FluidStack fluidStack) {
- return RecipeMaps.COMBUSTION_GENERATOR_FUELS.find(Collections.emptyList(), Collections.singletonList(fluidStack), (Objects::nonNull)) != null;
- }
-
- @Override
- public IFluidTankProperties[] getTankProperties() {
- return new FluidTankProperties[]{new FluidTankProperties(getFluid(), capacity, true, false)};
- }
- };
+ return new GTFluidHandlerItemStack(itemStack, maxCapacity)
+ .setFilter(JETPACK_FUEL_FILTER)
+ .setCanDrain(false);
}
@Override
diff --git a/src/main/java/gregtech/common/items/behaviors/FoamSprayerBehavior.java b/src/main/java/gregtech/common/items/behaviors/FoamSprayerBehavior.java
index 5596c606a41..83304faf8d6 100644
--- a/src/main/java/gregtech/common/items/behaviors/FoamSprayerBehavior.java
+++ b/src/main/java/gregtech/common/items/behaviors/FoamSprayerBehavior.java
@@ -1,14 +1,17 @@
package gregtech.common.items.behaviors;
+import gregtech.api.capability.impl.GTFluidHandlerItemStack;
+import gregtech.api.capability.impl.SingleFluidFilter;
import gregtech.api.items.metaitem.stats.IItemBehaviour;
import gregtech.api.items.metaitem.stats.IItemCapabilityProvider;
import gregtech.api.items.metaitem.stats.IItemDurabilityManager;
import gregtech.api.items.metaitem.stats.ISubItemHandler;
+import gregtech.api.recipes.ModHandler;
import gregtech.api.unification.material.Materials;
import gregtech.api.util.GradientUtil;
import gregtech.common.blocks.BlockFrame;
import gregtech.common.blocks.MetaBlocks;
-import net.minecraft.block.material.Material;
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
@@ -22,13 +25,14 @@
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
-import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.awt.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
+import java.util.Set;
public class FoamSprayerBehavior implements IItemCapabilityProvider, IItemDurabilityManager, IItemBehaviour, ISubItemHandler {
@@ -44,6 +48,10 @@ public FoamSprayerBehavior() {
public ActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
ItemStack itemStack = player.getHeldItem(hand);
IFluidHandlerItem fluidHandlerItem = itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null);
+ if (fluidHandlerItem == null) {
+ return ActionResult.newResult(EnumActionResult.FAIL, itemStack);
+ }
+
FluidStack fluidStack = fluidHandlerItem.drain(Integer.MAX_VALUE, false);
if (fluidStack != null && fluidStack.amount >= FLUID_PER_BLOCK) {
BlockPos offsetPos = pos.offset(facing);
@@ -87,12 +95,8 @@ public Pair getDurabilityColorsForDisplay(ItemStack itemStack) {
@Override
public ICapabilityProvider createProvider(ItemStack itemStack) {
- return new FluidHandlerItemStack(itemStack, 10000) {
- @Override
- public boolean canFillFluidType(FluidStack fluid) {
- return fluid != null && fluid.isFluidEqual(Materials.ConstructionFoam.getFluid(1));
- }
- };
+ return new GTFluidHandlerItemStack(itemStack, 10000)
+ .setFilter(new SingleFluidFilter(Materials.ConstructionFoam.getFluid(1), false));
}
private static int foamAllFrameBlocks(World world, BlockPos pos, int maxBlocksToFoam, boolean isSneaking) {
@@ -102,7 +106,8 @@ private static int foamAllFrameBlocks(World world, BlockPos pos, int maxBlocksTo
//replace blocks without updating physics
for (BlockPos framePos : frameBlocks) {
IBlockState blockState = world.getBlockState(framePos);
- boolean isNormalFrame = blockState.getBlock().getMaterial(blockState) == Material.WOOD || isSneaking;
+ boolean isNormalFrame = isSneaking ||
+ ModHandler.isMaterialWood(((BlockFrame) blockState.getBlock()).getGtMaterial(blockState));
if (isNormalFrame) {
blockState.getBlock().dropBlockAsItem(world, framePos, blockState, 0);
}
@@ -135,49 +140,49 @@ private static int foamReplacableBlocks(World world, BlockPos pos, int maxBlocks
return replacableBlocks.size();
}
- private static List gatherReplacableBlocks(World worldIn, BlockPos centerPos, int maxRadiusSq) {
- HashSet observedSet = new HashSet<>();
+ private static List gatherReplacableBlocks(World world, BlockPos centerPos, int maxRadiusSq) {
+ Set observedSet = new ObjectOpenHashSet<>();
ArrayList resultAirBlocks = new ArrayList<>();
observedSet.add(centerPos);
resultAirBlocks.add(centerPos);
- Deque moveStack = new ArrayDeque<>();
+ List moveStack = new ArrayList<>();
MutableBlockPos currentPos = new MutableBlockPos(centerPos);
main:
while (true) {
for (EnumFacing facing : EnumFacing.VALUES) {
currentPos.move(facing);
- IBlockState blockStateHere = worldIn.getBlockState(currentPos);
+ IBlockState blockStateHere = world.getBlockState(currentPos);
//if there is node, and it can connect with previous node, add it to list, and set previous node as current
- if (blockStateHere.getBlock().isReplaceable(worldIn, currentPos) &&
+ if (blockStateHere.getBlock().isReplaceable(world, currentPos) &&
currentPos.distanceSq(centerPos) <= maxRadiusSq && !observedSet.contains(currentPos)) {
BlockPos immutablePos = currentPos.toImmutable();
observedSet.add(immutablePos);
resultAirBlocks.add(immutablePos);
- moveStack.push(facing.getOpposite());
+ moveStack.add(facing.getOpposite());
continue main;
} else currentPos.move(facing.getOpposite());
}
if (!moveStack.isEmpty()) {
- currentPos.move(moveStack.pop());
+ currentPos.move(moveStack.remove(moveStack.size() - 1));
} else break;
}
resultAirBlocks.sort(Comparator.comparing(it -> it.distanceSq(centerPos)));
return resultAirBlocks;
}
- private static List gatherFrameBlocks(World worldIn, BlockPos centerPos, int maxRadiusSq) {
- HashSet observedSet = new HashSet<>();
+ private static List gatherFrameBlocks(World world, BlockPos centerPos, int maxRadiusSq) {
+ Set observedSet = new ObjectOpenHashSet<>();
ArrayList resultFrameBlocks = new ArrayList<>();
observedSet.add(centerPos);
resultFrameBlocks.add(centerPos);
IBlockState frameState = null;
- Deque moveStack = new ArrayDeque<>();
+ List moveStack = new ArrayList<>();
MutableBlockPos currentPos = new MutableBlockPos(centerPos);
main:
while (true) {
for (EnumFacing facing : EnumFacing.VALUES) {
currentPos.move(facing);
- IBlockState blockStateHere = worldIn.getBlockState(currentPos);
+ IBlockState blockStateHere = world.getBlockState(currentPos);
//if there is node, and it can connect with previous node, add it to list, and set previous node as current
if (blockStateHere.getBlock() instanceof BlockFrame &&
currentPos.distanceSq(centerPos) <= maxRadiusSq &&
@@ -185,13 +190,13 @@ private static List gatherFrameBlocks(World worldIn, BlockPos centerPo
BlockPos immutablePos = currentPos.toImmutable();
observedSet.add(immutablePos);
resultFrameBlocks.add(immutablePos);
- moveStack.push(facing.getOpposite());
+ moveStack.add(facing.getOpposite());
frameState = blockStateHere;
continue main;
} else currentPos.move(facing.getOpposite());
}
if (!moveStack.isEmpty()) {
- currentPos.move(moveStack.pop());
+ currentPos.move(moveStack.remove(moveStack.size() - 1));
} else break;
}
resultFrameBlocks.sort(Comparator.comparing(it -> it.distanceSq(centerPos)));
diff --git a/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityMultiblockTank.java b/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityMultiblockTank.java
index 6bb5b68c02f..efed08b53be 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityMultiblockTank.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityMultiblockTank.java
@@ -6,6 +6,7 @@
import codechicken.lib.vec.Matrix4;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidTankList;
+import gregtech.api.capability.impl.PropertyFluidFilter;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
import gregtech.api.gui.widgets.LabelWidget;
@@ -30,7 +31,6 @@
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
-import net.minecraftforge.fluids.FluidTank;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -52,12 +52,12 @@ public MetaTileEntityMultiblockTank(ResourceLocation metaTileEntityId, boolean i
protected void initializeInventory() {
super.initializeInventory();
- FluidTank tank = new FilteredFluidHandler(capacity).setFillPredicate(
- fluidStack -> isMetal || (!fluidStack.getFluid().isGaseous() && fluidStack.getFluid().getTemperature() <= 325));
- FluidTankList tankList = new FluidTankList(true, tank);
+ FilteredFluidHandler tank = new FilteredFluidHandler(capacity);
+ if (!isMetal) {
+ tank.setFilter(new PropertyFluidFilter(340, false, false, false, false));
+ }
- this.importFluids = tankList;
- this.exportFluids = tankList;
+ this.exportFluids = this.importFluids = new FluidTankList(true, tank);
this.fluidInventory = tank;
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiFluidHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiFluidHatch.java
index a4292ab0832..7e6edc67df9 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiFluidHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiFluidHatch.java
@@ -6,9 +6,9 @@
import gregtech.api.capability.GregtechDataCodes;
import gregtech.api.capability.GregtechTileCapabilities;
import gregtech.api.capability.IControllable;
-import gregtech.api.capability.IMultipleTankHandler;
+import gregtech.api.capability.IMultipleTankHandler.MultiFluidTankEntry;
import gregtech.api.capability.impl.FluidTankList;
-import gregtech.api.capability.impl.NotifiableFluidTankFromList;
+import gregtech.api.capability.impl.NotifiableFluidTank;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
import gregtech.api.gui.widgets.TankWidget;
@@ -34,18 +34,23 @@
import javax.annotation.Nullable;
import java.util.List;
-import java.util.function.Supplier;
public class MetaTileEntityMultiFluidHatch extends MetaTileEntityMultiblockNotifiablePart implements IMultiblockAbilityPart, IControllable {
private static final int TANK_SIZE = 16000;
- protected FluidTankList fluidTanks;
+ // only holding this for convenience
+ private final FluidTankList fluidTankList;
private boolean workingEnabled;
public MetaTileEntityMultiFluidHatch(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch) {
super(metaTileEntityId, tier, isExportHatch);
this.workingEnabled = true;
+ FluidTank[] fluidsHandlers = new FluidTank[getTier() * getTier()];
+ for (int i = 0; i < fluidsHandlers.length; i++) {
+ fluidsHandlers[i] = new NotifiableFluidTank(TANK_SIZE, this, isExportHatch);
+ }
+ this.fluidTankList = new FluidTankList(false, fluidsHandlers);
initializeInventory();
}
@@ -56,17 +61,7 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity metaTileEntityHol
@Override
protected void initializeInventory() {
- FluidTank[] fluidsHandlers = new FluidTank[(int) Math.pow(this.getTier(), 2)];
- for (int i = 0; i < fluidsHandlers.length; i++) {
- fluidsHandlers[i] = new NotifiableFluidTankFromList(TANK_SIZE, this, isExportHatch, i) {
- @Override
- public Supplier getFluidTankList() {
- return () -> MetaTileEntityMultiFluidHatch.this.fluidTanks;
- }
- };
- }
- this.fluidTanks = new FluidTankList(false, fluidsHandlers);
- this.fluidInventory = fluidTanks;
+ if (this.fluidTankList == null) return;
super.initializeInventory();
}
@@ -173,12 +168,12 @@ public void addToolUsages(ItemStack stack, @Nullable World world, List t
@Override
protected FluidTankList createImportFluidHandler() {
- return isExportHatch ? new FluidTankList(false) : new FluidTankList(false, fluidTanks);
+ return isExportHatch ? new FluidTankList(false) : fluidTankList;
}
@Override
protected FluidTankList createExportFluidHandler() {
- return isExportHatch ? new FluidTankList(false, fluidTanks) : new FluidTankList(false);
+ return isExportHatch ? fluidTankList : new FluidTankList(false);
}
@Override
@@ -188,7 +183,9 @@ public MultiblockAbility getAbility() {
@Override
public void registerAbilities(List abilityList) {
- abilityList.addAll(fluidTanks.getFluidTanks());
+ for (IFluidTank fluidTank : fluidTankList.getFluidTanks()) {
+ abilityList.add(new MultiFluidTankEntry(this.fluidTankList, fluidTank));
+ }
}
@Override
@@ -201,7 +198,7 @@ protected ModularUI createUI(EntityPlayer entityPlayer) {
for (int y = 0; y < rowSize; y++) {
for (int x = 0; x < rowSize; x++) {
int index = y * rowSize + x;
- builder.widget(new TankWidget(fluidTanks.getTankAt(index), 89 - rowSize * 9 + x * 18, 18 + y * 18, 18, 18)
+ builder.widget(new TankWidget(fluidTankList.getTankAt(index), 89 - rowSize * 9 + x * 18, 18 + y * 18, 18, 18)
.setBackgroundTexture(GuiTextures.FLUID_SLOT)
.setContainerClicking(true, !isExportHatch)
.setAlwaysShowFull(true));
diff --git a/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java b/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java
index ef670b22dd2..98962ee4b71 100644
--- a/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java
+++ b/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java
@@ -5,6 +5,7 @@
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
import gregtech.api.capability.*;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.capability.impl.NotifiableItemStackHandler;
@@ -18,7 +19,6 @@
import gregtech.api.metatileentity.IDataInfoProvider;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.interfaces.IGregTechTileEntity;
-import gregtech.api.recipes.ModHandler;
import gregtech.api.util.GTUtility;
import gregtech.client.renderer.texture.Textures;
import gregtech.client.renderer.texture.cube.SimpleSidedCubeRenderer;
@@ -80,8 +80,7 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) {
@Override
public FluidTankList createImportFluidHandler() {
- return new FluidTankList(false, new FilteredFluidHandler(16000)
- .setFillPredicate(ModHandler::isSteam));
+ return new FluidTankList(false, new FilteredFluidHandler(16000).setFilter(CommonFluidFilters.STEAM));
}
protected IItemHandlerModifiable createImportItemHandler() {
@@ -318,7 +317,7 @@ public void tryDoVenting() {
double posY = (double) machinePos.getY() + 0.5D + (double) ventingSide.getYOffset() * 0.6D;
double posZ = (double) machinePos.getZ() + 0.5D + (double) ventingSide.getZOffset() * 0.6D;
world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, posX, posY, posZ, 7 + world.rand.nextInt(3), (double) ventingSide.getXOffset() / 2.0D, (double) ventingSide.getYOffset() / 2.0D, (double) ventingSide.getZOffset() / 2.0D, 0.1D);
- if (ConfigHolder.machines.machineSounds && !this.isMuffled()){
+ if (ConfigHolder.machines.machineSounds && !this.isMuffled()) {
world.playSound(null, posX, posY, posZ, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
this.setNeedsVenting(false);
diff --git a/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamBoiler.java b/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamBoiler.java
index f9c681a1dd0..9cbe34c96c1 100644
--- a/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamBoiler.java
+++ b/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamBoiler.java
@@ -5,6 +5,7 @@
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
import gregtech.api.GTValues;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.gui.GuiTextures;
@@ -16,7 +17,6 @@
import gregtech.api.gui.widgets.TankWidget;
import gregtech.api.metatileentity.IDataInfoProvider;
import gregtech.api.metatileentity.MetaTileEntity;
-import gregtech.api.recipes.ModHandler;
import gregtech.api.unification.material.Materials;
import gregtech.api.util.GTTransferUtils;
import gregtech.api.util.GTUtility;
@@ -232,7 +232,7 @@ private void generateSteam() {
boolean hasDrainedWater = waterFluidTank.drain(1, true) != null;
int filledSteam = 0;
if (hasDrainedWater) {
- filledSteam = steamFluidTank.fill(ModHandler.getSteam(fillAmount), true);
+ filledSteam = steamFluidTank.fill(Materials.Steam.getFluid(fillAmount), true);
}
if (this.hasNoWater && hasDrainedWater) {
doExplosion(2.0f);
@@ -292,7 +292,7 @@ public double getFuelLeftPercent() {
@Override
protected FluidTankList createImportFluidHandler() {
- this.waterFluidTank = new FilteredFluidHandler(16000).setFillPredicate(ModHandler::isWater);
+ this.waterFluidTank = new FilteredFluidHandler(16000).setFilter(CommonFluidFilters.BOILER_FLUID);
return new FluidTankList(false, waterFluidTank);
}
diff --git a/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamLavaBoiler.java b/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamLavaBoiler.java
index 59371dd8649..5ab8832caed 100755
--- a/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamLavaBoiler.java
+++ b/src/main/java/gregtech/common/metatileentities/steam/boiler/SteamLavaBoiler.java
@@ -2,8 +2,10 @@
import gregtech.api.GTValues;
import gregtech.api.capability.GregtechCapabilities;
+import gregtech.api.capability.IFilter;
import gregtech.api.capability.IFuelInfo;
import gregtech.api.capability.IFuelable;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidFuelInfo;
import gregtech.api.capability.impl.FluidTankList;
@@ -14,6 +16,9 @@
import gregtech.api.metatileentity.interfaces.IGregTechTileEntity;
import gregtech.api.unification.material.Materials;
import gregtech.client.renderer.texture.Textures;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntMaps;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
@@ -25,20 +30,55 @@
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Objects;
public class SteamLavaBoiler extends SteamBoiler implements IFuelable {
- private FluidTank fuelFluidTank;
+ private static final Object2IntMap BOILER_FUEL_TO_CONSUMPTION = new Object2IntOpenHashMap<>();
+ private static boolean initialized;
+
+ private static final IFilter FUEL_FILTER = new IFilter<>() {
+ @Override
+ public boolean test(@Nonnull FluidStack fluidStack) {
+ for (Fluid fluid : getBoilerFuelToConsumption().keySet()) {
+ if (CommonFluidFilters.matchesFluid(fluidStack, fluid)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int getPriority() {
+ return IFilter.whitelistPriority(getBoilerFuelToConsumption().size());
+ }
+ };
+
+ private static void init() {
+ setBoilerFuelToConsumption(Materials.Lava.getFluid(), 100);
+ setBoilerFuelToConsumption(Materials.Creosote.getFluid(), 250);
+ }
+
+ @Nonnull
+ public static Object2IntMap getBoilerFuelToConsumption() {
+ if (!initialized) {
+ initialized = true;
+ init();
+ }
+ return Object2IntMaps.unmodifiable(BOILER_FUEL_TO_CONSUMPTION);
+ }
- private final Map boilerFuels;
+ public static void setBoilerFuelToConsumption(@Nonnull Fluid fluid, int amount) {
+ Objects.requireNonNull(fluid, "fluid == null");
+ if (amount <= 0) throw new IllegalArgumentException("amount <= 0");
+ BOILER_FUEL_TO_CONSUMPTION.put(fluid, amount);
+ }
+
+ private FluidTank fuelFluidTank;
public SteamLavaBoiler(ResourceLocation metaTileEntityId, boolean isHighPressure) {
super(metaTileEntityId, isHighPressure, Textures.LAVA_BOILER_OVERLAY);
- this.boilerFuels = getBoilerFuels();
}
@Override
@@ -51,30 +91,23 @@ protected int getBaseSteamOutput() {
return isHighPressure ? 600 : 240;
}
- private Map getBoilerFuels() {
- Map fuels = new HashMap<>();
- fuels.put(Materials.Lava.getFluid(), 100);
- fuels.put(Materials.Creosote.getFluid(), 250);
-
- return fuels;
- }
-
@Override
protected FluidTankList createImportFluidHandler() {
FluidTankList superHandler = super.createImportFluidHandler();
- this.fuelFluidTank = new FilteredFluidHandler(16000)
- .setFillPredicate(fs -> boilerFuels.containsKey(fs.getFluid()));
+ this.fuelFluidTank = new FilteredFluidHandler(16000).setFilter(FUEL_FILTER);
return new FluidTankList(false, superHandler, fuelFluidTank);
-
}
@Override
protected void tryConsumeNewFuel() {
- for(Map.Entry fuels : boilerFuels.entrySet()) {
- if(fuelFluidTank.getFluid() != null && fuelFluidTank.getFluid().isFluidEqual(new FluidStack(fuels.getKey(), fuels.getValue())) && fuelFluidTank.getFluidAmount() >= fuels.getValue()) {
- fuelFluidTank.drain(fuels.getValue(), true);
- setFuelMaxBurnTime(100);
- }
+ FluidStack fluid = fuelFluidTank.getFluid();
+ if (fluid == null || fluid.tag != null) { // fluid with nbt tag cannot match normal fluids
+ return;
+ }
+ int consumption = getBoilerFuelToConsumption().getInt(fluid.getFluid());
+ if (consumption > 0 && fuelFluidTank.getFluidAmount() >= consumption) {
+ fuelFluidTank.drain(consumption, true);
+ setFuelMaxBurnTime(100);
}
}
@@ -106,7 +139,7 @@ public Collection getFuels() {
final int fuelRemaining = fuel.amount;
final int fuelCapacity = fuelFluidTank.getCapacity();
final long burnTime = (long) fuelRemaining * (this.isHighPressure ? 6 : 12); // 100 mb lasts 600 or 1200 ticks
- return Collections.singleton(new FluidFuelInfo(fuel, fuelRemaining, fuelCapacity, boilerFuels.get(fuel.getFluid()), burnTime));
+ return Collections.singleton(new FluidFuelInfo(fuel, fuelRemaining, fuelCapacity, getBoilerFuelToConsumption().get(fuel.getFluid()), burnTime));
}
@Override
diff --git a/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamHatch.java b/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamHatch.java
index f36ec653292..9f6ce0a38f8 100644
--- a/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamHatch.java
@@ -17,7 +17,7 @@
import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart;
import gregtech.api.metatileentity.multiblock.MultiblockAbility;
import gregtech.api.metatileentity.multiblock.MultiblockControllerBase;
-import gregtech.api.recipes.ModHandler;
+import gregtech.api.capability.impl.CommonFluidFilters;
import gregtech.client.renderer.ICubeRenderer;
import gregtech.client.renderer.texture.Textures;
import gregtech.client.renderer.texture.cube.SimpleOverlayRenderer;
@@ -94,7 +94,8 @@ public int getDefaultPaintingColor() {
@Override
protected FluidTankList createImportFluidHandler() {
- return new FluidTankList(false, new FilteredFluidHandler(INVENTORY_SIZE).setFillPredicate(ModHandler::isSteam));
+ return new FluidTankList(false, new FilteredFluidHandler(INVENTORY_SIZE)
+ .setFilter(CommonFluidFilters.STEAM));
}
@Override
diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityDrum.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityDrum.java
index 15a8fff425b..78f68758bf5 100644
--- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityDrum.java
+++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityDrum.java
@@ -6,11 +6,9 @@
import codechicken.lib.render.pipeline.ColourMultiplier;
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
+import gregtech.api.capability.IPropertyFluidFilter;
import gregtech.api.capability.impl.FilteredFluidHandler;
-import gregtech.api.capability.impl.ThermalFluidHandlerItemStack;
-import gregtech.api.fluids.MaterialFluid;
-import gregtech.api.fluids.fluidType.FluidType;
-import gregtech.api.fluids.fluidType.FluidTypes;
+import gregtech.api.capability.impl.GTFluidHandlerItemStack;
import gregtech.api.gui.ModularUI;
import gregtech.api.items.toolitem.ToolClasses;
import gregtech.api.metatileentity.MetaTileEntity;
@@ -36,7 +34,6 @@
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.Constants;
-import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidUtil;
@@ -64,9 +61,6 @@ public MetaTileEntityDrum(ResourceLocation metaTileEntityId, Material material,
super(metaTileEntityId);
this.tankSize = tankSize;
this.material = material;
- if (!this.material.hasProperty(PropertyKey.FLUID_PIPE)) {
- throw new IllegalArgumentException(String.format("Material %s requires FluidPipePropety for Drums", material));
- }
initializeInventory();
}
@@ -106,26 +100,13 @@ public boolean hasFrontFacing() {
@Override
protected void initializeInventory() {
+ if (this.material == null) return; // call before field initialization, should be called later with fields set
super.initializeInventory();
- this.fluidTank = new FilteredFluidHandler(tankSize)
- .setFillPredicate(stack -> {
- if (stack == null || stack.getFluid() == null) return false;
-
- Fluid fluid = stack.getFluid();
- FluidPipeProperties pipeProperties = material.getProperty(PropertyKey.FLUID_PIPE);
- if (fluid.getTemperature() > pipeProperties.getMaxFluidTemperature()) return false;
- // fluids less than 120K are cryogenic
- if (fluid.getTemperature() < 120 && !pipeProperties.isCryoProof()) return false;
- if (fluid.isGaseous() && !pipeProperties.isGasProof()) return false;
-
- if (fluid instanceof MaterialFluid) {
- FluidType fluidType = ((MaterialFluid) fluid).getFluidType();
- if (fluidType == FluidTypes.ACID && !pipeProperties.isAcidProof()) return false;
- return fluidType != FluidTypes.PLASMA || pipeProperties.isPlasmaProof();
- }
- return true;
- });
- this.fluidInventory = fluidTank;
+ IPropertyFluidFilter filter = this.material.getProperty(PropertyKey.FLUID_PIPE);
+ if (filter == null) {
+ throw new IllegalArgumentException(String.format("Material %s requires FluidPipePropety for Drums", material));
+ }
+ this.fluidInventory = this.fluidTank = new FilteredFluidHandler(tankSize).setFilter(filter);
}
@Override
@@ -150,13 +131,7 @@ public void writeItemStackData(NBTTagCompound itemStack) {
@Override
public ICapabilityProvider initItemStackCapabilities(ItemStack itemStack) {
- FluidPipeProperties pipeProperties = material.getProperty(PropertyKey.FLUID_PIPE);
- return new ThermalFluidHandlerItemStack(itemStack, tankSize,
- pipeProperties.getMaxFluidTemperature(),
- pipeProperties.isGasProof(),
- pipeProperties.isAcidProof(),
- pipeProperties.isCryoProof(),
- pipeProperties.isPlasmaProof());
+ return new GTFluidHandlerItemStack(itemStack, tankSize).setFilter(this.fluidTank.getFilter());
}
@Override
@@ -240,7 +215,7 @@ private void toggleOutput() {
@Override
@SideOnly(Side.CLIENT)
public Pair getParticleTexture() {
- if(ModHandler.isMaterialWood(material)) {
+ if (ModHandler.isMaterialWood(material)) {
return Pair.of(Textures.WOODEN_DRUM.getParticleTexture(), getPaintingColorForRendering());
} else {
int color = ColourRGBA.multiply(
@@ -253,7 +228,7 @@ public Pair getParticleTexture() {
@Override
public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) {
- if(ModHandler.isMaterialWood(material)) {
+ if (ModHandler.isMaterialWood(material)) {
ColourMultiplier multiplier = new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(getPaintingColorForRendering()));
Textures.WOODEN_DRUM.render(renderState, translation, ArrayUtils.add(pipeline, multiplier), getFrontFacing());
} else {
@@ -332,5 +307,4 @@ public void readFromNBT(NBTTagCompound data) {
protected boolean shouldSerializeInventories() {
return false;
}
-
}
diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java
index f980e8e99c1..5a12b5ffbd9 100644
--- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java
+++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java
@@ -7,10 +7,12 @@
import codechicken.lib.vec.Matrix4;
import gregtech.api.capability.GregtechTileCapabilities;
import gregtech.api.capability.IActiveOutputSide;
+import gregtech.api.capability.IFilter;
+import gregtech.api.capability.IFilteredFluidContainer;
import gregtech.api.capability.impl.FilteredItemHandler;
import gregtech.api.capability.impl.FluidHandlerProxy;
import gregtech.api.capability.impl.FluidTankList;
-import gregtech.api.capability.impl.ThermalFluidHandlerItemStack;
+import gregtech.api.capability.impl.GTFluidHandlerItemStack;
import gregtech.api.cover.ICoverable;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
@@ -51,6 +53,7 @@
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
@@ -65,10 +68,12 @@ public class MetaTileEntityQuantumTank extends MetaTileEntity implements ITiered
private final int maxFluidCapacity;
protected FluidTank fluidTank;
private boolean autoOutputFluids;
+ @Nullable
private EnumFacing outputFacing;
private boolean allowInputFromOutputSide = false;
protected IFluidHandler outputFluidInventory;
+ @Nullable
private FluidStack previousFluid;
private boolean locked;
private boolean voiding;
@@ -335,8 +340,7 @@ private Consumer> getFluidNameText(TankWidget tankWidget) {
if (this.lockedFluid != null) {
fluidName = this.lockedFluid.getLocalizedName();
}
- }
- else {
+ } else {
fluidName = tankWidget.getFluidLocalizedName();
}
@@ -357,8 +361,7 @@ private Consumer> getFluidAmountText(TankWidget tankWidget)
if (this.lockedFluid != null) {
fluidAmount = "0";
}
- }
- else {
+ } else {
fluidAmount = tankWidget.getFormattedFluidAmount();
}
if (!fluidAmount.isEmpty()) {
@@ -491,7 +494,7 @@ public T getCapability(Capability capability, EnumFacing side) {
@Override
public ICapabilityProvider initItemStackCapabilities(ItemStack itemStack) {
- return new ThermalFluidHandlerItemStack(itemStack, maxFluidCapacity, Integer.MAX_VALUE, true, true, true, true);
+ return new GTFluidHandlerItemStack(itemStack, maxFluidCapacity);
}
@Override
@@ -577,7 +580,22 @@ public boolean needsSneakToRotate() {
return true;
}
- private class QuantumFluidTank extends FluidTank {
+ @Override
+ public AxisAlignedBB getRenderBoundingBox() {
+ return new AxisAlignedBB(getPos());
+ }
+
+ @Override
+ public boolean isOpaqueCube() {
+ return false;
+ }
+
+ @Override
+ public int getLightOpacity() {
+ return 0;
+ }
+
+ private class QuantumFluidTank extends FluidTank implements IFilteredFluidContainer, IFilter {
public QuantumFluidTank(int capacity) {
super(capacity);
@@ -595,22 +613,22 @@ public int fillInternal(FluidStack resource, boolean doFill) {
@Override
public boolean canFillFluidType(FluidStack fluid) {
- return !locked || lockedFluid == null || fluid.isFluidEqual(lockedFluid);
+ return test(fluid);
}
- }
- @Override
- public AxisAlignedBB getRenderBoundingBox() {
- return new AxisAlignedBB(getPos());
- }
+ @Override
+ public IFilter getFilter() {
+ return this;
+ }
- @Override
- public boolean isOpaqueCube() {
- return false;
- }
+ @Override
+ public boolean test(@Nonnull FluidStack fluidStack) {
+ return !locked || lockedFluid == null || fluidStack.isFluidEqual(lockedFluid);
+ }
- @Override
- public int getLightOpacity() {
- return 0;
+ @Override
+ public int getPriority() {
+ return !locked || lockedFluid == null ? IFilter.noPriority() : IFilter.whitelistPriority(1);
+ }
}
}
diff --git a/src/main/java/gregtech/common/pipelike/fluidpipe/tile/TileEntityFluidPipeTickable.java b/src/main/java/gregtech/common/pipelike/fluidpipe/tile/TileEntityFluidPipeTickable.java
index be6d6f1e3c5..427525fc3fd 100644
--- a/src/main/java/gregtech/common/pipelike/fluidpipe/tile/TileEntityFluidPipeTickable.java
+++ b/src/main/java/gregtech/common/pipelike/fluidpipe/tile/TileEntityFluidPipeTickable.java
@@ -1,12 +1,13 @@
package gregtech.common.pipelike.fluidpipe.tile;
import gregtech.api.GTValues;
-import gregtech.api.capability.GregtechCapabilities;
+import gregtech.api.capability.IPropertyFluidFilter;
import gregtech.api.cover.CoverBehavior;
import gregtech.api.fluids.MaterialFluid;
import gregtech.api.fluids.fluidType.FluidTypes;
import gregtech.api.metatileentity.IDataInfoProvider;
import gregtech.api.metatileentity.MetaTileEntity;
+import gregtech.api.unification.material.properties.FluidPipeProperties;
import gregtech.api.util.EntityDamageUtil;
import gregtech.api.util.GTUtility;
import gregtech.common.covers.CoverPump;
@@ -111,15 +112,16 @@ private void distributeFluid(int channel, FluidTank tank, FluidStack fluid) {
FluidStack maxFluid = fluid.copy();
double availableCapacity = 0;
- for (byte side, i = 0, j = (byte) GTValues.RNG.nextInt(6); i < 6; i++) {
+ for (byte i = 0, j = (byte) GTValues.RNG.nextInt(6); i < 6; i++) {
// Get a list of tanks accepting fluids, and what side they're on
- side = (byte) ((i + j) % 6);
+ byte side = (byte) ((i + j) % 6);
EnumFacing facing = EnumFacing.VALUES[side];
- if (!isConnected(facing) || (lastReceivedFrom & (1 << side)) != 0)
+
+ if (!isConnected(facing) || (lastReceivedFrom & (1 << side)) != 0) {
continue;
- EnumFacing oppositeSide = facing.getOpposite();
+ }
- IFluidHandler fluidHandler = getFluidHandlerAt(facing, oppositeSide);
+ IFluidHandler fluidHandler = getFluidHandlerAt(facing, facing.getOpposite());
if (fluidHandler == null)
continue;
@@ -127,31 +129,25 @@ private void distributeFluid(int channel, FluidTank tank, FluidStack fluid) {
CoverBehavior cover = getCoverableImplementation().getCoverAtSide(facing);
// pipeTank should only be determined by the cover attached to the actual pipe
- if (cover != null){
- IFluidHandler capability = cover.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, pipeTank);
+ if (cover != null) {
+ pipeTank = cover.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, pipeTank);
// Shutter covers return null capability when active, so check here to prevent NPE
- if (capability == null) {
- continue;
- }
- pipeTank = capability;
+ if (pipeTank == null) continue;
} else {
- cover = getOtherCoverAt(facing, oppositeSide);
+ MetaTileEntity tile = GTUtility.getMetaTileEntity(world, pos.offset(facing));
+ if (tile != null) cover = tile.getCoverAtSide(facing.getOpposite());
}
- if (cover instanceof CoverPump) {
-
+ if (cover instanceof CoverPump coverPump) {
int pipeThroughput = getNodeData().getThroughput() * 20;
- if (((CoverPump) cover).getTransferRate() > pipeThroughput) {
- ((CoverPump) cover).setTransferRate(pipeThroughput);
+ if (coverPump.getTransferRate() > pipeThroughput) {
+ coverPump.setTransferRate(pipeThroughput);
}
-
- ManualImportExportMode mode = ((CoverPump) cover).getManualImportExportMode();
- if (mode == ManualImportExportMode.DISABLED) {
+ if (coverPump.getManualImportExportMode() == ManualImportExportMode.DISABLED) {
continue;
}
}
-
FluidStack drainable = pipeTank.drain(maxFluid, false);
if (drainable == null || drainable.amount <= 0) {
continue;
@@ -178,7 +174,8 @@ private void distributeFluid(int channel, FluidTank tank, FluidStack fluid) {
triple.setRight((int) Math.floor(triple.getRight() * maxAmount / availableCapacity)); // Distribute fluids based on percentage available space at destination
}
if (triple.getRight() == 0) {
- if (tank.getFluidAmount() <= 0) break; // If there is no more stored fluid, stop transferring to prevent dupes
+ if (tank.getFluidAmount() <= 0)
+ break; // If there is no more stored fluid, stop transferring to prevent dupes
triple.setRight(1); // If the percent is not enough to give at least 1L, try to give 1L
} else if (triple.getRight() < 0) {
continue;
@@ -196,18 +193,20 @@ private void distributeFluid(int channel, FluidTank tank, FluidStack fluid) {
public void checkAndDestroy(@Nonnull FluidStack stack) {
Fluid fluid = stack.getFluid();
- boolean burning = getNodeData().getMaxFluidTemperature() < fluid.getTemperature(stack);
- boolean leaking = !getNodeData().isGasProof() && fluid.isGaseous(stack);
- boolean shattering = !getNodeData().isCryoProof() && fluid.getTemperature() < 120; // fluids less than 120K are cryogenic
+ FluidPipeProperties prop = getNodeData();
+
+ boolean burning = prop.getMaxFluidTemperature() < fluid.getTemperature(stack);
+ boolean leaking = !prop.isGasProof() && fluid.isGaseous(stack);
+ boolean shattering = !prop.isCryoProof() && fluid.getTemperature() < IPropertyFluidFilter.CRYOGENIC_TEMPERATURE_THRESHOLD;
boolean corroding = false;
boolean melting = false;
- if (fluid instanceof MaterialFluid) {
- MaterialFluid materialFluid = (MaterialFluid) fluid;
- corroding = !getNodeData().isAcidProof() && materialFluid.getFluidType().equals(FluidTypes.ACID);
- melting = !getNodeData().isPlasmaProof() && materialFluid.getFluidType().equals(FluidTypes.PLASMA);
+
+ if (fluid instanceof MaterialFluid materialFluid) {
+ corroding = !prop.isAcidProof() && materialFluid.getFluidType().equals(FluidTypes.ACID);
+ melting = !prop.isPlasmaProof() && materialFluid.getFluidType().equals(FluidTypes.PLASMA);
// carrying plasmas which are too hot when plasma proof does not burn pipes
- if (burning && getNodeData().isPlasmaProof() && materialFluid.getFluidType().equals(FluidTypes.PLASMA))
+ if (burning && prop.isPlasmaProof() && materialFluid.getFluidType().equals(FluidTypes.PLASMA))
burning = false;
}
@@ -319,14 +318,6 @@ private IFluidHandler getFluidHandlerAt(EnumFacing facing, EnumFacing oppositeSi
return tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, oppositeSide);
}
- private CoverBehavior getOtherCoverAt(EnumFacing facing, EnumFacing oppositeSide) {
- MetaTileEntity tile = GTUtility.getMetaTileEntity(world, pos.offset(facing));
- if (tile == null) {
- return null;
- }
- return tile.getCoverAtSide(oppositeSide);
- }
-
public void receivedFrom(EnumFacing facing) {
if (facing != null) {
lastReceivedFrom |= (1 << facing.getIndex());
diff --git a/src/main/java/gregtech/core/CoreModule.java b/src/main/java/gregtech/core/CoreModule.java
index eb92cfe9ac9..57f12dbc2a9 100644
--- a/src/main/java/gregtech/core/CoreModule.java
+++ b/src/main/java/gregtech/core/CoreModule.java
@@ -135,7 +135,6 @@ public void preInit(FMLPreInitializationEvent event) {
MetaItems.init();
ToolItems.init();
MetaFluids.init();
- ModHandler.init();
/* Start MetaTileEntity Registration */
MTE_REGISTRY.unfreeze();
diff --git a/src/test/java/gregtech/Bootstrap.java b/src/test/java/gregtech/Bootstrap.java
index edbecea3587..e450bceae47 100644
--- a/src/test/java/gregtech/Bootstrap.java
+++ b/src/test/java/gregtech/Bootstrap.java
@@ -3,7 +3,6 @@
import gregtech.api.GTValues;
import gregtech.api.GregTechAPI;
import gregtech.api.fluids.MetaFluids;
-import gregtech.api.recipes.ModHandler;
import gregtech.api.unification.material.Materials;
import gregtech.api.unification.ore.OrePrefix;
import gregtech.common.items.MetaItems;
@@ -67,7 +66,6 @@ public static void perform() {
OrePrefix.runMaterialHandlers();
MetaFluids.init();
MetaItems.init();
- ModHandler.init();
bootstrapped = true;
}
diff --git a/src/test/java/gregtech/api/capability/impl/FluidTankListTest.java b/src/test/java/gregtech/api/capability/impl/FluidTankListTest.java
new file mode 100644
index 00000000000..ed636cfa186
--- /dev/null
+++ b/src/test/java/gregtech/api/capability/impl/FluidTankListTest.java
@@ -0,0 +1,435 @@
+package gregtech.api.capability.impl;
+
+import gregtech.Bootstrap;
+import gregtech.api.capability.IMultipleTankHandler;
+import gregtech.api.unification.material.Materials;
+import gregtech.api.util.OverlayedFluidHandler;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTank;
+import net.minecraftforge.fluids.IFluidTank;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import static net.minecraftforge.fluids.FluidRegistry.LAVA;
+import static net.minecraftforge.fluids.FluidRegistry.WATER;
+
+public class FluidTankListTest {
+
+ @BeforeAll
+ public static void bootstrap() {
+ Bootstrap.perform();
+ }
+
+ @Test
+ public void testSimpleFills() {
+ new FluidHandlerTester(false,
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 1000)
+ .expectContents(new FluidStack(WATER, 1000));
+
+ new FluidHandlerTester(false,
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 333))
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 666))
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 999))
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 1000));
+
+ new FluidHandlerTester(false,
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 333), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 666), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 999), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 1000), null);
+
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 333), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 666), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 999), null)
+ .fill(WATER, 333)
+ .expectContents(new FluidStack(WATER, 1000), new FluidStack(WATER, 332));
+
+ new FluidHandlerTester(false,
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 1500)
+ .expectContents(new FluidStack(WATER, 1000), null);
+
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 1500)
+ .expectContents(new FluidStack(WATER, 1000), new FluidStack(WATER, 500));
+ }
+
+ @Test
+ public void testMultipleFluidFills() {
+ new FluidHandlerTester(false,
+ new FluidTank(1000),
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(LAVA, 800),
+ null)
+ .drain(WATER, 1000)
+ .expectContents(
+ null,
+ new FluidStack(LAVA, 800),
+ null)
+ .fill(LAVA, 800)
+ .expectContents(
+ null,
+ new FluidStack(LAVA, 1000),
+ null)
+ .fill(LAVA, 800)
+ .expectContents(
+ null,
+ new FluidStack(LAVA, 1000),
+ null);
+
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 600),
+ new FluidStack(LAVA, 800))
+ .drain(WATER, 1600)
+ .expectContents(
+ null,
+ null,
+ new FluidStack(LAVA, 800))
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(LAVA, 600),
+ null,
+ new FluidStack(LAVA, 1000))
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(LAVA, 1000),
+ new FluidStack(LAVA, 400),
+ new FluidStack(LAVA, 1000))
+ .fill(WATER, 69420)
+ .expectContents(
+ new FluidStack(LAVA, 1000),
+ new FluidStack(LAVA, 400),
+ new FluidStack(LAVA, 1000));
+ }
+
+ @Test
+ public void testMixedSameFluidFill() {
+ new FluidHandlerTester(new FluidTankList(true,
+ new FluidTankList(false,
+ new FluidTank(1000),
+ new FluidTank(1000)
+ ),
+ new FluidTank(1000),
+ new FluidTank(1000))) // distinct slots first
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ null,
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 400));
+
+ new FluidHandlerTester(new FluidTankList(false,
+ new FluidTankList(true,
+ new FluidTank(1000),
+ new FluidTank(1000)
+ ),
+ new FluidTank(1000),
+ new FluidTank(1000))) // non-distinct slots first
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 400),
+ null);
+ }
+
+ @Test
+ public void testDrain() {
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FluidTank(1000),
+ new FluidTank(1000))
+ .fill(WATER, 1500)
+ .fill(LAVA, 500)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 500),
+ new FluidStack(LAVA, 500))
+ .drain(1000)
+ .expectContents(
+ null,
+ new FluidStack(WATER, 500),
+ new FluidStack(LAVA, 500))
+ .drain(1000)
+ .expectContents(
+ null,
+ null,
+ new FluidStack(LAVA, 500))
+ .drain(1000)
+ .expectContents(
+ null,
+ null,
+ null)
+ .fill(LAVA, 500)
+ .fill(WATER, 1500)
+ .expectContents(
+ new FluidStack(LAVA, 500),
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 500))
+ .drain(1000)
+ .expectContents(
+ null,
+ new FluidStack(WATER, 1000),
+ new FluidStack(WATER, 500))
+ .drain(500)
+ .expectContents(
+ null,
+ new FluidStack(WATER, 500),
+ new FluidStack(WATER, 500))
+ .drain(1000)
+ .expectContents(
+ null,
+ null,
+ null);
+ }
+
+ @Test
+ public void testFilterOrdering() {
+ SingleFluidFilter waterFilter = new SingleFluidFilter(new FluidStack(WATER, 1), false);
+ SingleFluidFilter lavaFilter = new SingleFluidFilter(new FluidStack(LAVA, 1), false);
+ SingleFluidFilter creosoteFilter = new SingleFluidFilter(new FluidStack(Materials.Creosote.getFluid(), 1), false);
+
+ new FluidHandlerTester(false,
+ new FilteredFluidHandler(1000).setFilter(waterFilter),
+ new FilteredFluidHandler(1000).setFilter(lavaFilter),
+ new FilteredFluidHandler(1000).setFilter(creosoteFilter))
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(LAVA, 800),
+ null);
+
+ new FluidHandlerTester(true,
+ new FilteredFluidHandler(1000).setFilter(waterFilter),
+ new FilteredFluidHandler(1000).setFilter(lavaFilter),
+ new FilteredFluidHandler(1000).setFilter(creosoteFilter))
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(WATER, 1000),
+ new FluidStack(LAVA, 800),
+ null);
+
+ new FluidHandlerTester(true,
+ new FilteredFluidHandler(1000).setFilter(waterFilter),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(WATER, 800),
+ new FluidStack(LAVA, 800));
+
+ new FluidHandlerTester(true,
+ new FilteredFluidHandler(1000).setFilter(waterFilter),
+ new FluidTank(1000))
+ .beginSimulation()
+ .fill(LAVA, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(WATER, 800),
+ new FluidStack(LAVA, 800));
+
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FilteredFluidHandler(1000).setFilter(waterFilter))
+ .beginSimulation()
+ .fill(WATER, 800)
+ .fill(LAVA, 800)
+ .expectContents(
+ new FluidStack(LAVA, 800),
+ new FluidStack(WATER, 800));
+
+ new FluidHandlerTester(true,
+ new FluidTank(1000),
+ new FilteredFluidHandler(1000).setFilter(waterFilter))
+ .beginSimulation()
+ .fill(LAVA, 800)
+ .fill(WATER, 800)
+ .expectContents(
+ new FluidStack(LAVA, 800),
+ new FluidStack(WATER, 800));
+ }
+
+ private static final class FluidHandlerTester {
+
+ private final FluidTankList tank;
+
+ @Nullable
+ private OverlayedFluidHandler overlayedFluidHandler;
+
+ FluidHandlerTester(FluidTankList tank) {
+ this.tank = tank;
+ }
+
+ FluidHandlerTester(boolean allowSameFluidFill, IFluidTank... tanks) {
+ this(new FluidTankList(allowSameFluidFill, tanks));
+ }
+
+ FluidHandlerTester fill(Fluid fluid, int amount) {
+ return fill(new FluidStack(fluid, amount));
+ }
+
+ FluidHandlerTester fill(FluidStack fluidStack) {
+ // make string representation before modifying the state, to produce better error message
+ String tankString = this.tank.toString(true);
+
+ int tankFillSim = this.tank.fill(fluidStack, false);
+
+ if (this.overlayedFluidHandler != null) {
+ String overlayString = this.overlayedFluidHandler.toString(true);
+ int ofhSim = this.overlayedFluidHandler.insertFluid(fluidStack, fluidStack.amount);
+
+ if (tankFillSim != ofhSim) {
+ throw new AssertionError("Result of simulation fill from tank and OFH differ.\n" +
+ "Tank Simulation: " + tankFillSim + ", OFH simulation: " + ofhSim + "\n" +
+ "Tank: " + tankString + "\n" +
+ "OFH: " + overlayString);
+ }
+ }
+ int actualFill = this.tank.fill(fluidStack, true);
+ if (tankFillSim != actualFill) {
+ throw new AssertionError("Simulation fill to tank and actual fill differ.\n" +
+ "Simulated Fill: " + tankFillSim + ", Actual Fill: " + actualFill + "\n" +
+ "Tank: " + tankString);
+ }
+ return this;
+ }
+
+ FluidHandlerTester drain(Fluid fluid, int amount) {
+ return drain(new FluidStack(fluid, amount));
+ }
+
+ FluidHandlerTester drain(FluidStack fluidStack) {
+ if (this.overlayedFluidHandler != null) {
+ throw new IllegalStateException("Cannot drain stuff in simulation");
+ }
+ // make string representation before modifying the state, to produce better error message
+ String tankString = this.tank.toString(true);
+
+ FluidStack drainSim = this.tank.drain(fluidStack, false);
+ FluidStack actualDrain = this.tank.drain(fluidStack, true);
+
+ if (!eq(drainSim, actualDrain)) {
+ throw new AssertionError("Simulation drain from tank and actual drain differ.\n" +
+ "Simulated Drain: " + ftos(drainSim) + ", Actual Drain: " + ftos(actualDrain) + "\n" +
+ "Tank: " + tankString);
+ }
+ return this;
+ }
+
+ FluidHandlerTester drain(int amount) {
+ if (this.overlayedFluidHandler != null) {
+ throw new IllegalStateException("Cannot drain stuff in simulation");
+ }
+ // make string representation before modifying the state, to produce better error message
+ String tankString = this.tank.toString(true);
+
+ FluidStack drainSim = this.tank.drain(amount, false);
+ FluidStack actualDrain = this.tank.drain(amount, true);
+
+ if (!eq(drainSim, actualDrain)) {
+ throw new AssertionError("Simulation drain from tank and actual drain differ.\n" +
+ "Simulated Drain: " + ftos(drainSim) + ", Actual Drain: " + ftos(actualDrain) + "\n" +
+ "Tank: " + tankString);
+ }
+ return this;
+ }
+
+ FluidHandlerTester beginSimulation() {
+ if (this.overlayedFluidHandler != null) {
+ throw new IllegalStateException("Simulation already begun");
+ }
+ this.overlayedFluidHandler = new OverlayedFluidHandler(this.tank);
+ return this;
+ }
+
+ FluidHandlerTester expectContents(@Nonnull FluidStack... optionalFluidStacks) {
+ if (optionalFluidStacks.length != this.tank.getTanks()) {
+ throw new IllegalArgumentException("Wrong number of fluids to compare; " +
+ "expected: " + this.tank.getTanks() + ", provided: " + optionalFluidStacks.length);
+ }
+ for (int i = 0; i < optionalFluidStacks.length; i++) {
+ IMultipleTankHandler.MultiFluidTankEntry tank = this.tank.getTankAt(i);
+ if (!eq(tank.getFluid(), optionalFluidStacks[i])) {
+ throw new AssertionError("Contents of the tank don't match expected state.\n" +
+ "Expected: [\n " + Arrays.stream(optionalFluidStacks)
+ .map(FluidHandlerTester::ftos)
+ .collect(Collectors.joining(",\n ")) + "\n]\n" +
+ "Tank: " + this.tank.toString(true));
+ }
+ }
+ return this;
+ }
+
+ static boolean eq(@Nullable FluidStack fluid1, @Nullable FluidStack fluid2) {
+ if (fluid1 == null || fluid1.amount <= 0) {
+ return fluid2 == null || fluid2.amount <= 0;
+ } else {
+ return fluid1.isFluidEqual(fluid2);
+ }
+ }
+
+ static String ftos(@Nullable FluidStack fluid) {
+ return fluid == null ? "Empty" : fluid.getFluid().getName() + " / " + fluid.amount;
+ }
+ }
+}