diff options
Diffstat (limited to 'src/main/java/gregtech/api/logic')
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( + " |
