aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/logic
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gregtech/api/logic')
-rw-r--r--src/main/java/gregtech/api/logic/AbstractProcessingLogic.java346
-rw-r--r--src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java219
-rw-r--r--src/main/java/gregtech/api/logic/ControllerFluidLogic.java152
-rw-r--r--src/main/java/gregtech/api/logic/ControllerItemLogic.java148
-rw-r--r--src/main/java/gregtech/api/logic/FluidInventoryLogic.java269
-rw-r--r--src/main/java/gregtech/api/logic/ItemInventoryLogic.java314
-rw-r--r--src/main/java/gregtech/api/logic/MuTEProcessingLogic.java256
-rw-r--r--src/main/java/gregtech/api/logic/NullPowerLogic.java5
-rw-r--r--src/main/java/gregtech/api/logic/PollutionLogic.java17
-rw-r--r--src/main/java/gregtech/api/logic/PowerLogic.java129
-rw-r--r--src/main/java/gregtech/api/logic/ProcessingLogic.java323
-rw-r--r--src/main/java/gregtech/api/logic/interfaces/FluidInventoryLogicHost.java95
-rw-r--r--src/main/java/gregtech/api/logic/interfaces/ItemInventoryLogicHost.java172
-rw-r--r--src/main/java/gregtech/api/logic/interfaces/PollutionLogicHost.java8
-rw-r--r--src/main/java/gregtech/api/logic/interfaces/PowerLogicHost.java48
-rw-r--r--src/main/java/gregtech/api/logic/interfaces/ProcessingLogicHost.java80
16 files changed, 2094 insertions, 487 deletions
diff --git a/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java
new file mode 100644
index 0000000000..ae78bbacc2
--- /dev/null
+++ b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java
@@ -0,0 +1,346 @@
+package gregtech.api.logic;
+
+import java.util.function.Supplier;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.api.interfaces.tileentity.IVoidable;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.check.CheckRecipeResult;
+import gregtech.api.recipe.check.CheckRecipeResultRegistry;
+import gregtech.api.util.GT_OverclockCalculator;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+
+/**
+ * Logic class to calculate result of recipe check from inputs.
+ */
+@SuppressWarnings({ "unused", "UnusedReturnValue" })
+public abstract class AbstractProcessingLogic<P extends AbstractProcessingLogic<P>> {
+
+ protected IVoidable machine;
+ protected Supplier<RecipeMap<?>> recipeMapSupplier;
+ protected GT_Recipe lastRecipe;
+ protected RecipeMap<?> lastRecipeMap;
+ protected ItemStack[] outputItems;
+ protected FluidStack[] outputFluids;
+ protected long calculatedEut;
+ protected int duration;
+ protected long availableVoltage;
+ protected long availableAmperage;
+ protected int overClockTimeReduction = 1;
+ protected int overClockPowerIncrease = 2;
+ protected boolean protectItems;
+ protected boolean protectFluids;
+ protected int maxParallel = 1;
+ protected Supplier<Integer> maxParallelSupplier;
+ protected int calculatedParallels = 0;
+ protected int batchSize = 1;
+ protected float euModifier = 1.0f;
+ protected float speedBoost = 1.0f;
+ protected boolean amperageOC = true;
+ protected boolean isCleanroom;
+
+ // #region Setters
+
+ /**
+ * Overwrites item output result of the calculation.
+ */
+ public P setOutputItems(ItemStack... itemOutputs) {
+ this.outputItems = itemOutputs;
+ return getThis();
+ }
+
+ /**
+ * Overwrites fluid output result of the calculation.
+ */
+ public P setOutputFluids(FluidStack... fluidOutputs) {
+ this.outputFluids = fluidOutputs;
+ return getThis();
+ }
+
+ public P setIsCleanroom(boolean isCleanroom) {
+ this.isCleanroom = isCleanroom;
+ return getThis();
+ }
+
+ /**
+ * Sets max amount of parallel.
+ */
+ public P setMaxParallel(int maxParallel) {
+ this.maxParallel = maxParallel;
+ return getThis();
+ }
+
+ /**
+ * Sets method to get max amount of parallel.
+ */
+ public P setMaxParallelSupplier(Supplier<Integer> supplier) {
+ this.maxParallelSupplier = supplier;
+ return getThis();
+ }
+
+ /**
+ * Sets batch size for batch mode.
+ */
+ public P setBatchSize(int size) {
+ this.batchSize = size;
+ return getThis();
+ }
+
+ public P setRecipeMap(RecipeMap<?> recipeMap) {
+ return setRecipeMapSupplier(() -> recipeMap);
+ }
+
+ public P setRecipeMapSupplier(Supplier<RecipeMap<?>> supplier) {
+ this.recipeMapSupplier = supplier;
+ return getThis();
+ }
+
+ public P setEuModifier(float modifier) {
+ this.euModifier = modifier;
+ return getThis();
+ }
+
+ public P setSpeedBonus(float speedModifier) {
+ this.speedBoost = speedModifier;
+ return getThis();
+ }
+
+ /**
+ * Sets machine used for void protection logic.
+ */
+ public P setMachine(IVoidable machine) {
+ this.machine = machine;
+ return getThis();
+ }
+
+ /**
+ * Overwrites duration result of the calculation.
+ */
+ public P setDuration(int duration) {
+ this.duration = duration;
+ return getThis();
+ }
+
+ /**
+ * Overwrites EU/t result of the calculation.
+ */
+ public P setCalculatedEut(long calculatedEut) {
+ this.calculatedEut = calculatedEut;
+ return getThis();
+ }
+
+ /**
+ * Sets voltage of the machine. It doesn't need to be actual voltage (excluding amperage) of the machine;
+ * For example, most of the multiblock machines set maximum possible input power (including amperage) as voltage
+ * and 1 as amperage. That way recipemap search will be executed with overclocked voltage.
+ */
+ public P setAvailableVoltage(long voltage) {
+ availableVoltage = voltage;
+ return getThis();
+ }
+
+ /**
+ * Sets amperage of the machine. This amperage doesn't involve in EU/t when searching recipemap.
+ * Useful for preventing tier skip but still considering amperage for parallel.
+ */
+ public P setAvailableAmperage(long amperage) {
+ availableAmperage = amperage;
+ return getThis();
+ }
+
+ public P setVoidProtection(boolean protectItems, boolean protectFluids) {
+ this.protectItems = protectItems;
+ this.protectFluids = protectFluids;
+ return getThis();
+ }
+
+ /**
+ * Sets custom overclock ratio. 2/4 by default.
+ * Parameters represent number of bit shift, so 1 -> 2x, 2 -> 4x.
+ */
+ public P setOverclock(int timeReduction, int powerIncrease) {
+ this.overClockTimeReduction = timeReduction;
+ this.overClockPowerIncrease = powerIncrease;
+ return getThis();
+ }
+
+ /**
+ * Sets overclock ratio to 4/4.
+ */
+ public P enablePerfectOverclock() {
+ return this.setOverclock(2, 2);
+ }
+
+ /**
+ * Sets whether the multi should use amperage to OC or not
+ */
+ public P setAmperageOC(boolean amperageOC) {
+ this.amperageOC = amperageOC;
+ return getThis();
+ }
+
+ /**
+ * Clears calculated results (and provided machine inputs) to prepare for the next machine operation.
+ */
+ public P clear() {
+ this.calculatedEut = 0;
+ this.duration = 0;
+ this.calculatedParallels = 0;
+ return getThis();
+ }
+
+ // #endregion
+
+ // #region Logic
+
+ /**
+ * Executes the recipe check: Find recipe from recipemap, Calculate parallel, overclock and outputs.
+ */
+ @Nonnull
+ public abstract CheckRecipeResult process();
+
+ /**
+ * Refreshes recipemap to use. Remember to call this before {@link #process} to make sure correct recipemap is used.
+ *
+ * @return Recipemap to use now
+ */
+ protected RecipeMap<?> preProcess() {
+ RecipeMap<?> recipeMap;
+ if (recipeMapSupplier == null) {
+ recipeMap = null;
+ } else {
+ recipeMap = recipeMapSupplier.get();
+ }
+ if (lastRecipeMap != recipeMap) {
+ lastRecipe = null;
+ lastRecipeMap = recipeMap;
+ }
+
+ if (maxParallelSupplier != null) {
+ maxParallel = maxParallelSupplier.get();
+ }
+
+ return recipeMap;
+ }
+
+ /**
+ * Check has been succeeded, so it applies the recipe and calculated parameters.
+ * At this point, inputs have been already consumed.
+ */
+ @Nonnull
+ protected CheckRecipeResult applyRecipe(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper,
+ @Nonnull GT_OverclockCalculator calculator, @Nonnull CheckRecipeResult result) {
+ if (recipe.mCanBeBuffered) {
+ lastRecipe = recipe;
+ } else {
+ lastRecipe = null;
+ }
+ calculatedParallels = helper.getCurrentParallel();
+
+ if (calculator.getConsumption() == Long.MAX_VALUE) {
+ return CheckRecipeResultRegistry.POWER_OVERFLOW;
+ }
+ if (calculator.getDuration() == Integer.MAX_VALUE) {
+ return CheckRecipeResultRegistry.DURATION_OVERFLOW;
+ }
+
+ calculatedEut = calculator.getConsumption();
+
+ double finalDuration = calculateDuration(recipe, helper, calculator);
+ if (finalDuration >= Integer.MAX_VALUE) {
+ return CheckRecipeResultRegistry.DURATION_OVERFLOW;
+ }
+ duration = (int) finalDuration;
+
+ CheckRecipeResult hookResult = onRecipeStart(recipe);
+ if (!hookResult.wasSuccessful()) {
+ return hookResult;
+ }
+
+ outputItems = helper.getItemOutputs();
+ outputFluids = helper.getFluidOutputs();
+
+ return result;
+ }
+
+ /**
+ * Override to tweak final duration that will be set as a result of this logic class.
+ */
+ protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper,
+ @Nonnull GT_OverclockCalculator calculator) {
+ return calculator.getDuration() * helper.getDurationMultiplierDouble();
+ }
+
+ /**
+ * Override to do additional check for found recipe if needed.
+ */
+ @Nonnull
+ protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) {
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ /**
+ * Override to perform additional logic when recipe starts.
+ *
+ * This is called when the recipe processing logic has finished all
+ * checks, consumed all inputs, but has not yet set the outputs to
+ * be produced. Returning a result other than SUCCESSFUL will void
+ * all inputs!
+ */
+ @Nonnull
+ protected CheckRecipeResult onRecipeStart(@Nonnull GT_Recipe recipe) {
+ return CheckRecipeResultRegistry.SUCCESSFUL;
+ }
+
+ /**
+ * Override to tweak overclock logic if needed.
+ */
+ @Nonnull
+ protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) {
+ return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt)
+ .setAmperage(availableAmperage)
+ .setEUt(availableVoltage)
+ .setDuration(recipe.mDuration)
+ .setSpeedBoost(speedBoost)
+ .setEUtDiscount(euModifier)
+ .setAmperageOC(amperageOC)
+ .setDurationDecreasePerOC(overClockTimeReduction)
+ .setEUtIncreasePerOC(overClockPowerIncrease);
+ }
+ // #endregion
+
+ // #region Getters
+
+ public ItemStack[] getOutputItems() {
+ return outputItems;
+ }
+
+ public FluidStack[] getOutputFluids() {
+ return outputFluids;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public long getCalculatedEut() {
+ return calculatedEut;
+ }
+
+ public int getCurrentParallels() {
+ return calculatedParallels;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ public P getThis() {
+ return (P) this;
+ }
+
+ // #endregion
+}
diff --git a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java
index 3c7974db9e..72a74ebd04 100644
--- a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java
+++ b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java
@@ -5,180 +5,117 @@ import java.util.stream.LongStream;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
-import gregtech.api.multitileentity.multiblock.base.Controller;
-import gregtech.api.recipe.RecipeMap;
-import gregtech.api.util.GT_OverclockCalculator;
-import gregtech.api.util.GT_ParallelHelper;
-import gregtech.api.util.GT_Recipe;
+public class ComplexParallelProcessingLogic<P extends ComplexParallelProcessingLogic<P>>
+ extends MuTEProcessingLogic<P> {
-public class ComplexParallelProcessingLogic {
+ protected int maxComplexParallels;
+ protected ItemStack[][] outputItems;
+ protected FluidStack[][] outputFluids;
+ protected long[] calculatedEutValues;
+ protected int[] durations;
+ protected int[] progresses;
- protected Controller<?> tileEntity;
- protected RecipeMap<?> recipeMap;
- protected boolean hasPerfectOverclock;
- protected final int maxComplexParallels;
- protected final ItemStack[][] outputItems;
- protected final ItemStack[][] inputItems;
- protected final FluidStack[][] inputFluids;
- protected final FluidStack[][] outputFluids;
- protected final long[] availableEut;
- protected final long[] eut;
- protected final long[] durations;
- protected final boolean[] isItemVoidProtected;
- protected final boolean[] isFluidVoidProtected;
-
- public ComplexParallelProcessingLogic(int maxComplexParallels) {
- this(null, maxComplexParallels);
- }
-
- public ComplexParallelProcessingLogic(RecipeMap<?> recipeMap, int maxComplexParallels) {
+ public P setMaxComplexParallel(int maxComplexParallels) {
this.maxComplexParallels = maxComplexParallels;
- this.recipeMap = recipeMap;
- inputItems = new ItemStack[maxComplexParallels][];
- outputItems = new ItemStack[maxComplexParallels][];
- inputFluids = new FluidStack[maxComplexParallels][];
- outputFluids = new FluidStack[maxComplexParallels][];
- eut = new long[maxComplexParallels];
- availableEut = new long[maxComplexParallels];
- durations = new long[maxComplexParallels];
- isItemVoidProtected = new boolean[maxComplexParallels];
- isFluidVoidProtected = new boolean[maxComplexParallels];
- }
-
- public ComplexParallelProcessingLogic setRecipeMap(RecipeMap<?> recipeMap) {
- this.recipeMap = recipeMap;
- return this;
+ reinitializeProcessingArrays();
+ return getThis();
}
- public ComplexParallelProcessingLogic setInputItems(int index, ItemStack... itemInputs) {
+ public ItemStack[] getOutputItems(int index) {
if (index >= 0 && index < maxComplexParallels) {
- inputItems[index] = itemInputs;
+ return outputItems[index];
}
- return this;
+ return null;
}
- public ComplexParallelProcessingLogic setInputFluids(int index, FluidStack... inputFluids) {
+ public FluidStack[] getOutputFluids(int index) {
if (index >= 0 && index < maxComplexParallels) {
- this.inputFluids[index] = inputFluids;
+ return outputFluids[index];
}
- return this;
+ return null;
}
- public ComplexParallelProcessingLogic setTileEntity(Controller<?> tileEntity) {
- this.tileEntity = tileEntity;
- return this;
+ @Override
+ public boolean canWork() {
+ for (int i = 0; i < maxComplexParallels; i++) {
+ if (progresses[i] >= durations[i]) {
+ return machineHost.isAllowedToWork();
+ }
+ }
+ return false;
}
- public ComplexParallelProcessingLogic setEut(int index, long eut) {
- if (index >= 0 && index < maxComplexParallels) {
- availableEut[index] = eut;
- }
- return this;
+ @Override
+ public long getCalculatedEut() {
+ return LongStream.of(this.calculatedEutValues)
+ .sum();
}
- public ComplexParallelProcessingLogic setVoidProtection(int index, boolean protectItem, boolean protectFluid) {
- if (index >= 0 && index < maxComplexParallels) {
- isItemVoidProtected[index] = protectItem;
- isFluidVoidProtected[index] = protectFluid;
- }
- return this;
+ public int getDuration(int index) {
+ return durations[index];
}
- public ComplexParallelProcessingLogic setPerfectOverclock(boolean shouldOverclockPerfectly) {
- this.hasPerfectOverclock = shouldOverclockPerfectly;
- return this;
+ public int getProgress(int index) {
+ return progresses[index];
}
- public ComplexParallelProcessingLogic clear() {
+ @Override
+ public void progress() {
for (int i = 0; i < maxComplexParallels; i++) {
- outputItems[i] = null;
- outputFluids[i] = null;
- durations[i] = 0;
- eut[i] = 0;
+ if (progresses[i] == durations[i]) {
+ progresses[i] = 0;
+ durations[i] = 0;
+ output(i);
+ continue;
+ }
+ progresses[i] = progresses[i] + 1;
}
- return this;
}
- public ComplexParallelProcessingLogic clear(int index) {
- if (index >= 0 && index < maxComplexParallels) {
- inputItems[index] = null;
- inputFluids[index] = null;
- outputItems[index] = null;
- outputFluids[index] = null;
- durations[index] = 0;
- availableEut[index] = 0;
- eut[index] = 0;
+ @Override
+ public void startCheck() {
+ for (int i = 0; i < maxComplexParallels; i++) {
+ if (durations[i] > 0) continue;
+ recipeResult = process();
+ calculatedEutValues[i] = calculatedEut;
+ durations[i] = duration;
+ progresses[i] = 0;
+ outputItems[i] = getOutputItems();
+ outputFluids[i] = getOutputFluids();
}
- return this;
}
- public boolean process(int index) {
- if (recipeMap == null) {
- return false;
- }
- GT_Recipe recipe = recipeMap
- .findRecipe(tileEntity, false, false, availableEut[index], inputFluids[index], inputItems[index]);
- if (recipe == null) {
- return false;
- }
-
- GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(recipe)
- .setItemInputs(inputItems[index])
- .setFluidInputs(inputFluids[index])
- .setAvailableEUt(availableEut[index])
- .setMachine(tileEntity, isItemVoidProtected[index], isFluidVoidProtected[index])
- .setConsumption(true)
- .setOutputCalculation(true);
-
- helper.build();
-
- if (helper.getCurrentParallel() <= 0) {
- return false;
- }
-
- GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt)
- .setDuration(recipe.mDuration)
- .setEUt(availableEut[index]);
+ protected void output(int index) {
+ setOutputItems(getOutputItems(index));
+ setOutputFluids(getOutputFluids(index));
+ output();
+ }
- if (hasPerfectOverclock) {
- calculator.enablePerfectOC();
+ protected void reinitializeProcessingArrays() {
+ ItemStack[][] oldOutputItems = outputItems;
+ FluidStack[][] oldOutputFluids = outputFluids;
+ long[] oldCalculatedEutValues = calculatedEutValues;
+ int[] oldDurations = durations;
+ int[] oldProgresses = progresses;
+ outputItems = new ItemStack[maxComplexParallels][];
+ outputFluids = new FluidStack[maxComplexParallels][];
+ calculatedEutValues = new long[maxComplexParallels];
+ durations = new int[maxComplexParallels];
+ progresses = new int[maxComplexParallels];
+ for (int i = 0; i < oldOutputItems.length; i++) {
+ outputItems[i] = oldOutputItems[i];
}
-
- if (calculator.getConsumption() == Long.MAX_VALUE - 1 || calculator.getDuration() == Integer.MAX_VALUE - 1) {
- return false;
+ for (int i = 0; i < oldOutputFluids.length; i++) {
+ outputFluids[i] = oldOutputFluids[i];
}
-
- durations[index] = calculator.getDuration();
- eut[index] = calculator.getConsumption();
- outputItems[index] = helper.getItemOutputs();
- outputFluids[index] = helper.getFluidOutputs();
-
- return true;
- }
-
- public long getDuration(int index) {
- if (index >= 0 && index < maxComplexParallels) {
- return durations[index];
+ for (int i = 0; i < oldCalculatedEutValues.length; i++) {
+ calculatedEutValues[i] = oldCalculatedEutValues[i];
}
- return 0;
- }
-
- public long getTotalEU() {
- return LongStream.of(eut)
- .sum();
- }
-
- public ItemStack[] getOutputItems(int index) {
- if (index >= 0 && index < maxComplexParallels) {
- return outputItems[index];
+ for (int i = 0; i < oldDurations[i]; i++) {
+ durations[i] = oldDurations[i];
}
- return null;
- }
-
- public FluidStack[] getOutputFluids(int index) {
- if (index >= 0 && index < maxComplexParallels) {
- return outputFluids[index];
+ for (int i = 0; i < oldProgresses.length; i++) {
+ progresses[i] = oldProgresses[i];
}
- return null;
}
}
diff --git a/src/main/java/gregtech/api/logic/ControllerFluidLogic.java b/src/main/java/gregtech/api/logic/ControllerFluidLogic.java
new file mode 100644
index 0000000000..211c1c2982
--- /dev/null
+++ b/src/main/java/gregtech/api/logic/ControllerFluidLogic.java
@@ -0,0 +1,152 @@
+package gregtech.api.logic;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraftforge.common.util.Constants;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Controller logic for Fluid inventories
+ *
+ * @author BlueWeabo
+ */
+public class ControllerFluidLogic {
+
+ private final Map<UUID, FluidInventoryLogic> inventories = new HashMap<>();
+ private final Set<Pair<UUID, FluidInventoryLogic>> unallocatedInventories = new HashSet<>();
+
+ public void addInventory(@Nonnull UUID id, @Nonnull FluidInventoryLogic inventory) {
+ Pair<UUID, FluidInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory);
+ if (inventory.isUpgradeInventory() && found != null) {
+ unallocatedInventories.remove(found);
+ inventories.put(id, found.getRight());
+ return;
+ }
+ inventories.put(id, inventory);
+ }
+
+ @Nonnull
+ public UUID addInventory(@Nonnull FluidInventoryLogic inventory) {
+ Pair<UUID, FluidInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory);
+ if (inventory.isUpgradeInventory() && found != null) {
+ unallocatedInventories.remove(found);
+ inventories.put(found.getLeft(), found.getRight());
+ return Objects.requireNonNull(found.getLeft());
+ }
+ UUID generatedUUID = Objects.requireNonNull(UUID.randomUUID());
+ inventories.put(generatedUUID, inventory);
+ return generatedUUID;
+ }
+
+ @Nullable
+ private Pair<UUID, FluidInventoryLogic> checkIfInventoryExistsAsUnallocated(
+ @Nonnull FluidInventoryLogic inventory) {
+ if (unallocatedInventories.size() == 0) {
+ return null;
+ }
+ return unallocatedInventories.stream()
+ .filter(
+ unallocated -> unallocated.getRight()
+ .getTier() == inventory.getTier())
+ .findFirst()
+ .get();
+ }
+
+ /**
+ * Removes the inventory with said id and gives it back to be processed if needed.
+ */
+ @Nonnull
+ public FluidInventoryLogic removeInventory(@Nonnull UUID id) {
+ return Objects.requireNonNull(inventories.remove(id));
+ }
+
+ @Nonnull
+ public FluidInventoryLogic getAllInventoryLogics() {
+ return new FluidInventoryLogic(
+ inventories.values()
+ .stream()
+ .map(inv -> inv.getInventory())
+ .collect(Collectors.toList()));
+ }
+
+ @Nonnull
+ public FluidInventoryLogic getInventoryLogic(@Nullable UUID id) {
+ if (id == null) return getAllInventoryLogics();
+ return Objects.requireNonNull(inventories.getOrDefault(id, getAllInventoryLogics()));
+ }
+
+ @Nonnull
+ public Set<Entry<UUID, FluidInventoryLogic>> getAllInventoryLogicsAsEntrySet() {
+ return Objects.requireNonNull(inventories.entrySet());
+ }
+
+ @Nonnull
+ public String getInventoryDisplayName(@Nullable UUID id) {
+ if (id == null) return "";
+ FluidInventoryLogic logic = inventories.get(id);
+ if (logic == null) return "";
+ String displayName = logic.getDisplayName();
+ if (displayName == null) return Objects.requireNonNull(id.toString());
+ return displayName;
+ }
+
+ public void setInventoryDisplayName(@Nullable UUID id, @Nullable String displayName) {
+ if (id == null) return;
+ FluidInventoryLogic logic = inventories.get(id);
+ if (logic == null) return;
+ logic.setDisplayName(displayName);
+ }
+
+ @Nonnull
+ public NBTTagCompound saveToNBT() {
+ NBTTagCompound nbt = new NBTTagCompound();
+ NBTTagList inventoriesNBT = new NBTTagList();
+ inventories.forEach((uuid, inventory) -> {
+ NBTTagCompound inventoryNBT = new NBTTagCompound();
+ inventoryNBT.setTag("inventory", inventory.saveToNBT());
+ inventoryNBT.setString("uuid", uuid.toString());
+ inventoryNBT.setInteger(
+ "invSize",
+ inventory.getInventory()
+ .getTanks());
+ inventoryNBT.setLong(
+ "tankCapacity",
+ inventory.getInventory()
+ .getTankCapacity(0));
+ inventoriesNBT.appendTag(inventoryNBT);
+ });
+ nbt.setTag("inventories", inventoriesNBT);
+ return nbt;
+ }
+
+ public void loadFromNBT(@Nonnull NBTTagCompound nbt) {
+ NBTTagList inventoriesNBT = nbt.getTagList("inventories", Constants.NBT.TAG_COMPOUND);
+ if (inventoriesNBT == null) return;
+ for (int i = 0; i < inventoriesNBT.tagCount(); i++) {
+ NBTTagCompound inventoryNBT = inventoriesNBT.getCompoundTagAt(i);
+ UUID uuid = UUID.fromString(inventoryNBT.getString("uuid"));
+ FluidInventoryLogic inventory = new FluidInventoryLogic(
+ inventoryNBT.getInteger("invSize"),
+ inventoryNBT.getLong("tankCapacity"));
+ inventory.loadFromNBT(inventoryNBT.getCompoundTag("inventory"));
+ if (inventory.isUpgradeInventory()) {
+ unallocatedInventories.add(Pair.of(uuid, inventory));
+ } else {
+ inventories.put(uuid, inventory);
+ }
+ }
+ }
+}
diff --git a/src/main/java/gregtech/api/logic/ControllerItemLogic.java b/src/main/java/gregtech/api/logic/ControllerItemLogic.java
new file mode 100644
index 0000000000..2863c2f49c
--- /dev/null
+++ b/src/main/java/gregtech/api/logic/ControllerItemLogic.java
@@ -0,0 +1,148 @@
+package gregtech.api.logic;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraftforge.common.util.Constants;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Logic of the Item logic for the controller. This is controlling all of the inventories.
+ *
+ * @author BlueWeabo
+ */
+public class ControllerItemLogic {
+
+ private final Map<UUID, ItemInventoryLogic> inventories = new HashMap<>();
+ private final Set<Pair<UUID, ItemInventoryLogic>> unallocatedInventories = new HashSet<>();
+
+ public void addInventory(@Nonnull UUID id, @Nonnull ItemInventoryLogic inventory) {
+ Pair<UUID, ItemInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory);
+ if (inventory.isUpgradeInventory() && found != null) {
+ unallocatedInventories.remove(found);
+ inventories.put(id, found.getRight());
+ return;
+ }
+ inventories.put(id, inventory);
+ }
+
+ @Nonnull
+ public UUID addInventory(@Nonnull ItemInventoryLogic inventory) {
+ Pair<UUID, ItemInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory);
+ if (inventory.isUpgradeInventory() && found != null) {
+ unallocatedInventories.remove(found);
+ inventories.put(found.getLeft(), found.getRight());
+ return Objects.requireNonNull(found.getLeft());
+ }
+ UUID generatedUUID = Objects.requireNonNull(UUID.randomUUID());
+ inventories.put(generatedUUID, inventory);
+ return generatedUUID;
+ }
+
+ @Nullable
+ private Pair<UUID, ItemInventoryLogic> checkIfInventoryExistsAsUnallocated(@Nonnull ItemInventoryLogic inventory) {
+ if (unallocatedInventories.size() == 0) {
+ return null;
+ }
+ return unallocatedInventories.stream()
+ .filter(
+ unallocated -> unallocated.getRight()
+ .getTier() == inventory.getTier()
+ && unallocated.getRight()
+ .getSlots() == inventory.getSlots())
+ .findFirst()
+ .get();
+ }
+
+ /**
+ * Removes the inventory with said id and gives it back to be processed if needed.
+ */
+ @Nonnull
+ public ItemInventoryLogic removeInventory(@Nonnull UUID id) {
+ return Objects.requireNonNull(inventories.remove(id));
+ }
+
+ @Nonnull
+ public ItemInventoryLogic getAllInventoryLogics() {
+ return new ItemInventoryLogic(
+ inventories.values()
+ .stream()
+ .map(inv -> inv.getInventory())
+ .collect(Collectors.toList()));
+ }
+
+ @Nonnull
+ public ItemInventoryLogic getInventoryLogic(@Nullable UUID id) {
+ if (id == null) return getAllInventoryLogics();
+ return Objects.requireNonNull(inventories.getOrDefault(id, getAllInventoryLogics()));
+ }
+
+ @Nonnull
+ public Set<Entry<UUID, ItemInventoryLogic>> getAllInventoryLogicsAsEntrySet() {
+ return Objects.requireNonNull(inventories.entrySet());
+ }
+
+ @Nullable
+ public String getInventoryDisplayName(@Nullable UUID id) {
+ if (id == null) return "";
+ ItemInventoryLogic logic = inventories.get(id);
+ if (logic == null) return "";
+ String displayName = logic.getDisplayName();
+ if (displayName == null) return Objects.requireNonNull(id.toString());
+ return displayName;
+ }
+
+ public void setInventoryDisplayName(@Nullable UUID id, @Nullable String displayName) {
+ if (id == null) return;
+ ItemInventoryLogic logic = inventories.get(id);
+ if (logic == null) return;
+ logic.setDisplayName(displayName);
+ }
+
+ @Nonnull
+ public NBTTagCompound saveToNBT() {
+ NBTTagCompound nbt = new NBTTagCompound();
+ NBTTagList inventoriesNBT = new NBTTagList();
+ inventories.forEach((uuid, inventory) -> {
+ NBTTagCompound inventoryNBT = new NBTTagCompound();
+ inventoryNBT.setTag("inventory", inventory.saveToNBT());
+ inventoryNBT.setString("uuid", uuid.toString());
+ inventoryNBT.setInteger(
+ "