diff options
author | Maxim <maxim235@gmx.de> | 2023-07-10 10:13:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-10 10:13:04 +0200 |
commit | fe0387946550f89a403b09f4e8cf6e43ee8f2e8f (patch) | |
tree | 6b56a553c2a5bbf2427a93e92724452ba5bc60f7 /src/main/java/gregtech/api/logic | |
parent | 9fe44bf0eaa55825c1c3cdf90f69aeeb668f45b1 (diff) | |
download | GT5-Unofficial-fe0387946550f89a403b09f4e8cf6e43ee8f2e8f.tar.gz GT5-Unofficial-fe0387946550f89a403b09f4e8cf6e43ee8f2e8f.tar.bz2 GT5-Unofficial-fe0387946550f89a403b09f4e8cf6e43ee8f2e8f.zip |
Generic processing logic (#2096)
* Added enumeration for check recipe result
* Rework processing logic to work with MTEs too
* Switched first few multiblocks to new checkRecipe method
* Applied generic logic to EBF
* Added support for long power base and applied generic processing logic to more machines
* Address some feedback
* Added more setter to further configure the processing logic
* Change internal checkRecipe to work with checkRecipeResult, to allow the injection of custom failure messages
* Suppress warning, change access
* Merge recipeMap and mapSupplier
* Move calls to setMetaTEController and setRecipeMap to base classes
* Make processingLogic final
* Make results non-null
* Rename `ProcessingLogic#checkRecipe` -> `#validateRecipe`
Otherwise it's confusing with `GT_MetaTileEntity_MultiBlockBase#checkRecipe`
* oops
* Added recipe locking to generic processing logic
* Rename: getWorldObject -> getIHasWorldObjectAndCoords
* Annotate missing overrides
* Renamed recipeLockableController -> recipeLockableMachine
* Migrated Cleanroom
* Migrated pyrolyse oven
* Migrated driller
* Migrated charcoal pit
* Migrated DT
* Rename: controller -> machine
* Make recipemaps override base `findRecipe` and mark others final
* Remove unused maps
* Add FindRecipeResult
* Remove IHasWorldObjectAndCoords parameter from findRecipe
This removes argument for printer recipemap to pass for GT_ModHandler.getAllRecipeOutput, but I don't think there's any mod that adds world-specific coloring recipe.
* Added method to set processing logic power so machines can override it on demand
* Restructure CheckRecipeResult, show voltage required and move package
* Reword: insufficient voltage -> power
* Change text color: dark gray -> gray
* Added findRecipeResult for insufficient heat
* Migrated PCB factory
* Fix result not being reset on shut down
* Show coil tier for heat
* clean
* Reverted migration of driller base
* Migrated TPM
* Moved getting of parallel supplier, to accomodate TPM
* Migrated power gen multiblocks
* Migrated Assembling Line
* Migrated fusion
* Migrated multi smelter
* Migrated boiler
* Migrated DTPF
* Migrated ore factory
* Migrated heat exchanger
* Make checkRecipe() final, javadoc, minor cleanup
* Fix overclock behavior with multiple hatches, javadoc, minor cleanup
* Minor fix for javadoc
* Fixed creation of OC calculator not factoring in batch mode correctly
* Make GT_ParallelHelper#setRecipe nonnull
* Rework SimpleCheckRecipeResult to not require registration
* Migrate charcoal pit and cleanroom
* Fix result not being reset when turning off machine
* Add API for BW to make recipemap sensitive to special slot on recipe search
* Migrated PA
* Migrated driller base
* Make ProcessingLogic#duration int
* Minor cleanup
* missing recipe locking for long multi
* Fix NPE
* Show crash message and turn off machine
* minor javadoc fix
* Fixed power setting for extended power base
* Integrate SingleRecipeCheck into ProcessingLogic, fix duration overflow, fix duration for batch mode, migrate PA for GT_MetaTileEntity_ExtendedPowerMultiBlockBase
* Fixed ME stocking busses
* Minor PA fixes
* Cleanup item collecting logic & apply to normal multi as well
* Oversight
* Derp
* Multiple voltage instead of amperage with recipe map amperage, since usually amperage is intended for parallel, not for recipe checking
* Fix missing EU modifiers on PCB factory OC calculator
* Removed left over OC method
* Fixed duration calculation of PCB not applying roughness multiplier
* Fixed OC parameters
* Make createOverclockCalculator nonnull & more nonnull annotations
* Fixed input processing voltage
* Round down voltage for other machines too
* Revert Nano Forge, return correct long voltage
* Use region / endregion
---------
Co-authored-by: miozune <miozune@gmail.com>
Diffstat (limited to 'src/main/java/gregtech/api/logic')
-rw-r--r-- | src/main/java/gregtech/api/logic/ProcessingLogic.java | 308 |
1 files changed, 294 insertions, 14 deletions
diff --git a/src/main/java/gregtech/api/logic/ProcessingLogic.java b/src/main/java/gregtech/api/logic/ProcessingLogic.java index fa0d285401..db97ac151f 100644 --- a/src/main/java/gregtech/api/logic/ProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java @@ -1,39 +1,89 @@ package gregtech.api.logic; +import java.util.List; +import java.util.function.Supplier; + +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.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.FindRecipeResult; +import gregtech.api.recipe.check.SingleRecipeCheck; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Recipe.GT_Recipe_Map; -public abstract class ProcessingLogic { +/** + * Logic class to calculate result of recipe check from inputs, based on recipemap. + */ +@SuppressWarnings({ "unused", "UnusedReturnValue" }) +public class ProcessingLogic { - protected GT_Recipe_Map recipeMap; + protected IVoidable machine; + protected IRecipeLockable recipeLockableMachine; + protected Supplier<GT_Recipe_Map> recipeMapSupplier; + protected GT_Recipe lastRecipe; protected ItemStack[] inputItems; protected ItemStack[] outputItems; protected ItemStack[] currentOutputItems; protected FluidStack[] inputFluids; protected FluidStack[] outputFluids; protected FluidStack[] currentOutputFluids; - protected long eut; - protected long duration; + 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 boolean isRecipeLocked; + protected int maxParallel = 1; + protected int calculatedParallels = 0; + protected Supplier<Integer> maxParallelSupplier; + protected int batchSize = 1; public ProcessingLogic() {} + // region Setters + public ProcessingLogic setInputItems(ItemStack... itemInputs) { this.inputItems = itemInputs; return this; } + public ProcessingLogic setInputItems(List<ItemStack> itemOutputs) { + this.inputItems = itemOutputs.toArray(new ItemStack[0]); + return this; + } + public ProcessingLogic setInputFluids(FluidStack... fluidInputs) { this.inputFluids = fluidInputs; return this; } + public ProcessingLogic setInputFluids(List<FluidStack> fluidInputs) { + this.inputFluids = fluidInputs.toArray(new FluidStack[0]); + return this; + } + + /** + * Overwrites item output result of the calculation. + */ public ProcessingLogic setOutputItems(ItemStack... itemOutputs) { this.outputItems = itemOutputs; return this; } + /** + * Overwrites fluid output result of the calculation. + */ public ProcessingLogic setOutputFluids(FluidStack... fluidOutputs) { this.outputFluids = fluidOutputs; return this; @@ -49,35 +99,263 @@ public abstract class ProcessingLogic { return this; } + /** + * Enables single recipe locking mode. + */ + public ProcessingLogic setRecipeLocking(IRecipeLockable recipeLockableMachine, boolean isRecipeLocked) { + this.recipeLockableMachine = recipeLockableMachine; + this.isRecipeLocked = isRecipeLocked; + return this; + } + + /** + * Sets max amount of parallel. + */ + public ProcessingLogic setMaxParallel(int maxParallel) { + this.maxParallel = maxParallel; + return this; + } + + /** + * Sets method to get max amount of parallel. + */ + public ProcessingLogic setMaxParallelSupplier(Supplier<Integer> supplier) { + this.maxParallelSupplier = supplier; + return this; + } + + /** + * Sets batch size for batch mode. + */ + public ProcessingLogic setBatchSize(int size) { + this.batchSize = size; + return this; + } + public ProcessingLogic setRecipeMap(GT_Recipe_Map recipeMap) { - this.recipeMap = recipeMap; + return setRecipeMapSupplier(() -> recipeMap); + } + + public ProcessingLogic setRecipeMapSupplier(Supplier<GT_Recipe_Map> supplier) { + this.recipeMapSupplier = supplier; + return this; + } + + /** + * Sets machine used for void protection logic. + */ + public ProcessingLogic setMachine(IVoidable machine) { + this.machine = machine; return this; } - public ProcessingLogic setDuration(long duration) { + /** + * Overwrites duration result of the calculation. + */ + public ProcessingLogic setDuration(int duration) { this.duration = duration; return this; } - public ProcessingLogic setEut(long eut) { - this.eut = eut; + /** + * Overwrites EU/t result of the calculation. + */ + public ProcessingLogic setCalculatedEut(long calculatedEut) { + this.calculatedEut = calculatedEut; + return this; + } + + /** + * 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 ProcessingLogic setAvailableVoltage(long voltage) { + availableVoltage = voltage; + return this; + } + + /** + * 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 ProcessingLogic setAvailableAmperage(long amperage) { + availableAmperage = amperage; return this; } + public ProcessingLogic setVoidProtection(boolean protectItems, boolean protectFluids) { + this.protectItems = protectItems; + this.protectFluids = protectFluids; + return this; + } + + /** + * Sets custom overclock ratio. 2/4 by default. + * Parameters represent number of bit shift, so 1 -> 2x, 2 -> 4x. + */ + public ProcessingLogic setOverclock(int timeReduction, int powerIncrease) { + this.overClockTimeReduction = timeReduction; + this.overClockPowerIncrease = powerIncrease; + return this; + } + + /** + * Sets overclock ratio to 4/4. + */ + public ProcessingLogic enablePerfectOverclock() { + return this.setOverclock(2, 2); + } + /** - * Clears everything stored in the Processing Logic other than the Recipe map used + * Clears calculated results and provided machine inputs to prepare for the next machine operation. */ public ProcessingLogic clear() { this.inputItems = null; this.inputFluids = null; this.outputItems = null; this.outputFluids = null; - this.eut = 0; + this.calculatedEut = 0; this.duration = 0; + this.calculatedParallels = 0; return this; } - public abstract boolean process(); + // endregion + + // region Logic + + /** + * Executes the recipe check: Find recipe from recipemap, Calculate parallel, overclock and outputs. + */ + @Nonnull + public CheckRecipeResult process() { + if (recipeMapSupplier == null) return CheckRecipeResultRegistry.NO_RECIPE; + + GT_Recipe_Map recipeMap = recipeMapSupplier.get(); + if (recipeMap == null) return CheckRecipeResultRegistry.NO_RECIPE; + + if (maxParallelSupplier != null) { + maxParallel = maxParallelSupplier.get(); + } + + FindRecipeResult findRecipeResult; + if (isRecipeLocked && recipeLockableMachine != null && recipeLockableMachine.getSingleRecipeCheck() != null) { + // Recipe checker is already built, we'll use it + SingleRecipeCheck singleRecipeCheck = recipeLockableMachine.getSingleRecipeCheck(); + // Validate recipe here, otherwise machine will show "not enough output space" + // even if recipe cannot be found + if (singleRecipeCheck.checkRecipeInputs(false, 1, inputItems, inputFluids) == 0) { + return CheckRecipeResultRegistry.NO_RECIPE; + } + findRecipeResult = FindRecipeResult.ofSuccess( + recipeLockableMachine.getSingleRecipeCheck() + .getRecipe()); + } else { + findRecipeResult = recipeMap + .findRecipeWithResult(lastRecipe, false, false, availableVoltage, inputFluids, null, inputItems); + } + + GT_Recipe recipe; + if (findRecipeResult.isSuccessful()) { + recipe = findRecipeResult.getRecipeNonNull(); + CheckRecipeResult result = validateRecipe(recipe); + if (!result.wasSuccessful()) { + return result; + } else { + lastRecipe = recipe; + } + } else { + if (findRecipeResult.getState() == FindRecipeResult.State.INSUFFICIENT_VOLTAGE) { + return CheckRecipeResultRegistry.insufficientPower(findRecipeResult.getRecipeNonNull().mEUt); + } else { + return CheckRecipeResultRegistry.NO_RECIPE; + } + } + + GT_ParallelHelper helper = createParallelHelper(recipe); + + helper.build(); + + if (helper.getCurrentParallel() <= 0) return CheckRecipeResultRegistry.OUTPUT_FULL; + + calculatedParallels = helper.getCurrentParallel(); + + GT_OverclockCalculator calculator = createOverclockCalculator(recipe, helper); + + calculator.calculate(); + 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; + + outputItems = helper.getItemOutputs(); + outputFluids = helper.getFluidOutputs(); + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + /** + * 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 tweak parallel logic if needed. + */ + @Nonnull + protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) { + return new GT_ParallelHelper().setRecipe(recipe) + .setItemInputs(inputItems) + .setFluidInputs(inputFluids) + .setAvailableEUt(availableVoltage * availableAmperage) + .setMachine(machine, protectItems, protectFluids) + .setRecipeLocked(recipeLockableMachine, isRecipeLocked) + .setMaxParallel(maxParallel) + .enableBatchMode(batchSize) + .enableConsumption() + .enableOutputCalculation(); + } + + /** + * Override to do additional check for finding recipe if needed, mainly for special value of the recipe. + */ + @Nonnull + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + /** + * Override to tweak overclock logic if needed. + */ + @Nonnull + 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(recipe.mDuration) + .setAmperage(availableAmperage) + .setEUt(availableVoltage) + .setDurationDecreasePerOC(overClockTimeReduction) + .setEUtIncreasePerOC(overClockPowerIncrease); + } + + // endregion + + // region Getters public ItemStack[] getOutputItems() { return outputItems; @@ -87,11 +365,13 @@ public abstract class ProcessingLogic { return outputFluids; } - public long getDuration() { + public int getDuration() { return duration; } - public long getEut() { - return eut; + public long getCalculatedEut() { + return calculatedEut; } + + // endregion } |