diff options
Diffstat (limited to 'src/main')
17 files changed, 715 insertions, 372 deletions
diff --git a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java index 65d7ea5397..05d39cd02c 100644 --- a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java @@ -126,8 +126,8 @@ public class ComplexParallelProcessingLogic { .setFluidInputs(inputFluids[index]) .setAvailableEUt(availableEut[index]) .setMachine(tileEntity, isItemVoidProtected[index], isFluidVoidProtected[index]) - .enableConsumption() - .enableOutputCalculation(); + .setConsumption(true) + .setOutputCalculation(true); helper.build(); diff --git a/src/main/java/gregtech/api/logic/ProcessingLogic.java b/src/main/java/gregtech/api/logic/ProcessingLogic.java index cf3bef97e8..2a2e0e5137 100644 --- a/src/main/java/gregtech/api/logic/ProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java @@ -53,6 +53,7 @@ public class ProcessingLogic { protected int batchSize = 1; protected float euModifier = 1.0f; protected float speedBoost = 1.0f; + protected boolean amperageOC = true; public ProcessingLogic() {} @@ -228,6 +229,14 @@ public class ProcessingLogic { } /** + * Sets wether the multi should use amperage to OC or not + */ + public ProcessingLogic setAmperageOC(boolean amperageOC) { + this.amperageOC = amperageOC; + return this; + } + + /** * Clears calculated results and provided machine inputs to prepare for the next machine operation. */ public ProcessingLogic clear() { @@ -301,16 +310,17 @@ public class ProcessingLogic { } GT_ParallelHelper helper = createParallelHelper(recipe); - + GT_OverclockCalculator calculator = createOverclockCalculator(recipe); + helper.setCalculator(calculator); helper.build(); - if (helper.getCurrentParallel() <= 0) return CheckRecipeResultRegistry.OUTPUT_FULL; + if (!helper.getResult() + .wasSuccessful()) { + return helper.getResult(); + } calculatedParallels = helper.getCurrentParallel(); - GT_OverclockCalculator calculator = createOverclockCalculator(recipe, helper); - - calculator.calculate(); if (calculator.getConsumption() == Long.MAX_VALUE) { return CheckRecipeResultRegistry.POWER_OVERFLOW; } @@ -346,8 +356,14 @@ public class ProcessingLogic { @Nonnull protected FindRecipeResult findRecipe(@Nullable GT_Recipe_Map map) { if (map == null) return FindRecipeResult.NOT_FOUND; - return map - .findRecipeWithResult(lastRecipe, false, false, availableVoltage, inputFluids, specialSlotItem, inputItems); + return map.findRecipeWithResult( + lastRecipe, + false, + false, + amperageOC ? availableVoltage * availableAmperage : availableVoltage, + inputFluids, + specialSlotItem, + inputItems); } /** @@ -364,8 +380,8 @@ public class ProcessingLogic { .setMaxParallel(maxParallel) .setEUtModifier(euModifier) .enableBatchMode(batchSize) - .enableConsumption() - .enableOutputCalculation(); + .setConsumption(true) + .setOutputCalculation(true); } /** @@ -377,18 +393,31 @@ public class ProcessingLogic { } /** - * Override to tweak overclock logic if needed. + * Use {@link #createOverclockCalculator(GT_Recipe)} */ @Nonnull + @Deprecated protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nonnull GT_ParallelHelper helper) { + @Nullable GT_ParallelHelper helper) { + return createOverclockCalculator(recipe); + } + + /** + * Override to tweak overclock logic if needed. + */ + @Nonnull + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) - .setParallel((int) Math.floor(helper.getCurrentParallel() / helper.getDurationMultiplierDouble())) - .setDuration(recipe.mDuration) + .setRecipeAmperage( + recipeMapSupplier != null && recipeMapSupplier.get() != null + ? Math.max(recipeMapSupplier.get().mAmperage, 1) + : 1) .setAmperage(availableAmperage) .setEUt(availableVoltage) + .setDuration(recipe.mDuration) .setSpeedBoost(speedBoost) .setEUtDiscount(euModifier) + .setAmperageOC(amperageOC) .setDurationDecreasePerOC(overClockTimeReduction) .setEUtIncreasePerOC(overClockPowerIncrease); } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java index 938423012c..5b5c848ad5 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java @@ -210,8 +210,9 @@ public abstract class GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T extends GT @Override protected void setProcessingLogicPower(ProcessingLogic logic) { - logic.setAvailableVoltage(GT_Utility.roundDownVoltage(getAverageInputVoltage())); + logic.setAvailableVoltage(getAverageInputVoltage()); logic.setAvailableAmperage(getMaxInputAmps()); + logic.setAmperageOC(true); } @Override @@ -295,14 +296,17 @@ public abstract class GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T extends GT return GT_ExoticEnergyInputHelper.getMaxInputVoltageMulti(getExoticAndNormalEnergyHatchList()); } + @Override public long getAverageInputVoltage() { return GT_ExoticEnergyInputHelper.getAverageInputVoltageMulti(getExoticAndNormalEnergyHatchList()); } + @Override public long getMaxInputAmps() { return GT_ExoticEnergyInputHelper.getMaxWorkingInputAmpsMulti(getExoticAndNormalEnergyHatchList()); } + @Override public long getMaxInputEu() { return GT_ExoticEnergyInputHelper.getTotalEuMulti(getExoticAndNormalEnergyHatchList()); } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java index d427e99d4e..2f84151af9 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java @@ -786,8 +786,9 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } protected void setProcessingLogicPower(ProcessingLogic logic) { - logic.setAvailableVoltage(GT_Utility.roundDownVoltage(getMaxInputVoltage())); - logic.setAvailableAmperage(1); + logic.setAvailableVoltage(getAverageInputVoltage()); + logic.setAvailableAmperage(getMaxInputAmps()); + logic.setAmperageOC(mEnergyHatches.size() != 1); } protected int getMaxBatchSize() { @@ -1010,6 +1011,18 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return rVoltage; } + public long getAverageInputVoltage() { + return GT_ExoticEnergyInputHelper.getAverageInputVoltageMulti(mEnergyHatches); + } + + public long getMaxInputAmps() { + return GT_ExoticEnergyInputHelper.getMaxWorkingInputAmpsMulti(mEnergyHatches); + } + + public long getMaxInputEu() { + return GT_ExoticEnergyInputHelper.getTotalEuMulti(mEnergyHatches); + } + /** * Sums up max input EU/t of energy hatches, amperage included. */ diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java index 7a2d8661dd..aa129bab86 100644 --- a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java +++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java @@ -80,6 +80,10 @@ public final class CheckRecipeResultRegistry { * Progress time overflowed. */ public static final CheckRecipeResult DURATION_OVERFLOW = SimpleCheckRecipeResult.ofFailure("duration_overflow"); + /** + * Machine had an internal error + */ + public static final CheckRecipeResult INTERNAL_ERROR = SimpleCheckRecipeResult.ofFailure("internal_error"); /** * Cannot process recipe because the machine cannot handle required EUt. diff --git a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java index d8948fc265..5b4380028f 100644 --- a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java +++ b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java @@ -1,51 +1,123 @@ package gregtech.api.util; +import java.util.function.Supplier; + import javax.annotation.Nonnull; public class GT_OverclockCalculator { + private static final double LOG4 = Math.log(4); + /** - * mAmps - Amperage of the multiblock - * mEUt - Voltage of the multiblock - * mRecipeEUt - Voltage the recipe will run at - * mRecipeAmps - The amount of amps the recipe needs + * Voltage the recipe will run at */ - private long mAmps = 1, mEUt = 0, mRecipeEUt = 0, mRecipeAmps = 1; + private long recipeVoltage = 0; + /* + * The amount of amps the recipe needs + */ + private long recipeAmperage = 1; /** - * mEUtDiscount - Discount for EUt at the beginning of calculating overclocks, like GT++ machines - * mSpeedBoost - Speeding/Slowing up/down the duration of a recipe at the beginning of calculating overclocks, like - * GT++ machines - * mHeatDiscountAmount - The value used for discount final eut per 900 heat + * Voltage of the machine */ - private double mEUtDiscount = 1, mSpeedBoost = 1, mHeatDiscountAmount = 0.95f; + private long machineVoltage = 0; /** - * mEUtIncreasePerOC - How much the bits should be moved to the left when it is overclocking (Going up, 2 meaning - * it is multiplied with 4x) - * mDurationDecreasePerOC - How much the bits should be moved to the right when its overclocking (Going down, 1 - * meaning it is halved) - * mDuration - Duration of the recipe - * mParallel - The parallel the multi has when trying to overclock - * mRecipeHeat - The min heat required for the recipe - * mMultiHeat - The heat the multi has when starting the recipe - * mHeatPerfectOC - How much the bits should be moved to the right for each 1800 above recipe heat (Used for - * duration) + * Amperage of the machine */ - private int mEUtIncreasePerOC = 2, mDurationDecreasePerOC = 1, mDuration = 0, mParallel = 1, mRecipeHeat = 0, - mMultiHeat = 0, mHeatPerfectOC = 2; + private long machineAmperage = 1; /** - * mHeatOC - Whether to enable overclocking with heat like the EBF every 1800 heat difference - * mOneTickDiscount - Whether to give EUt Discount when the duration goes below one tick - * calculates - variable to check whether the overclocks have been calculated - * mHeatDiscount - Whether to enable heat discounts every 900 heat difference + * Duration of the recipe */ - private boolean mHeatOC, mOneTickDiscount, calculated, mHeatDiscount; + private int duration = 0; + /** + * The parallel the machine has when trying to overclock + */ + private int parallel = 1; - /** If the OC calculator should only do a given amount of overclocks. Mainly used in fusion reactors */ + /** + * The min heat required for the recipe + */ + private int recipeHeat = 0; + /** + * The heat the machine has when starting the recipe + */ + private int machineHeat = 0; + /** + * How much the bits should be moved to the right for each 1800 above recipe heat (Used for duration) + */ + private int durationDecreasePerHeatOC = 2; + /** + * Whether to enable overclocking with heat like the EBF every 1800 heat difference + */ + private boolean heatOC; + /** + * Whether to enable heat discounts every 900 heat difference + */ + private boolean heatDiscount; + /** + * The value used for discount final eut per 900 heat + */ + private double heatDiscountExponent = 0.95; + + /** + * Discount for EUt at the beginning of calculating overclocks, like GT++ machines + */ + private double eutDiscount = 1; + /** + * Speeding/Slowing up/down the duration of a recipe at the beginning of calculating overclocks, like + * GT++ machines + */ + private double speedBoost = 1; + + /** + * How much the bits should be moved to the left when it is overclocking (Going up, 2 meaning it is multiplied with + * 4x)- + */ + private int eutIncreasePerOC = 2; + /** + * How much the bits should be moved to the right when its overclocking (Going down, 1 meaning it is halved) + */ + private int durationDecreasePerOC = 1; + /** + * Whether to give EUt Discount when the duration goes below one tick + */ + private boolean oneTickDiscount; + /** + * Whether the multi should use amperage to overclock with an exponent. Incompatible with amperageOC + */ + private boolean laserOC; + /** + * Laser OC's penalty for using high amp lasers for overclocking. Like what the Adv. Assline is doing + */ + private double laserOCPenalty = 0.3; + /** + * Whether the multi should use amperage to overclock normally. Incompatible with laserOC + */ + private boolean amperageOC; + /** + * If the OC calculator should only do a given amount of overclocks. Mainly used in fusion reactors + */ private boolean limitOverclocks; - /** Maximum amount of overclocks to perform, when limitOverclocks = true */ + /** + * Maximum amount of overclocks to perform, when limitOverclocks = true + */ private int maxOverclocks; - /** How many overclocks have been performed */ + /** + * How many overclocks have been performed + */ private int overclockCount; + /** + * How many overclocks were performed with heat out of the overclocks we had + */ + private int heatOverclockCount; + /** + * A supplier, which is used for machines which have a custom way of calculating duration, like Neutron Activator + */ + private Supplier<Double> durationUnderOneTickSupplier; + + /** + * variable to check whether the overclocks have been calculated + */ + private boolean calculated; private static final int HEAT_DISCOUNT_THRESHOLD = 900; private static final int HEAT_PERFECT_OVERCLOCK_THRESHOLD = 1800; @@ -72,42 +144,73 @@ public class GT_OverclockCalculator { public GT_OverclockCalculator() {} /** - * @param aRecipeEUt Sets the Recipe's starting voltage + * Constructor for creating a new calculator with the save values + * + * @param calculator Calculator to copy over + */ + public GT_OverclockCalculator(@Nonnull GT_OverclockCalculator calculator) { + this(); + setRecipeEUt(calculator.recipeVoltage); + setRecipeAmperage(calculator.recipeAmperage); + setEUt(calculator.machineVoltage); + setAmperage(calculator.machineAmperage); + setDuration(calculator.duration); + setParallel(calculator.parallel); + setRecipeHeat(calculator.recipeHeat); + setMachineHeat(calculator.machineHeat); + setHeatPerfectOC(calculator.durationDecreasePerHeatOC); + setHeatOC(calculator.heatOC); + setHeatDiscount(calculator.heatDiscount); + setHeatDiscountMultiplier((float) calculator.heatDiscountExponent); + setEUtDiscount((float) calculator.eutDiscount); + setSpeedBoost((float) calculator.speedBoost); + setEUtIncreasePerOC(calculator.eutIncreasePerOC); + setDurationDecreasePerOC(calculator.durationDecreasePerOC); + setOneTickDiscount(calculator.oneTickDiscount); + setLaserOC(calculator.laserOC); + setLaserOCPenalty(calculator.laserOCPenalty); + setAmperageOC(calculator.amperageOC); + maxOverclocks = calculator.maxOverclocks; + limitOverclocks = calculator.limitOverclocks; + } + + /** + * @param recipeEUt Sets the Recipe's starting voltage */ - public GT_OverclockCalculator setRecipeEUt(long aRecipeEUt) { - mRecipeEUt = aRecipeEUt; + public GT_OverclockCalculator setRecipeEUt(long recipeEUt) { + this.recipeVoltage = recipeEUt; return this; } /** - * @param aEUt Sets the EUt that the multiblock can use. This is the voltage of the multi + * @param machineVoltage Sets the EUt that the machine can use. This is the voltage of the machine */ - public GT_OverclockCalculator setEUt(long aEUt) { - mEUt = aEUt; + public GT_OverclockCalculator setEUt(long machineVoltage) { + this.machineVoltage = machineVoltage; return this; } /** - * @param aDuration Sets the duration of the recipe + * @param duration Sets the duration of the recipe */ - public GT_OverclockCalculator setDuration(int aDuration) { - mDuration = aDuration; + public GT_OverclockCalculator setDuration(int duration) { + this.duration = duration; return this; } /** - * @param aAmps Sets the Amperage that the multi can support + * @param machineAmperage Sets the Amperage that the machine can support */ - public GT_OverclockCalculator setAmperage(long aAmps) { - mAmps = aAmps; + public GT_OverclockCalculator setAmperage(long machineAmperage) { + this.machineAmperage = machineAmperage; return this; } /** - * @param aRecipeAmps Sets the Amperage of the recipe + * @param recipeAmperage Sets the Amperage of the recipe */ - public GT_OverclockCalculator setRecipeAmperage(long aRecipeAmps) { - mRecipeAmps = aRecipeAmps; + public GT_OverclockCalculator setRecipeAmperage(long recipeAmperage) { + this.recipeAmperage = recipeAmperage; return this; } @@ -115,39 +218,63 @@ public class GT_OverclockCalculator { * Enables Perfect OC in calculation */ public GT_OverclockCalculator enablePerfectOC() { - mDurationDecreasePerOC = 2; + this.durationDecreasePerOC = 2; return this; } /** - * Enables calculating overclocking using EBF's perfectOC + * Use {@link #setHeatOC(boolean)} */ + @Deprecated public GT_OverclockCalculator enableHeatOC() { - mHeatOC = true; + return setHeatOC(true); + } + + /** + * Set if we should be calculating overclocking using EBF's perfectOC + */ + public GT_OverclockCalculator setHeatOC(boolean heatOC) { + this.heatOC = heatOC; return this; } /** - * Enables adding a heat discount at the end of calculating an overclock, just like the EBF + * Use {@link #setHeatDiscount(boolean)} */ + @Deprecated public GT_OverclockCalculator enableHeatDiscount() { - mHeatDiscount = true; + return setHeatDiscount(true); + } + + /** + * Sets if we should add a heat discount at the end of calculating an overclock, just like the EBF + */ + public GT_OverclockCalculator setHeatDiscount(boolean heatDiscount) { + this.heatDiscount = heatDiscount; return this; } /** * Sets the starting heat of the recipe */ - public GT_OverclockCalculator setRecipeHeat(int aRecipeHeat) { - mRecipeHeat = aRecipeHeat; + public GT_OverclockCalculator setRecipeHeat(int recipeHeat) { + this.recipeHeat = recipeHeat; return this; } /** - * Sets the heat of the coils on the multi + * Use {@link #setMachineHeat(int)} */ - public GT_OverclockCalculator setMultiHeat(int aMultiHeat) { - mMultiHeat = aMultiHeat; + @Deprecated + public GT_OverclockCalculator setMultiHeat(int machineHeat) { + return setMachineHeat(machineHeat); + } + + /** + * Sets the heat of the coils on the machine + */ + public GT_OverclockCalculator setMachineHeat(int machineHeat) { + this.machineHeat = machineHeat; return this; } @@ -155,7 +282,7 @@ public class GT_OverclockCalculator { * Sets an EUtDiscount. 0.9 is 10% less energy. 1.1 is 10% more energy */ public GT_OverclockCalculator setEUtDiscount(float aEUtDiscount) { - mEUtDiscount = aEUtDiscount; + this.eutDiscount = aEUtDiscount; return this; } @@ -163,7 +290,7 @@ public class GT_OverclockCalculator { * Sets a Speed Boost for the multiblock. 0.9 is 10% faster. 1.1 is 10% slower */ public GT_OverclockCalculator setSpeedBoost(float aSpeedBoost) { - mSpeedBoost = aSpeedBoost; + this.speedBoost = aSpeedBoost; return this; } @@ -171,7 +298,7 @@ public class GT_OverclockCalculator { * Sets the parallel that the multiblock uses */ public GT_OverclockCalculator setParallel(int aParallel) { - mParallel = aParallel; + this.parallel = aParallel; return this; } @@ -179,8 +306,8 @@ public class GT_OverclockCalculator { * Sets the heat discount during OC calculation if HeatOC is used. Default: 0.95 = 5% discount Used like a EU/t * Discount */ - public GT_OverclockCalculator setHeatDiscount(float aHeatDiscount) { - mHeatDiscountAmount = aHeatDiscount; + public GT_OverclockCalculator setHeatDiscountMultiplier(float heatDiscountExponent) { + this.heatDiscountExponent = heatDiscountExponent; return this; } @@ -188,8 +315,8 @@ public class GT_OverclockCalculator { * Sets the Overclock that should be calculated when one. This uses BitShifting! Default is 2, which is a 4x * decrease */ - public GT_OverclockCalculator setHeatPerfectOC(int aHeatPerfectOC) { - mHeatPerfectOC = aHeatPerfectOC; + public GT_OverclockCalculator setHeatPerfectOC(int heatPerfectOC) { + this.durationDecreasePerHeatOC = heatPerfectOC; return this; } @@ -197,7 +324,7 @@ public class GT_OverclockCalculator { * Sets the amount that the EUt increases per overclock. This uses BitShifting! Default is 2, which is a 4x increase */ public GT_OverclockCalculator setEUtIncreasePerOC(int aEUtIncreasePerOC) { - mEUtIncreasePerOC = aEUtIncreasePerOC; + this.eutIncreasePerOC = aEUtIncreasePerOC; return this; } @@ -205,17 +332,25 @@ public class GT_OverclockCalculator { * Sets the amount that the duration decreases per overclock. This uses BitShifting! Default is 1, which halves the * duration */ - public GT_OverclockCalculator setDurationDecreasePerOC(int aDurationDecreasePerOC) { - mDurationDecreasePerOC = aDurationDecreasePerOC; + public GT_OverclockCalculator setDurationDecreasePerOC(int durationDecreasePerOC) { + this.durationDecreasePerOC = durationDecreasePerOC; return this; } /** - * Enables One Tick Discount on EUt based on Duration Decrease Per Overclock. This functions the same as single - * blocks. + * Use {@link #setOneTickDiscount(boolean)} */ + @Deprecated public GT_OverclockCalculator enableOneTickDiscount() { - mOneTickDiscount = true; + return setOneTickDiscount(true); + } + + /** + * Set One Tick Discount on EUt based on Duration Decrease Per Overclock. This functions the same as single + * blocks. + */ + public GT_OverclockCalculator setOneTickDiscount(boolean oneTickDiscount) { + this.oneTickDiscount = oneTickDiscount; return this; } @@ -229,81 +364,137 @@ public class GT_OverclockCalculator { return this; } + public GT_OverclockCalculator setLaserOC(boolean laserOC) { + this.laserOC = laserOC; + return this; + } + + public GT_OverclockCalculator setAmperageOC(boolean amperageOC) { + this.amperageOC = amperageOC; + return this; + } + + public GT_OverclockCalculator setLaserOCPenalty(double laserOCPenalty) { + this.laserOCPenalty = laserOCPenalty; + return this; + } + + /** + * Set a supplier for calculating custom duration for when its needed under one tick + */ + public GT_OverclockCalculator setDurationUnderOneTickSupplier(Supplier<Double> supplier) { + this.durationUnderOneTickSupplier = supplier; + return this; + } + /** * Call this when all values have been put it. */ public GT_OverclockCalculator calculate() { + if (calculated) { + throw new IllegalStateException("Tried to calculate overclocks twice"); + } calculateOverclock(); calculated = true; return this; } private void calculateOverclock() { - if (mRecipeEUt > mEUt || mRecipeHeat > mMultiHeat) { - mRecipeEUt = Long.MAX_VALUE; - mDuration = Integer.MAX_VALUE; - return; + if (laserOC && amperageOC) { + throw new IllegalStateException("Tried to calculate overclock with both laser and amperage overclocking"); } - int heatDiscounts = mHeatDiscount ? (mMultiHeat - mRecipeHeat) / HEAT_DISCOUNT_THRESHOLD : 0; - double heatDiscountMultiplier = Math.pow(mHeatDiscountAmount, heatDiscounts); - mDuration = (int) Math.ceil(mDuration * mSpeedBoost); - if (mHeatOC) { - while (mRecipeHeat + HEAT_PERFECT_OVERCLOCK_THRESHOLD <= mMultiHeat - && (long) Math.ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier) << 2 - < mEUt * mAmps) { - if (mDuration < 1) { - break; - } - mRecipeEUt <<= mEUtIncreasePerOC; - mDuration >>= mHeatPerfectOC; - mRecipeHeat += HEAT_PERFECT_OVERCLOCK_THRESHOLD; - } + double heatDiscountMultiplier = calculateHeatDiscountMultiplier(); + duration = (int) Math.ceil(duration * speedBoost); + if (heatOC) { + heatOverclockCount = calculateAmountOfHeatOverclocks(); } - int tRecipeTier = GT_Utility.getTier(mRecipeEUt); - if (tRecipeTier == 0) { - int tTier = GT_Utility.getTier(mEUt); - int tTierDifference = tTier - 1; - long tNextConsumption = ((long) Math - .ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier)) - << mEUtIncreasePerOC; - while (tTierDifference > 0 && tNextConsumption < mEUt * mAmps - && (!limitOverclocks || overclockCount++ < maxOverclocks)) { - if (mDuration <= 1) { - break; - } - mRecipeEUt <<= mEUtIncreasePerOC; - mDuration >>= mDurationDecreasePerOC; - tNextConsumption <<= mEUtIncreasePerOC; - tTierDifference--; - } - } else { - long tNextConsumption = ((long) Math - .ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier)) - << mEUtIncreasePerOC; - while (tNextConsumption < mEUt * mAmps && (!limitOverclocks || overclockCount++ < maxOverclocks)) { - if (mDuration <= 1) { - break; - } - mRecipeEUt <<= mEUtIncreasePerOC; - mDuration >>= mDurationDecreasePerOC; - tNextConsumption <<= mEUtIncreasePerOC; + double recipePowerTier = calculateRecipePowerTier(heatDiscountMultiplier); + double machinePowerTier = calculateMachinePowerTier(); + // Math.log(a) / Math.log(b) equals to log_b (a) + overclockCount = calculateAmountOfNeededOverclocks(machinePowerTier, recipePowerTier); + if (overclockCount < 0) { + recipeVoltage = Long.MAX_VALUE; + duration = Integer.MAX_VALUE; + return; + } + + overclockCount = limitOverclocks ? Math.min(maxOverclocks, overclockCount) : overclockCount; + heatOverclockCount = Math.min(heatOverclockCount, overclockCount); + recipeVoltage <<= eutIncreasePerOC * overclockCount; + duration >>= durationDecreasePerOC * (overclockCount - heatOverclockCount); + duration >>= durationDecreasePerHeatOC * heatOverclockCount; + if (oneTickDiscount) { + recipeVoltage >>= durationDecreasePerOC * ((int) (machinePowerTier - recipePowerTier - overclockCount)); + if (recipeVoltage < 1) { + recipeVoltage = 1; } } - if (mDuration < 1) { - mDuration = 1; + if (laserOC) { + calculateLaserOC(); } - if (mOneTickDiscount) { - int voltageDifference = GT_Utility.getTier(mEUt) - GT_Utility.getTier(mRecipeEUt); - mRecipeEUt >>= (long) voltageDifference * mDurationDecreasePerOC; - if (mRecipeEUt < 1) { - mRecipeEUt = 1; - } + if (duration < 1) { + duration = 1; } - mRecipeEUt = (long) Math.ceil(mRecipeEUt * mParallel * mRecipeAmps * mEUtDiscount * heatDiscountMultiplier); + recipeVoltage = calculateFinalRecipeEUt(heatDiscountMultiplier); + } + + private double calculateRecipePowerTier(double heatDiscountMultiplier) { + return Math.max( + 1, + Math.log(recipeVoltage * parallel * eutDiscount * heatDiscountMultiplier * recipeAmperage) / LOG4 - 1); + } + + private double calculateMachinePowerTier() { + return Math.max( + 1, + Math.log(machineVoltage * (amperageOC ? machineAmperage : Math.min(machineAmperage, parallel))) / LOG4 - 1); + } + + private long calculateFinalRecipeEUt(double heatDiscountMultiplier) { + return (long) Math.ceil(recipeVoltage * eutDiscount * heatDiscountMultiplier * parallel * recipeAmperage); + } + + private int calculateAmountOfHeatOverclocks() { + return Math.min( + (machineHeat - recipeHeat) / HEAT_PERFECT_OVERCLOCK_THRESHOLD, + calculateAmountOfOverclocks( + calculateMachinePowerTier(), + calculateRecipePowerTier(calculateHeatDiscountMultiplier()))); + } + + /** + * Calculate maximum possible overclocks ignoring if we are going to go under 1 tick + */ + private int calculateAmountOfOverclocks(double machinePowerTier, double recipePowerTier) { + return (int) (machinePowerTier - recipePowerTier); + } + + /** + * Calculates the amount of overclocks needed to reach 1 ticking + */ + private int calculateAmountOfNeededOverclocks(double machinePowerTier, double recipePowerTier) { + return (int) Math.min( + calculateAmountOfOverclocks(machinePowerTier, recipePowerTier), + Math.log(duration) / Math.log(1 << durationDecreasePerOC)); + } + + private double calculateHeatDiscountMultiplier() { + int heatDiscounts = heatDiscount ? (machineHeat - recipeHeat) / HEAT_DISCOUNT_THRESHOLD : 0; + return Math.pow(heatDiscountExponent, heatDiscounts); + } + + private void calculateLaserOC() { + long inputEut = machineVoltage * machineAmperage; + double currentPenalty = (1 << eutIncreasePerOC) + laserOCPenalty; + while (inputEut > recipeVoltage * currentPenalty && recipeVoltage * currentPenalty > 0 && duration > 1) { + duration >>= durationDecreasePerOC; + recipeVoltage *= currentPenalty; + currentPenalty += laserOCPenalty; + } } /** @@ -311,9 +502,9 @@ public class GT_OverclockCalculator { */ public long getConsumption() { if (!calculated) { - calculate(); + throw new IllegalStateException("Tried to get consumption before calculating"); } - return mRecipeEUt; + return recipeVoltage; } /** @@ -321,9 +512,9 @@ public class GT_OverclockCalculator { */ public int getDuration() { if (!calculated) { - calculate(); + throw new IllegalStateException("Tried to get duration before calculating"); } - return mDuration; + return duration; } /** @@ -331,8 +522,40 @@ public class GT_OverclockCalculator { */ public int getPerformedOverclocks() { if (!calculated) { - calculate(); + throw new IllegalStateException("Tried to get performed overclocks before calculating"); } return overclockCount; } + + /** + * Returns duration as a double to show how much it is overclocking too much to determine extra parallel. + * This doesn't count as calculating + */ + public double calculateDurationUnderOneTick() { + if (durationUnderOneTickSupplier != null) return durationUnderOneTickSupplier.get(); + int normalOverclocks = calculateAmountOfOverclocks( + calculateMachinePowerTier(), + calculateRecipePowerTier(calculateHeatDiscountMultiplier())); + normalOverclocks = limitOverclocks ? Math.min(normalOverclocks, maxOverclocks) : normalOverclocks; + int heatOverclocks = Math.min(calculateAmountOfHeatOverclocks(), normalOverclocks); + return (duration * speedBoost) / (Math.pow(1 << durationDecreasePerOC, normalOverclocks - heatOverclocks) + * Math.pow(1 << durationDecreasePerHeatOC, heatOverclocks)); + } + + /** + * Returns the EUt consumption one would get from overclocking under 1 tick + * This Doesn't count as calculating + * + * @param originalMaxParallel Parallels which are of the actual machine before the overclocking extra ones + */ + public long calculateEUtConsumptionUnderOneTick(int originalMaxParallel, int currentParallel) { + double parallelOverclocks = Math.log((double) currentParallel / originalMaxParallel) + / Math.log(1 << durationDecreasePerOC); + return (long) Math.floor( + recipeVoltage * Math.pow(1 << eutIncreasePerOC, parallelOverclocks) + * originalMaxParallel + * eutDiscount + * recipeAmperage + * calculateHeatDiscountMultiplier()); + } } diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java index 07439967d3..6d28dab036 100644 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -1,6 +1,7 @@ package gregtech.api.util; import java.util.Objects; +import java.util.function.Function; import javax.annotation.Nonnull; @@ -11,11 +12,14 @@ import gregtech.api.interfaces.tileentity.IRecipeLockable; import gregtech.api.interfaces.tileentity.IVoidable; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; import gregtech.api.objects.XSTR; +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 */ @@ -31,40 +35,40 @@ public class GT_ParallelHelper { /** * Recipe used when trying to calculate parallels */ - private GT_Recipe mRecipe; + private GT_Recipe recipe; /** * EUt available to the multiblock (This should be the total eut available) */ - private long mAvailableEUt; + private long availableEUt; /** * The current parallel possible for the multiblock */ - private int mCurrentParallel = 0; + private int currentParallel = 0; /** * The maximum possible parallel possible for the multiblock */ - private int mMaxParallel = 1; + 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 mBatchModifier = 1; + private int batchModifier = 1; /** * The inputs of the multiblock for the current recipe check */ - private ItemStack[] mItemInputs; + private ItemStack[] itemInputs; /** * The outputs of the recipe with the applied parallel */ - private ItemStack[] mItemOutputs; + private ItemStack[] itemOutputs; /** * The inputs of the multiblock for the current recipe check */ - private FluidStack[] mFluidInputs; + private FluidStack[] fluidInputs; /** * The outputs of the recipe with the applied parallel */ - private FluidStack[] mFluidOutputs; + private FluidStack[] fluidOutputs; /** * Does the multi have void protection enabled for items */ @@ -76,28 +80,39 @@ public class GT_ParallelHelper { /** * Should the Parallel Helper automatically consume for the multi */ - private boolean mConsume; + private boolean consume; /** * Is batch mode turned on? */ - private boolean mBatchMode; + private boolean batchMode; /** * Should the Parallel Helper automatically calculate the outputs of the recipe with current * parallel */ - private boolean mCalculateOutputs; + private boolean calculateOutputs; /** * Has the Parallel Helper been built? */ - private boolean mBuilt; + private boolean built; /** * What is the duration multiplier with batch mode enabled */ - private double mDurationMultiplier; + private double durationMultiplier; /** * Modifier which is applied on the recipe eut. Useful for GT++ machines */ - private float mEUtModifier = 1; + private float eutModifier = 1; + + /** + * Calculator to use for overclocking + */ + private GT_OverclockCalculator calculator; + + private CheckRecipeResult result = CheckRecipeResultRegistry.NONE; + + private Function<Integer, ItemStack[]> customItemOutputCalculation; + + private Function<Integer, FluidStack[]> customFluidOutputCalculation; public GT_ParallelHelper() {} @@ -143,7 +158,7 @@ public class GT_ParallelHelper { * Sets the recipe, which will be used for the parallel calculation */ public GT_ParallelHelper setRecipe(@Nonnull GT_Recipe aRecipe) { - mRecipe = Objects.requireNonNull(aRecipe); + recipe = Objects.requireNonNull(aRecipe); return this; } @@ -157,7 +172,7 @@ public class GT_ParallelHelper { * Sets the items available for the recipe check */ public GT_ParallelHelper setItemInputs(ItemStack... aItemInputs) { - mItemInputs = aItemInputs; + this.itemInputs = aItemInputs; return this; } @@ -165,7 +180,7 @@ public class GT_ParallelHelper { * Sets the fluid inputs available for the recipe check */ public GT_ParallelHelper setFluidInputs(FluidStack... aFluidInputs) { - mFluidInputs = aFluidInputs; + this.fluidInputs = aFluidInputs; return this; } @@ -173,7 +188,7 @@ public class GT_ParallelHelper { * Sets the available eut when trying for more parallels */ public GT_ParallelHelper setAvailableEUt(long aAvailableEUt) { - mAvailableEUt = aAvailableEUt; + this.availableEUt = aAvailableEUt; return this; } @@ -181,23 +196,38 @@ public class GT_ParallelHelper { * Sets the modifier for recipe eut. 1 does nothing 0.9 is 10% less. 1.1 is 10% more */ public GT_ParallelHelper setEUtModifier(float aEUtModifier) { - mEUtModifier = aEUtModifier; + this.eutModifier = aEUtModifier; + return this; + } + + public GT_ParallelHelper setCalculator(GT_OverclockCalculator calculator) { + this.calculator = calculator; return this; } /** - * Consume inputs when trying for parallels + * Use {@link #setConsumption(boolean)} */ + @Deprecated public GT_ParallelHelper enableConsumption() { - mConsume = true; + return setConsumption(true); + } + + /** + * Set if we should consume inputs or not when trying for parallels + * + * @param consume Should we consume inputs + */ + public GT_ParallelHelper setConsumption(boolean consume) { + this.consume = consume; return this; } /** * Sets the MaxParallel a multi can handle */ - public GT_ParallelHelper setMaxParallel(int aMaxParallel) { - mMaxParallel = aMaxParallel; + public GT_ParallelHelper setMaxParallel(int maxParallel) { + this.maxParallel = maxParallel; return this; } @@ -205,18 +235,45 @@ public class GT_ParallelHelper { * Enables Batch mode. Can do up to an additional processed recipes of mCurrentParallel * mBatchModifier A batch * modifier of 1 does nothing */ - public GT_ParallelHelper enableBatchMode(int aBatchModifier) { - mBatchMode = aBatchModifier > 1; - mBatchModifier = aBatchModifier; + public GT_ParallelHelper enableBatchMode(int batchModifier) { + this.batchMode = batchModifier > 1; + this.batchModifier = batchModifier; return this; } /** - * Enables the outputs to be calculated with its current Parallels, useful if one isn't doing anything special with - * outputs + * Use {@link #setOutputCalculation(boolean)} */ + @Deprecated public GT_ParallelHelper enableOutputCalculation() { - mCalculateOutputs = true; + return setOutputCalculation(true); + } + + /** + * Sets if we should calculate outputs with the parallels we found or not + * + * @param calculateOutputs Should we calculate outputs with the helper or not + */ + 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 + */ + 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 + */ + public GT_ParallelHelper setCustomFluidOutputCalculation(Function<Integer, FluidStack[]> custom) { + customFluidOutputCalculation = custom; return this; } @@ -224,13 +281,13 @@ public class GT_ParallelHelper { * Finishes the GT_ParallelHelper. Anything changed after this will not effect anything */ public GT_ParallelHelper build() { - if (mBuilt) { + if (built) { throw new IllegalStateException("Tried to build twice"); } - if (mRecipe == null) { + if (recipe == null) { throw new IllegalStateException("Recipe is not set"); } - mBuilt = true; + built = true; determineParallel(); return this; } @@ -239,21 +296,21 @@ public class GT_ParallelHelper { * @return The current parallels possible by the multiblock */ public int getCurrentParallel() { - if (!mBuilt) { + if (!built) { throw new IllegalStateException("Tried to get parallels before building"); } - return mCurrentParallel; + return currentParallel; } /** * @return The duration multiplier if batch mode was enabled for the multiblock */ public double getDurationMultiplierDouble() { - if (!mBuilt) { + if (!built) { throw new IllegalStateException("Tried to get duration multiplier before building"); } - if (mBatchMode) { - return mDurationMultiplier; + if (batchMode && durationMultiplier > 0) { + return durationMultiplier; } return 1; } @@ -269,72 +326,92 @@ public class GT_ParallelHelper { /** * @return The ItemOutputs from the recipe */ + @Nonnull public ItemStack[] getItemOutputs() { - if (!mBuilt || !mCalculateOutputs) { + if (!built || !calculateOutputs) { throw new IllegalStateException( "Tried to get item outputs before building or without enabling calculation of outputs"); } - return mItemOutputs; + return itemOutputs; } /** * @return The FluidOutputs from the recipe */ + @Nonnull public FluidStack[] getFluidOutputs() { - if (!mBuilt || !mCalculateOutputs) { + if (!built || !calculateOutputs) { throw new IllegalStateException( "Tried to get fluid outputs before building or without enabling calculation of outputs"); } - return mFluidOutputs; + 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; + } + + /** + * Use {@link #tryConsumeRecipeInputs(GT_Recipe, FluidStack[], ItemStack[], int)} + */ + @Deprecated + protected boolean tryConsumeRecipeInputs(GT_Recipe recipe, FluidStack[] fluids, ItemStack[] items) { + return tryConsumeRecipeInputs(recipe, fluids, items, 1); } /** * Try to consume the inputs of the recipe * - * @param recipe Processed recipe - * @param fluids fluid inputs that will be consumed - * @param items item inputs that will be consumed + * @param recipe Processed recipe + * @param fluids fluid inputs that will be consumed + * @param items item inputs that will be consumed + * @param minParallel minimum amount of parallels to do with this check * @return True if recipe was satisfied, else false */ - protected boolean tryConsumeRecipeInputs(GT_Recipe recipe, FluidStack[] fluids, ItemStack[] items) { - return recipe.isRecipeInputEqual(true, false, fluids, items); + protected boolean tryConsumeRecipeInputs(GT_Recipe recipe, FluidStack[] fluids, ItemStack[] items, + int minParallel) { + return recipe.isRecipeInputEqual(true, false, minParallel, fluids, items); } /** * Called by build(). Determines the parallels and everything else that needs to be done at build time */ protected void determineParallel() { - if (mRecipe.mEUt > mAvailableEUt) { - return; + if (itemInputs == null) { + itemInputs = new ItemStack[0]; } - if (mItemInputs == null) { - mItemInputs = new ItemStack[0]; + if (fluidInputs == null) { + fluidInputs = new FluidStack[0]; } - if (mFluidInputs == null) { - mFluidInputs = new FluidStack[0]; + + if (!consume) { + copyInputs(); } - ItemStack[] tItemInputs; - FluidStack[] tFluidInputs; - // see if people want to consume their inputs or not - if (mConsume) { - tItemInputs = mItemInputs; - tFluidInputs = mFluidInputs; - } else { - // copy to prevent consuming original inputs - tItemInputs = new ItemStack[mItemInputs.length]; - for (int i = 0; i < mItemInputs.length; i++) { - tItemInputs[i] = mItemInputs[i].copy(); - } - tFluidInputs = new FluidStack[mFluidInputs.length]; - for (int i = 0; i < mFluidInputs.length; i++) { - tFluidInputs[i] = mFluidInputs[i].copy(); - } + if (calculator == null) { + calculator = new GT_OverclockCalculator().setEUt(availableEUt) + .setRecipeEUt(recipe.mEUt) + .setDuration(recipe.mDuration) + .setEUtDiscount(eutModifier); + } + + // Save the original max parallel before calculating our overclocking under 1 tick + int originalMaxParallel = maxParallel; + double tickTimeAfterOC = calculator.calculateDurationUnderOneTick(); + if (tickTimeAfterOC < 1) { + maxParallel = (int) Math.floor(maxParallel / tickTimeAfterOC); } - int maxParallelBeforeBatchMode = mMaxParallel; - if (mBatchMode) { - mMaxParallel *= mBatchModifier; + int maxParallelBeforeBatchMode = maxParallel; + if (batchMode) { + maxParallel *= batchModifier; } SingleRecipeCheck recipeCheck = null; @@ -347,7 +424,7 @@ public class GT_ParallelHelper { GT_Recipe.GT_Recipe_Map recipeMap = singleRecipeMachine.getRecipeMap(); if (recipeMap != null) { tSingleRecipeCheckBuilder = SingleRecipeCheck.builder(recipeMap) - .setBefore(tItemInputs, tFluidInputs); + .setBefore(itemInputs, fluidInputs); } } } @@ -359,33 +436,37 @@ public class GT_ParallelHelper { } VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper(); voidProtectionHelper.setMachine(machine) - .setItemOutputs(mRecipe.mOutputs) - .setFluidOutputs(mRecipe.mFluidOutputs) - .setMaxParallel(mMaxParallel) + .setItemOutputs(recipe.mOutputs) + .setFluidOutputs(recipe.mFluidOutputs) + .setMaxParallel(maxParallel) .build(); - mMaxParallel = Math.min(voidProtectionHelper.getMaxParallel(), mMaxParallel); + maxParallel = Math.min(voidProtectionHelper.getMaxParallel(), maxParallel); + if (maxParallel <= 0) { + result = CheckRecipeResultRegistry.OUTPUT_FULL; + return; + } } - maxParallelBeforeBatchMode = Math.min(mMaxParallel, maxParallelBeforeBatchMode); + maxParallelBeforeBatchMode = Math.min(maxParallel, maxParallelBeforeBatchMode); - final int tRecipeEUt = (int) Math.ceil(mRecipe.mEUt * mEUtModifier); + final int tRecipeEUt = (int) Math.ceil(recipe.mEUt * eutModifier); // Consume inputs to determine normal parallel if (recipeCheck != null) { - int actualMaxParallel = (int) Math.min(maxParallelBeforeBatchMode, mAvailableEUt / tRecipeEUt); - mCurrentParallel = recipeCheck.checkRecipeInputs(true, actualMaxParallel, tItemInputs, tFluidInputs); + int actualMaxParallel = (int) Math.min(maxParallelBeforeBatchMode, availableEUt / tRecipeEUt); + currentParallel = recipeCheck.checkRecipeInputs(true, actualMaxParallel, itemInputs, fluidInputs); } else { long tCurrentUsage = 0; boolean builtRecipeCheck = false; - for (; mCurrentParallel < maxParallelBeforeBatchMode - && tCurrentUsage < (mAvailableEUt - tRecipeEUt); mCurrentParallel++) { - if (!tryConsumeRecipeInputs(mRecipe, tFluidInputs, tItemInputs)) { + for (; currentParallel < maxParallelBeforeBatchMode + && tCurrentUsage < (availableEUt - tRecipeEUt); currentParallel++) { + if (!tryConsumeRecipeInputs(recipe, fluidInputs, itemInputs)) { break; } tCurrentUsage += tRecipeEUt; if (tSingleRecipeCheckBuilder != null && !builtRecipeCheck) { // If recipe checker is not built yet, build and set it - SingleRecipeCheck builtCheck = tSingleRecipeCheckBuilder.setAfter(tItemInputs, tFluidInputs) - .setRecipe(mRecipe) + SingleRecipeCheck builtCheck = tSingleRecipeCheckBuilder.setAfter(itemInputs, fluidInputs) + .setRecipe(recipe) .build(); singleRecipeMachine.setSingleRecipeCheck(builtCheck); builtRecipeCheck = true; @@ -393,69 +474,111 @@ public class GT_ParallelHelper { } } + if (currentParallel <= 0) { + result = CheckRecipeResultRegistry.INTERNAL_ERROR; + return; + } + + long eutUseAfterOC = calculator.calculateEUtConsumptionUnderOneTick(originalMaxParallel, currentParallel); + calculator.setParallel(Math.min(currentParallel, originalMaxParallel)) + .calculate(); + if (currentParallel > originalMaxParallel) { + calculator.setRecipeEUt(eutUseAfterOC); + } // If Batch Mode is enabled determine how many extra parallels we can get - if (mBatchMode && mCurrentParallel > 0) { + if (batchMode && currentParallel > 0 && calculator.getDuration() < MAX_BATCH_MODE_TICK_TIME) { int tExtraParallels = 0; - final int maxExtraParallels = Math - .min(mCurrentParallel * (mBatchModifier - 1), mMaxParallel - mCurrentParallel); + 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, tItemInputs, tFluidInputs); + tExtraParallels = recipeCheck.checkRecipeInputs(true, maxExtraParallels, itemInputs, fluidInputs); } else { while (tExtraParallels < maxExtraParallels - && tryConsumeRecipeInputs(mRecipe, tFluidInputs, tItemInputs)) { - tExtraParallels++; + && tryConsumeRecipeInputs(recipe, fluidInputs, itemInputs, currentParallel)) { + tExtraParallels += currentParallel; } } - mDurationMultiplier = 1.0f + (float) tExtraParallels / mCurrentParallel; - mCurrentParallel += tExtraParallels; + durationMultiplier = 1.0f + (float) tExtraParallels / currentParallel; + currentParallel += tExtraParallels; } // If we want to calculate outputs we do it here - if (mCalculateOutputs && mCurrentParallel > 0) { - if (mRecipe.mOutputs != null) { + if (calculateOutputs && currentParallel > 0) { + if (recipe.mOutputs != null) { calculateItemOutputs(); } - if (mRecipe.mFluidOutputs != null) { - mFluidOutputs = new FluidStack[mRecipe.mFluidOutputs.length]; - for (int i = 0; i < mRecipe.mFluidOutputs.length; i++) { - if (mRecipe.getFluidOutput(i) == null) { - mFluidOutputs[i] = null; - } else { - FluidStack tFluid = mRecipe.getFluidOutput(i) - .copy(); - tFluid.amount *= mCurrentParallel; - mFluidOutputs[i] = tFluid; - } - } + if (recipe.mFluidOutputs != null) { + calculateFluidOutputs(); } } + 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; } protected void calculateItemOutputs() { - mItemOutputs = new ItemStack[mRecipe.mOutputs.length]; - for (int i = 0; i < mRecipe.mOutputs.length; i++) { - if (mRecipe.getOutputChance(i) >= 10000) { - ItemStack item = mRecipe.getOutput(i) + if (customItemOutputCalculation != null) { + itemOutputs = customItemOutputCalculation.apply(currentParallel); + return; + } + itemOutputs = new ItemStack[recipe.mOutputs.length]; + for (int i = 0; i < recipe.mOutputs.length; i++) { + if (recipe.getOutputChance(i) >= 10000) { + ItemStack item = recipe.getOutput(i) .copy(); - item.stackSize *= mCurrentParallel; - mItemOutputs[i] = item; + item.stackSize *= currentParallel; + itemOutputs[i] = item; continue; } int items = 0; - int itemStackSize = mRecipe.getOutput(i).stackSize; - for (int roll = 0; roll < mCurrentParallel; roll++) { - if (mRecipe.getOutputChance(i) >= XSTR.XSTR_INSTANCE.nextInt(10000)) { + int itemStackSize = recipe.getOutput(i).stackSize; + for (int roll = 0; roll < currentParallel; roll++) { + if (recipe.getOutputChance(i) >= XSTR.XSTR_INSTANCE.nextInt(10000)) { items += itemStackSize; } } - ItemStack item = mRecipe.getOutput(i) + ItemStack item = recipe.getOutput(i) .copy(); if (items == 0) { item = null; } else { item.stackSize = items; } - mItemOutputs[i] = item; + itemOutputs[i] = item; + } + } + + protected void calculateFluidOutputs() { + if (customFluidOutputCalculation != null) { + fluidOutputs = customFluidOutputCalculation.apply(currentParallel); + return; + } + fluidOutputs = new FluidStack[recipe.mFluidOutputs.length]; + for (int i = 0; i < recipe.mFluidOutputs.length; i++) { + if (recipe.getFluidOutput(i) == null) { + fluidOutputs[i] = null; + } else { + FluidStack tFluid = recipe.getFluidOutput(i) + .copy(); + tFluid.amount *= currentParallel; + fluidOutputs[i] = tFluid; + } } } } diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java index 912dbda73d..c0043d2adf 100644 --- a/src/main/java/gregtech/api/util/GT_Utility.java +++ b/src/main/java/gregtech/api/util/GT_Utility.java @@ -494,9 +494,17 @@ public class GT_Utility { } /** - * Rounds down partial voltage that exceeds tiered voltage, e.g. 4096 -> 2048 (EV) + * Do not use. It is rounding up voltage */ + @Deprecated public static long roundDownVoltage(long voltage) { + return roundUpVoltage(voltage); + } + + /** + * Rounds up partial voltage that exceeds tiered voltage, e.g. 4,096 -> 8,192(IV) + */ + public static long roundUpVoltage(long voltage) { if (voltage > V[V.length - 1]) { return voltage; } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java index d7c34af6d0..2a4bb0f907 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java @@ -55,7 +55,6 @@ import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; @@ -195,12 +194,11 @@ public class GT_MetaTileEntity_ElectricBlastFurnace extends @Nonnull @Override - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nonnull GT_ParallelHelper helper) { - return super.createOverclockCalculator(recipe, helper).setRecipeHeat(recipe.mSpecialValue) - .setMultiHeat(mHeatingCapacity) - .enableHeatOC() - .enableHeatDiscount(); + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe).setRecipeHeat(recipe.mSpecialValue) + .setMachineHeat(mHeatingCapacity) + .setHeatOC(true) + .setHeatDiscount(true); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java index 9b390ae822..d7dcaea6ae 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java @@ -300,26 +300,13 @@ public abstract class GT_MetaTileEntity_FusionComputer @Override protected GT_ParallelHelper createParallelHelper(@NotNull GT_Recipe recipe) { // When the fusion first loads and is still processing, it does the recipe check without consuming. - if (mRunningOnLoad) { - return new GT_ParallelHelper().setRecipe(recipe) - .setItemInputs(inputItems) - .setFluidInputs(inputFluids) - .setAvailableEUt(availableVoltage * availableAmperage) - .setMachine(machine, protectItems, protectFluids) - .setRecipeLocked(recipeLockableMachine, isRecipeLocked) - .setMaxParallel(maxParallel) - .enableBatchMode(batchSize) - .enableOutputCalculation(); - } - return super.createParallelHelper(recipe); + return super.createParallelHelper(recipe).setConsumption(!mRunningOnLoad); } @NotNull @Override - protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe, - @NotNull GT_ParallelHelper helper) { - return super.createOverclockCalculator(recipe, helper) - .limitOverclockCount(overclock(recipe.mSpecialValue)); + protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe).limitOverclockCount(overclock(recipe.mSpecialValue)); } @NotNull @@ -351,6 +338,7 @@ public abstract class GT_MetaTileEntity_FusionComputer protected void setProcessingLogicPower(ProcessingLogic logic) { logic.setAvailableVoltage(GT_Values.V[tier()]); logic.setAvailableAmperage(1); + logic.setAmperageOC(false); } public abstract int tierOverclock(); diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java index ca68d3ad4c..b30fb6495f 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java @@ -248,6 +248,7 @@ public class GT_MetaTileEntity_NanoForge extends protected void setProcessingLogicPower(ProcessingLogic logic) { logic.setAvailableVoltage(getMaxInputEu()); logic.setAvailableAmperage(1); + logic.setAmperageOC(false); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java index 2cfbd1a30e..dff6b7d3b4 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java @@ -557,28 +557,18 @@ public class GT_MetaTileEntity_PCBFactory extends return CheckRecipeResultRegistry.SUCCESSFUL; } - @Override - protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, - @Nonnull GT_OverclockCalculator calculator) { - if (isNoOC()) { - return super.calculateDuration(recipe, helper, calculator) * getDurationMultiplierFromRoughness(); - } - return super.calculateDuration(recipe, helper, calculator); - } - @Nonnull @Override - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nonnull GT_ParallelHelper helper) { + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { if (isNoOC()) { - return GT_OverclockCalculator.ofNoOverclock(recipe); + return GT_OverclockCalculator.ofNoOverclock(recipe) + .setEUtDiscount((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) + .setSpeedBoost(getDurationMultiplierFromRoughness()); } - GT_OverclockCalculator calculator = super.createOverclockCalculator(recipe, helper) + GT_OverclockCalculator calculator = super.createOverclockCalculator(recipe) .setEUtDiscount((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) - .setSpeedBoost(getDurationMultiplierFromRoughness()); - if (mOCTier2) { - calculator.enablePerfectOC(); - } + .setSpeedBoost(getDurationMultiplierFromRoughness()) + .setDurationDecreasePerOC(mOCTier2 ? 2 : 1); return calculator; } @@ -586,42 +576,24 @@ public class GT_MetaTileEntity_PCBFactory extends @Override protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) { return super.createParallelHelper(recipe) - .setEUtModifier((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)); - } - - @NotNull - @Override - public CheckRecipeResult process() { - CheckRecipeResult result = super.process(); - - if (!result.wasSuccessful()) { - return result; - } - - mCurrentParallel = calculatedParallels; - - ItemStack controllerStack = getControllerSlot(); - - if (mCurrentParallel > 0) { - ArrayList<ItemStack> chancedOutputs = new ArrayList<>(); - int remainingEfficiency = getMaxEfficiency(controllerStack); - for (int j = 0; j < (int) Math.ceil(getMaxEfficiency(controllerStack) / 10000.0f); j++) { - int chanced = getBaseMetaTileEntity().getRandomNumber(10000); - if (chanced >= remainingEfficiency) { - continue; - } - for (ItemStack tOutput : outputItems) { - if (tOutput == null) { - break; + .setEUtModifier((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) + .setCustomItemOutputCalculation(currentParallel -> { + ArrayList<ItemStack> chancedOutputs = new ArrayList<>(); + for (int i = 0; i < currentParallel; i++) { + for (ItemStack item : recipe.mOutputs) { + int remainingEfficiency = getMaxEfficiency(getControllerSlot()); + while (remainingEfficiency > 0) { + if (getBaseMetaTileEntity().getRandomNumber(10000) >= remainingEfficiency) { + remainingEfficiency -= 10000; + continue; + } + chancedOutputs.add(item); + remainingEfficiency -= 10000; + } } - chancedOutputs.add(tOutput); } - remainingEfficiency -= 10000; - } - setOutputItems(chancedOutputs.toArray(new ItemStack[0])); - } - - return result; + return chancedOutputs.toArray(new ItemStack[0]); + }); } }; } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java index 8d3504a1d7..3c254cf1aa 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java @@ -70,8 +70,6 @@ import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ExoticEnergyInputHelper; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; -import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_ProcessingArray_Manager; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Recipe.GT_Recipe_Map; @@ -237,25 +235,6 @@ public class GT_MetaTileEntity_ProcessingArray extends protected ProcessingLogic createProcessingLogic() { return new ProcessingLogic() { - @Override - protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, - @Nonnull GT_OverclockCalculator calculator) { - return calculator.getDuration(); - } - - @Nonnull - @Override - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nonnull GT_ParallelHelper helper) { - return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) - .setParallel((int) Math.floor(helper.getCurrentParallel() / helper.getDurationMultiplierDouble())) - .setDuration((int) Math.ceil(recipe.mDuration * helper.getDurationMultiplierDouble())) - .setAmperage(availableAmperage) - .setEUt(availableVoltage) - .setDurationDecreasePerOC(overClockTimeReduction) - .setEUtIncreasePerOC(overClockPowerIncrease); - } - @Nonnull @Override protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { @@ -278,6 +257,7 @@ public class GT_MetaTileEntity_ProcessingArray extends GT_Recipe_Map recipeMap = getRecipeMap(); logic.setAvailableVoltage(GT_Values.V[tTier] * (recipeMap != null ? recipeMap.mAmperage : 1)); logic.setAvailableAmperage(getMaxParallel()); + logic.setAmperageOC(true); } private void setTierAndMult() { diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java index c76ac32863..2d601b9055 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java @@ -164,12 +164,8 @@ public class GT_MetaTileEntity_PyrolyseOven @NotNull @Override public CheckRecipeResult process() { - CheckRecipeResult result = super.process(); - if (!result.wasSuccessful()) { - return result; - } - duration = Math.max(duration * 2 / (1 + coilHeat.getTier()), 1); - return result; + setSpeedBonus(2f / (1 + coilHeat.getTier())); + return super.process(); } }; } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java index 54f903299e..be034dbc1f 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java @@ -43,7 +43,6 @@ import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; import gregtech.common.items.GT_IntegratedCircuit_Item; @@ -164,8 +163,7 @@ public class GT_MetaTileEntity_TranscendentPlasmaMixer @Nonnull @Override - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, - @Nonnull GT_ParallelHelper helper) { + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { return GT_OverclockCalculator.ofNoOverclock(recipe); } @@ -191,6 +189,7 @@ public class GT_MetaTileEntity_TranscendentPlasmaMixer // The voltage is only used for recipe finding logic.setAvailableVoltage(Long.MAX_VALUE); logic.setAvailableAmperage(1); + logic.setAmperageOC(false); } @Override diff --git a/src/main/java/gregtech/nei/FusionSpecialValueFormatter.java b/src/main/java/gregtech/nei/FusionSpecialValueFormatter.java index 0d5517b6f0..2129fd7233 100644 --- a/src/main/java/gregtech/nei/FusionSpecialValueFormatter.java +++ b/src/main/java/gregtech/nei/FusionSpecialValueFormatter.java @@ -28,8 +28,10 @@ public class FusionSpecialValueFormatter implements INEISpecialInfoFormatter { tier = 2; } else if (startupPower <= 40 * M * 16) { tier = 3; - } else { + } else if (startupPower <= 80 * M * 16) { tier = 4; + } else { + tier = 5; } if (voltage <= GT_Values.V[6]) { @@ -38,8 +40,10 @@ public class FusionSpecialValueFormatter implements INEISpecialInfoFormatter { tier = Math.max(tier, 2); } else if (voltage <= GT_Values.V[8]) { tier = Math.max(tier, 3); + } else if (voltage <= GT_Values.V[9]) { + tier = Math.max(tier, 4); } else { - tier = 4; + tier = 5; } return tier; } diff --git a/src/main/resources/assets/gregtech/lang/en_US.lang b/src/main/resources/assets/gregtech/lang/en_US.lang index ba2fbde364..837641d937 100644 --- a/src/main/resources/assets/gregtech/lang/en_US.lang +++ b/src/main/resources/assets/gregtech/lang/en_US.lang @@ -352,6 +352,7 @@ GT5U.gui.text.insufficient_power=§7Recipe needs more power to start. Required: GT5U.gui.text.insufficient_heat=§7Recipe needs more heat to start. Required: %s K (%s§7) GT5U.gui.text.insufficient_machine_tier=§7Recipe needs higher structure tier. Required: %s GT5U.gui.text.insufficient_startup_power=§7Recipe needs higher startup power. Required: %s +GT5U.gui.text.internal_error=§4Recipe was found, but had internal error GT5U.item.programmed_circuit.select.header=Reprogram Circuit |