diff options
Diffstat (limited to 'src/main/java/gregtech/api/util/GT_ParallelHelper.java')
-rw-r--r-- | src/main/java/gregtech/api/util/GT_ParallelHelper.java | 713 |
1 files changed, 0 insertions, 713 deletions
diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java deleted file mode 100644 index 157488a8ca..0000000000 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ /dev/null @@ -1,713 +0,0 @@ -package gregtech.api.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Objects; -import java.util.Random; -import java.util.function.Function; - -import javax.annotation.Nonnull; - -import net.minecraft.item.ItemStack; -import net.minecraftforge.fluids.FluidStack; - -import gregtech.api.interfaces.tileentity.IRecipeLockable; -import gregtech.api.interfaces.tileentity.IVoidable; -import gregtech.api.logic.FluidInventoryLogic; -import gregtech.api.logic.ItemInventoryLogic; -import gregtech.api.objects.XSTR; -import gregtech.api.recipe.RecipeMap; -import gregtech.api.recipe.check.CheckRecipeResult; -import gregtech.api.recipe.check.CheckRecipeResultRegistry; -import gregtech.api.recipe.check.SingleRecipeCheck; - -@SuppressWarnings({ "unused", "UnusedReturnValue" }) -public class GT_ParallelHelper { - - private static final double MAX_BATCH_MODE_TICK_TIME = 128; - /** - * Machine used for calculation - */ - private IVoidable machine; - /** - * Machine used for single recipe locking calculation - */ - private IRecipeLockable singleRecipeMachine; - /** - * Is locked to a single recipe? - */ - private boolean isRecipeLocked; - /** - * Recipe used when trying to calculate parallels - */ - private GT_Recipe recipe; - /** - * EUt available to the multiblock (This should be the total eut available) - */ - private long availableEUt; - /** - * The current parallel possible for the multiblock - */ - private int currentParallel = 0; - /** - * The maximum possible parallel possible for the multiblock - */ - private int maxParallel = 1; - /** - * The Batch Modifier applied when batch mode is enabled. 1 does nothing. 2 doubles max possible - * parallel, but also duration - */ - private int batchModifier = 1; - /** - * The inputs of the multiblock for the current recipe check - */ - private ItemStack[] itemInputs; - /** - * The inputs of the machine for current recipe check - */ - private ItemInventoryLogic itemInputInventory; - /** - * The output item inventory of the machine - */ - private ItemInventoryLogic itemOutputInventory; - /** - * The outputs of the recipe with the applied parallel - */ - private ItemStack[] itemOutputs; - /** - * The inputs of the multiblock for the current recipe check - */ - private FluidStack[] fluidInputs; - /** - * The inputs of the machine for the current recipe check - */ - private FluidInventoryLogic fluidInputInventory; - /** - * The output fluid inventory of the machine; - */ - private FluidInventoryLogic fluidOutputInventory; - /** - * The outputs of the recipe with the applied parallel - */ - private FluidStack[] fluidOutputs; - /** - * Does the multi have void protection enabled for items - */ - private boolean protectExcessItem; - /** - * Does the multi have void protection enabled for fluids - */ - private boolean protectExcessFluid; - /** - * Should the Parallel Helper automatically consume for the multi - */ - private boolean consume; - /** - * Is batch mode turned on? - */ - private boolean batchMode; - /** - * Should the Parallel Helper automatically calculate the outputs of the recipe with current parallel? - */ - private boolean calculateOutputs; - /** - * Has the Parallel Helper been built? - */ - private boolean built; - /** - * What is the duration multiplier with batch mode enabled - */ - private double durationMultiplier; - /** - * Modifier which is applied on the recipe eut. Useful for GT++ machines - */ - private float eutModifier = 1; - /** - * Multiplier that is applied on the output chances - */ - private double chanceMultiplier = 1; - /** - * Multiplier by which the output will be multiplied - */ - private int outputMultiplier = 1; - /** - * Method for calculating max parallel from given inputs. - */ - private MaxParallelCalculator maxParallelCalculator = GT_Recipe::maxParallelCalculatedByInputs; - /** - * Method for consuming inputs after determining how many parallels it can execute. - */ - private InputConsumer inputConsumer = GT_Recipe::consumeInput; - - /** - * Calculator to use for overclocking - */ - private GT_OverclockCalculator calculator; - @Nonnull - private CheckRecipeResult result = CheckRecipeResultRegistry.NONE; - - private Function<Integer, ItemStack[]> customItemOutputCalculation; - - private Function<Integer, FluidStack[]> customFluidOutputCalculation; - - /** - * MuTE Mode this is a mode for changing how the GT_ParallelHelper works as Mutes don't use ItemStack and FluidStack - * arrays for inputs - */ - private boolean muteMode = false; - - public GT_ParallelHelper() {} - - /** - * Sets machine, with current configuration for void protection mode. - */ - @Nonnull - public GT_ParallelHelper setMachine(IVoidable machine) { - return setMachine(machine, machine.protectsExcessItem(), machine.protectsExcessFluid()); - } - - /** - * Sets machine, with void protection mode forcibly. - */ - @Nonnull - public GT_ParallelHelper setMachine(IVoidable machine, boolean protectExcessItem, boolean protectExcessFluid) { - this.protectExcessItem = protectExcessItem; - this.protectExcessFluid = protectExcessFluid; - this.machine = machine; - return this; - } - - /** - * Sets the recipe, which will be used for the parallel calculation - */ - @Nonnull - public GT_ParallelHelper setRecipe(@Nonnull GT_Recipe aRecipe) { - recipe = Objects.requireNonNull(aRecipe); - return this; - } - - @Nonnull - public GT_ParallelHelper setRecipeLocked(IRecipeLockable singleRecipeMachine, boolean isRecipeLocked) { - this.singleRecipeMachine = singleRecipeMachine; - this.isRecipeLocked = isRecipeLocked; - return this; - } - - /** - * Sets the items available for the recipe check - */ - @Nonnull - public GT_ParallelHelper setItemInputs(ItemStack... aItemInputs) { - this.itemInputs = aItemInputs; - return this; - } - - /** - * Sets the fluid inputs available for the recipe check - */ - @Nonnull - public GT_ParallelHelper setFluidInputs(FluidStack... aFluidInputs) { - this.fluidInputs = aFluidInputs; - return this; - } - - /** - * Sets the available eut when trying for more parallels - */ - @Nonnull - public GT_ParallelHelper setAvailableEUt(long aAvailableEUt) { - this.availableEUt = aAvailableEUt; - return this; - } - - /** - * Sets the modifier for recipe eut. 1 does nothing 0.9 is 10% less. 1.1 is 10% more - */ - @Nonnull - public GT_ParallelHelper setEUtModifier(float aEUtModifier) { - this.eutModifier = aEUtModifier; - return this; - } - - /** - * Sets the multiplier that is applied on output chances. 1 does nothing. 0.9 is 10% less. 1.1 is 10% more. - * Only useful for item outputs for sure. - */ - @Nonnull - public GT_ParallelHelper setChanceMultiplier(double chanceMultiplier) { - this.chanceMultiplier = chanceMultiplier; - return this; - } - - /** - * Sets the item/fluid output multiplier. 1 does nothing. 2 doubles the item and fluid outputs. - */ - @Nonnull - public GT_ParallelHelper setOutputMultiplier(int outputMultiplier) { - this.outputMultiplier = outputMultiplier; - return this; - } - - @Nonnull - public GT_ParallelHelper setCalculator(GT_OverclockCalculator calculator) { - this.calculator = calculator; - return this; - } - - /** - * Set if we should consume inputs or not when trying for parallels - * - * @param consume Should we consume inputs - */ - @Nonnull - public GT_ParallelHelper setConsumption(boolean consume) { - this.consume = consume; - return this; - } - - /** - * Sets the MaxParallel a multi can handle - */ - @Nonnull - public GT_ParallelHelper setMaxParallel(int maxParallel) { - this.maxParallel = maxParallel; - return this; - } - - /** - * Enables Batch mode. Can do up to an additional processed recipes of mCurrentParallel * mBatchModifier A batch - * modifier of 1 does nothing - */ - @Nonnull - public GT_ParallelHelper enableBatchMode(int batchModifier) { - this.batchMode = batchModifier > 1; - this.batchModifier = batchModifier; - return this; - } - - /** - * Sets if we should calculate outputs with the parallels we found or not - * - * @param calculateOutputs Should we calculate outputs with the helper or not - */ - @Nonnull - public GT_ParallelHelper setOutputCalculation(boolean calculateOutputs) { - this.calculateOutputs = calculateOutputs; - return this; - } - - /** - * Set a custom way to calculate item outputs. You are given the amount of parallels and must return an ItemStack - * array - */ - @Nonnull - public GT_ParallelHelper setCustomItemOutputCalculation(Function<Integer, ItemStack[]> custom) { - customItemOutputCalculation = custom; - return this; - } - - /** - * Set a custom way to calculate item outputs. You are given the amount of parallels and must return a FluidStack - * array - */ - @Nonnull - public GT_ParallelHelper setCustomFluidOutputCalculation(Function<Integer, FluidStack[]> custom) { - customFluidOutputCalculation = custom; - return this; - } - - @Nonnull - public GT_ParallelHelper setMuTEMode(boolean muteMode) { - this.muteMode = muteMode; - return this; - } - - @Nonnull - public GT_ParallelHelper setItemInputInventory(ItemInventoryLogic itemInputInventory) { - this.itemInputInventory = itemInputInventory; - return this; - } - - @Nonnull - public GT_ParallelHelper setFluidInputInventory(FluidInventoryLogic fluidInputInventory) { - this.fluidInputInventory = fluidInputInventory; - return this; - } - - /** - * Sets method for calculating max parallel from given inputs. - */ - public GT_ParallelHelper setMaxParallelCalculator(MaxParallelCalculator maxParallelCalculator) { - this.maxParallelCalculator = maxParallelCalculator; - return this; - } - - /** - * Sets method for consuming inputs after determining how many parallels it can execute. - */ - public GT_ParallelHelper setInputConsumer(InputConsumer inputConsumer) { - this.inputConsumer = inputConsumer; - return this; - } - - @Nonnull - public GT_ParallelHelper setItemOutputInventory(ItemInventoryLogic itemOutputInventory) { - this.itemOutputInventory = itemOutputInventory; - return this; - } - - @Nonnull - public GT_ParallelHelper setFluidOutputInventory(FluidInventoryLogic fluidOutputInventory) { - this.fluidOutputInventory = fluidOutputInventory; - return this; - } - - /** - * Finishes the GT_ParallelHelper. Anything changed after this will not effect anything - */ - @Nonnull - public GT_ParallelHelper build() { - if (built) { - throw new IllegalStateException("Tried to build twice"); - } - if (recipe == null) { - throw new IllegalStateException("Recipe is not set"); - } - built = true; - determineParallel(); - return this; - } - - /** - * @return The current parallels possible by the multiblock - */ - public int getCurrentParallel() { - if (!built) { - throw new IllegalStateException("Tried to get parallels before building"); - } - return currentParallel; - } - - /** - * @return The duration multiplier if batch mode was enabled for the multiblock - */ - public double getDurationMultiplierDouble() { - if (!built) { - throw new IllegalStateException("Tried to get duration multiplier before building"); - } - if (batchMode && durationMultiplier > 0) { - return durationMultiplier; - } - return 1; - } - - /** - * @return The ItemOutputs from the recipe - */ - @Nonnull - public ItemStack[] getItemOutputs() { - if (!built || !calculateOutputs) { - throw new IllegalStateException( - "Tried to get item outputs before building or without enabling calculation of outputs"); - } - return itemOutputs; - } - - /** - * @return The FluidOutputs from the recipe - */ - @Nonnull - public FluidStack[] getFluidOutputs() { - if (!built || !calculateOutputs) { - throw new IllegalStateException( - "Tried to get fluid outputs before building or without enabling calculation of outputs"); - } - return fluidOutputs; - } - - /** - * @return The result of why a recipe could've failed or succeeded - */ - @Nonnull - public CheckRecipeResult getResult() { - if (!built) { - throw new IllegalStateException("Tried to get recipe result before building"); - } - return result; - } - - /** - * Called by build(). Determines the parallels and everything else that needs to be done at build time - */ - protected void determineParallel() { - if (maxParallel <= 0) { - return; - } - if (itemInputs == null) { - itemInputs = new ItemStack[0]; - } - if (fluidInputs == null) { - fluidInputs = new FluidStack[0]; - } - - if (!consume) { - copyInputs(); - } - - if (calculator == null) { - calculator = new GT_OverclockCalculator().setEUt(availableEUt) - .setRecipeEUt(recipe.mEUt) - .setDuration(recipe.mDuration) - .setEUtDiscount(eutModifier); - } - - final int tRecipeEUt = (int) Math.ceil(recipe.mEUt * eutModifier); - if (availableEUt < tRecipeEUt) { - result = CheckRecipeResultRegistry.insufficientPower(tRecipeEUt); - return; - } - - // Save the original max parallel before calculating our overclocking under 1 tick - int originalMaxParallel = maxParallel; - calculator.setParallel(originalMaxParallel); - double tickTimeAfterOC = calculator.calculateDurationUnderOneTick(); - if (tickTimeAfterOC < 1) { - maxParallel = GT_Utility.safeInt((long) (maxParallel / tickTimeAfterOC), 0); - } - - int maxParallelBeforeBatchMode = maxParallel; - if (batchMode) { - maxParallel = GT_Utility.safeInt((long) maxParallel * batchModifier, 0); - } - - final ItemStack[] truncatedItemOutputs = recipe.mOutputs != null - ? Arrays.copyOfRange(recipe.mOutputs, 0, Math.min(machine.getItemOutputLimit(), recipe.mOutputs.length)) - : new ItemStack[0]; - final FluidStack[] truncatedFluidOutputs = recipe.mFluidOutputs != null ? Arrays - .copyOfRange(recipe.mFluidOutputs, 0, Math.min(machine.getFluidOutputLimit(), recipe.mFluidOutputs.length)) - : new FluidStack[0]; - - SingleRecipeCheck recipeCheck = null; - SingleRecipeCheck.Builder tSingleRecipeCheckBuilder = null; - if (isRecipeLocked && singleRecipeMachine != null) { - recipeCheck = singleRecipeMachine.getSingleRecipeCheck(); - if (recipeCheck == null) { - // Machine is configured to lock to a single recipe, but haven't built the recipe checker yet. - // Build the checker on next successful recipe. - RecipeMap<?> recipeMap = singleRecipeMachine.getRecipeMap(); - if (recipeMap != null) { - tSingleRecipeCheckBuilder = SingleRecipeCheck.builder(recipeMap) - .setBefore(itemInputs, fluidInputs); - } - } - } - - // Let's look at how many parallels we can get with void protection - if (protectExcessItem || protectExcessFluid) { - if (machine == null && !muteMode) { - throw new IllegalStateException("Tried to calculate void protection, but machine is not set"); - } - VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper(); - voidProtectionHelper.setMachine(machine) - .setItemOutputs(truncatedItemOutputs) - .setFluidOutputs(truncatedFluidOutputs) - .setChangeGetter(recipe::getOutputChance) - .setOutputMultiplier(outputMultiplier) - .setChanceMultiplier(chanceMultiplier) - .setMaxParallel(maxParallel) - .setItemOutputInventory(itemOutputInventory) - .setFluidOutputInventory(fluidOutputInventory) - .setMuTEMode(muteMode) - .build(); - maxParallel = Math.min(voidProtectionHelper.getMaxParallel(), maxParallel); - if (voidProtectionHelper.isItemFull()) { - result = CheckRecipeResultRegistry.ITEM_OUTPUT_FULL; - return; - } - if (voidProtectionHelper.isFluidFull()) { - result = CheckRecipeResultRegistry.FLUID_OUTPUT_FULL; - return; - } - } - - maxParallelBeforeBatchMode = Math.min(maxParallel, maxParallelBeforeBatchMode); - - // determine normal parallel - int actualMaxParallel = tRecipeEUt > 0 ? (int) Math.min(maxParallelBeforeBatchMode, availableEUt / tRecipeEUt) - : maxParallelBeforeBatchMode; - if (recipeCheck != null) { - currentParallel = recipeCheck.checkRecipeInputs(true, actualMaxParallel, itemInputs, fluidInputs); - } else { - currentParallel = (int) maxParallelCalculator.calculate(recipe, actualMaxParallel, fluidInputs, itemInputs); - if (currentParallel > 0) { - if (tSingleRecipeCheckBuilder != null) { - // If recipe checker is not built yet, build and set it - inputConsumer.consume(recipe, 1, fluidInputs, itemInputs); - SingleRecipeCheck builtCheck = tSingleRecipeCheckBuilder.setAfter(itemInputs, fluidInputs) - .setRecipe(recipe) - .build(); - singleRecipeMachine.setSingleRecipeCheck(builtCheck); - inputConsumer.consume(recipe, currentParallel - 1, fluidInputs, itemInputs); - } else { - inputConsumer.consume(recipe, currentParallel, fluidInputs, itemInputs); - } - } - } - - if (currentParallel <= 0) { - result = CheckRecipeResultRegistry.INTERNAL_ERROR; - return; - } - - calculator.setCurrentParallel(currentParallel) - .calculate(); - // If Batch Mode is enabled determine how many extra parallels we can get - if (batchMode && currentParallel > 0 && calculator.getDuration() < MAX_BATCH_MODE_TICK_TIME) { - int tExtraParallels; - double batchMultiplierMax = MAX_BATCH_MODE_TICK_TIME / calculator.getDuration(); - final int maxExtraParallels = (int) Math.floor( - Math.min( - currentParallel * Math.min(batchMultiplierMax - 1, batchModifier - 1), - maxParallel - currentParallel)); - if (recipeCheck != null) { - tExtraParallels = recipeCheck.checkRecipeInputs(true, maxExtraParallels, itemInputs, fluidInputs); - } else { - tExtraParallels = (int) maxParallelCalculator - .calculate(recipe, maxExtraParallels, fluidInputs, itemInputs); - inputConsumer.consume(recipe, tExtraParallels, fluidInputs, itemInputs); - } - durationMultiplier = 1.0f + (float) tExtraParallels / currentParallel; - currentParallel += tExtraParallels; - } - - // If we want to calculate outputs we do it here - if (calculateOutputs && currentParallel > 0) { - calculateItemOutputs(truncatedItemOutputs); - calculateFluidOutputs(truncatedFluidOutputs); - } - result = CheckRecipeResultRegistry.SUCCESSFUL; - } - - protected void copyInputs() { - ItemStack[] itemInputsToUse; - FluidStack[] fluidInputsToUse; - itemInputsToUse = new ItemStack[itemInputs.length]; - for (int i = 0; i < itemInputs.length; i++) { - itemInputsToUse[i] = itemInputs[i].copy(); - } - fluidInputsToUse = new FluidStack[fluidInputs.length]; - for (int i = 0; i < fluidInputs.length; i++) { - fluidInputsToUse[i] = fluidInputs[i].copy(); - } - itemInputs = itemInputsToUse; - fluidInputs = fluidInputsToUse; - } - - private void calculateItemOutputs(ItemStack[] truncatedItemOutputs) { - if (customItemOutputCalculation != null) { - itemOutputs = customItemOutputCalculation.apply(currentParallel); - return; - } - if (truncatedItemOutputs.length == 0) return; - ArrayList<ItemStack> itemOutputsList = new ArrayList<>(); - for (int i = 0; i < truncatedItemOutputs.length; i++) { - if (recipe.getOutput(i) == null) continue; - ItemStack origin = recipe.getOutput(i) - .copy(); - final long itemStackSize = origin.stackSize; - double chancedOutputMultiplier = calculateChancedOutputMultiplier( - (int) (recipe.getOutputChance(i) * chanceMultiplier), - currentParallel); - long items = (long) Math.ceil(itemStackSize * chancedOutputMultiplier * outputMultiplier); - addItemsLong(itemOutputsList, origin, items); - } - itemOutputs = itemOutputsList.toArray(new ItemStack[0]); - } - - private void calculateFluidOutputs(FluidStack[] truncatedFluidOutputs) { - if (customFluidOutputCalculation != null) { - fluidOutputs = customFluidOutputCalculation.apply(currentParallel); - return; - } - if (truncatedFluidOutputs.length == 0) return; - ArrayList<FluidStack> fluidOutputsList = new ArrayList<>(); - for (int i = 0; i < truncatedFluidOutputs.length; i++) { - if (recipe.getFluidOutput(i) == null) continue; - FluidStack origin = recipe.getFluidOutput(i) - .copy(); - long fluids = (long) this.outputMultiplier * origin.amount * currentParallel; - - addFluidsLong(fluidOutputsList, origin, fluids); - } - fluidOutputs = fluidOutputsList.toArray(new FluidStack[0]); - } - - private static final Random rand = new Random(); - - public static double calculateChancedOutputMultiplier(int chanceInt, int parallel) { - // Multiply the integer part of the chance directly with parallel - double multiplier = Math.floorDiv(chanceInt, 10000) * parallel; - int transformedChanceInt = chanceInt % 10000; - if (transformedChanceInt == 0) return multiplier; - // Calculation of the Decimal Part of chance - double chance = transformedChanceInt / 10000.0; - double mean = parallel * chance; - double stdDev = Math.sqrt(parallel * chance * (1 - chance)); - // Check if everything within 3 standard deviations of mean is within the range - // of possible values (0 ~ currentParallel) - boolean isSuitableForFittingWithNormalDistribution = mean - 3 * stdDev >= 0 && mean + 3 * stdDev <= parallel; - if (isSuitableForFittingWithNormalDistribution) { - // Use Normal Distribution to fit Binomial Distribution - double tMultiplier = stdDev * rand.nextGaussian() + mean; - multiplier += Math.max(Math.min(tMultiplier, parallel), 0); - } else { - // Do Binomial Distribution by loop - for (int roll = 0; roll < parallel; roll++) { - if (transformedChanceInt > XSTR.XSTR_INSTANCE.nextInt(10000)) { - multiplier += 1; - } - } - } - return multiplier; - } - - public static void addItemsLong(ArrayList<ItemStack> itemList, ItemStack origin, long amount) { - if (amount > 0) { - while (amount > Integer.MAX_VALUE) { - ItemStack item = origin.copy(); - item.stackSize = Integer.MAX_VALUE; - itemList.add(item); - amount -= Integer.MAX_VALUE; - } - ItemStack item = origin.copy(); - item.stackSize = (int) amount; - itemList.add(item); - } - } - - public static void addFluidsLong(ArrayList<FluidStack> fluidList, FluidStack origin, long amount) { - if (amount > 0) { - while (amount > Integer.MAX_VALUE) { - FluidStack fluid = origin.copy(); - fluid.amount = Integer.MAX_VALUE; - fluidList.add(fluid); - amount -= Integer.MAX_VALUE; - } - FluidStack fluid = origin.copy(); - fluid.amount = (int) amount; - fluidList.add(fluid); - } - } - - @FunctionalInterface - public interface MaxParallelCalculator { - - double calculate(GT_Recipe recipe, int maxParallel, FluidStack[] fluids, ItemStack[] items); - } - - @FunctionalInterface - public interface InputConsumer { - - void consume(GT_Recipe recipe, int amountMultiplier, FluidStack[] aFluidInputs, ItemStack[] aInputs); - } -} |