diff options
Diffstat (limited to 'src/main/java')
58 files changed, 2719 insertions, 2455 deletions
diff --git a/src/main/java/gregtech/api/enums/HeatingCoilLevel.java b/src/main/java/gregtech/api/enums/HeatingCoilLevel.java index f80f8139c6..f281695d5a 100644 --- a/src/main/java/gregtech/api/enums/HeatingCoilLevel.java +++ b/src/main/java/gregtech/api/enums/HeatingCoilLevel.java @@ -1,5 +1,7 @@ package gregtech.api.enums; +import javax.annotation.Nonnull; + import net.minecraft.util.StatCollector; public enum HeatingCoilLevel { @@ -32,7 +34,7 @@ public enum HeatingCoilLevel { } /** - * @return the coil tier, used for discount in the Pyrolyse Oven for example. + * @return the coil tier, used for discount in the Pyrolyse Oven for example. LV == 0 */ public byte getTier() { return (byte) (this.ordinal() - 2); @@ -52,16 +54,43 @@ public enum HeatingCoilLevel { return 1 << Math.max(0, this.ordinal() - 5); } + /** + * @return Translated name of this coil + */ public String getName() { return StatCollector.translateToLocal("GT5U.coil." + this); } + @Nonnull public static HeatingCoilLevel getFromTier(byte tier) { if (tier < 0 || tier > getMaxTier()) return HeatingCoilLevel.None; return VALUES[tier + 2]; } + /** + * @param applyColor Whether to apply tiered color + * @return Translated coil name. Heat exceeding MAX is represented as "Eternal+". + */ + @Nonnull + public static String getDisplayNameFromHeat(int heat, boolean applyColor) { + for (HeatingCoilLevel heatLevel : VALUES) { + if (heatLevel == HeatingCoilLevel.None || heatLevel == HeatingCoilLevel.ULV) continue; + if (heatLevel.getHeat() >= heat) { + String name = heatLevel.getName(); + if (applyColor) { + name = GT_Values.TIER_COLORS[heatLevel.getTier() + 1] + name; + } + return name; + } + } + String name = HeatingCoilLevel.MAX.getName() + "+"; + if (applyColor) { + name = GT_Values.TIER_COLORS[HeatingCoilLevel.MAX.getTier() + 1] + name; + } + return name; + } + public static int size() { return VALUES.length; } diff --git a/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java b/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java index 9a60092121..7b29f185c6 100644 --- a/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java +++ b/src/main/java/gregtech/api/interfaces/metatileentity/IMetaTileEntity.java @@ -298,8 +298,7 @@ public interface IMetaTileEntity extends ISidedInventory, IFluidTank, IFluidHand void receiveClientEvent(byte aEventID, byte aValue); /** - * Called to actually play the Sound. Do not insert Client/Server checks. That is already done for you. Do not - * use @playSoundEffect, Minecraft doesn't like that at all. Use @playSound instead. + * Called to actually play the sound on client side. Client/Server check is already done. */ void doSound(byte aIndex, double aX, double aY, double aZ); diff --git a/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java b/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java index 9f862e254d..3d4ed80f67 100644 --- a/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java +++ b/src/main/java/gregtech/api/interfaces/modularui/ControllerWithOptionalFeatures.java @@ -20,6 +20,7 @@ import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; import gregtech.api.enums.SoundResource; import gregtech.api.enums.VoidingMode; import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.tileentity.IRecipeLockable; import gregtech.api.interfaces.tileentity.IVoidable; /** @@ -33,7 +34,7 @@ import gregtech.api.interfaces.tileentity.IVoidable; * <li>Recipe locking</li> * </ul> */ -public interface ControllerWithOptionalFeatures extends IVoidable { +public interface ControllerWithOptionalFeatures extends IVoidable, IRecipeLockable { boolean isAllowedToWork(); @@ -233,22 +234,6 @@ public interface ControllerWithOptionalFeatures extends IVoidable { return (ButtonWidget) button; } - /** - * Override this if you are a multi-block that has added support for single recipe locking. - */ - boolean supportsSingleRecipeLocking(); - - /** - * @return true if recipe locking is enabled, else false. This is getter is used for displaying the icon in the GUI - */ - boolean isRecipeLockingEnabled(); - - void setRecipeLocking(boolean enabled); - - default boolean getDefaultRecipeLockingMode() { - return false; - } - Pos2d getRecipeLockingButtonPos(); default ButtonWidget createLockToSingleRecipeButton(IWidgetBuilder<?> builder) { diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IHasWorldObjectAndCoords.java b/src/main/java/gregtech/api/interfaces/tileentity/IHasWorldObjectAndCoords.java index 64d206aff7..6d81d5c401 100644 --- a/src/main/java/gregtech/api/interfaces/tileentity/IHasWorldObjectAndCoords.java +++ b/src/main/java/gregtech/api/interfaces/tileentity/IHasWorldObjectAndCoords.java @@ -136,8 +136,9 @@ public interface IHasWorldObjectAndCoords { boolean isDead(); /** - * Sends a Block Event to the Client TileEntity, the byte Parameters are only for validation as Minecraft doesn't - * properly write Packet Data. + * Sends a Block Event to the Client TileEntity. + * + * @param aValue value to sync */ void sendBlockEvent(byte aID, byte aValue); diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java b/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java new file mode 100644 index 0000000000..f793221a50 --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/tileentity/IRecipeLockable.java @@ -0,0 +1,34 @@ +package gregtech.api.interfaces.tileentity; + +import gregtech.api.recipe.check.SingleRecipeCheck; +import gregtech.api.util.GT_Recipe; + +/** + * Machines implementing this interface can have logic to lock to a single recipe. + */ +public interface IRecipeLockable { + + /** + * @return if this machine supports single recipe locking. + */ + boolean supportsSingleRecipeLocking(); + + /** + * @return true if recipe locking is enabled, else false. This is getter is used for displaying the icon in the GUI + */ + boolean isRecipeLockingEnabled(); + + void setRecipeLocking(boolean enabled); + + default boolean getDefaultRecipeLockingMode() { + return false; + } + + default SingleRecipeCheck getSingleRecipeCheck() { + return null; + } + + default void setSingleRecipeCheck(SingleRecipeCheck recipeCheck) {} + + GT_Recipe.GT_Recipe_Map getRecipeMap(); +} 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 } diff --git a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java index a23fbd8a85..72ca9f9124 100644 --- a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java @@ -595,6 +595,12 @@ public class BaseMetaTileEntity extends CommonMetaTileEntity } catch (Throwable e) { e.printStackTrace(); e.printStackTrace(GT_Log.err); + try { + mMetaTileEntity.onTickFail(this, mTickTimer); + } catch (Throwable ex) { + ex.printStackTrace(); + ex.printStackTrace(GT_Log.err); + } } if (aSideServer && hasValidMetaTileEntity()) { @@ -1020,6 +1026,9 @@ public class BaseMetaTileEntity extends CommonMetaTileEntity @Override public void disableWorking() { mWorks = false; + if (hasValidMetaTileEntity()) { + mMetaTileEntity.onDisableWorking(); + } } @Override @@ -1060,6 +1069,9 @@ public class BaseMetaTileEntity extends CommonMetaTileEntity @Override public void setActive(boolean aActive) { mActive = aActive; + if (hasValidMetaTileEntity()) { + mMetaTileEntity.onSetActive(aActive); + } } @Override diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index 453849923d..1ac42a2ea1 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -319,6 +319,12 @@ public abstract class MetaTileEntity implements IMetaTileEntity, ICleanroomRecei } } + public void onTickFail(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {} + + public void onSetActive(boolean active) {} + + public void onDisableWorking() {} + @Override public void inValidate() { /* Do nothing */ diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java index f251b5c02f..ac037b7919 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java @@ -69,6 +69,7 @@ import gregtech.api.interfaces.modularui.IAddGregtechLogo; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.check.FindRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ClientPreference; import gregtech.api.util.GT_CoverBehaviorBase; @@ -1085,15 +1086,24 @@ public abstract class GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_B public int checkRecipe(boolean skipOC) { GT_Recipe_Map tMap = getRecipeList(); if (tMap == null) return DID_NOT_FIND_RECIPE; - GT_Recipe tRecipe = tMap.findRecipe( - getBaseMetaTileEntity(), + FindRecipeResult result = tMap.findRecipeWithResult( mLastRecipe, false, + false, V[mTier], new FluidStack[] { getFillableStack() }, getSpecialSlot(), getAllInputs()); - if (tRecipe == null) return DID_NOT_FIND_RECIPE; + if (result.getState() == FindRecipeResult.State.EXPLODE && getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().doExplosion(V[mTier] * 4); + return DID_NOT_FIND_RECIPE; + } + if (result.getState() == FindRecipeResult.State.ON_FIRE && getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().setOnFire(); + return DID_NOT_FIND_RECIPE; + } + if (!result.isSuccessful()) return DID_NOT_FIND_RECIPE; + GT_Recipe tRecipe = result.getRecipeNonNull(); if (GT_Mod.gregtechproxy.mLowGravProcessing && (tRecipe.mSpecialValue == -100 || tRecipe.mSpecialValue == -300) && !isValidForLowGravity(tRecipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) 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 47dd69ba6c..ef3f587c01 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 @@ -5,6 +5,8 @@ import static gregtech.api.enums.GT_Values.VN; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; + import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -14,6 +16,9 @@ import net.minecraft.util.StatCollector; import net.minecraft.world.World; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_ExoticEnergyInputHelper; import gregtech.api.util.GT_Utility; @@ -127,6 +132,70 @@ public abstract class GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T extends GT } @Override + public @Nonnull CheckRecipeResult checkProcessing() { + // If no logic is found, try legacy checkRecipe + if (processingLogic == null) { + // noinspection deprecation + return checkRecipe(mInventory[1]) ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; + } + + CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE; + + processingLogic.clear(); + processingLogic.setMachine(this); + processingLogic.setRecipeMapSupplier(this::getRecipeMap); + processingLogic.setVoidProtection(protectsExcessItem(), protectsExcessFluid()); + processingLogic.setBatchSize(isBatchModeEnabled() ? getMaxBatchSize() : 1); + processingLogic.setRecipeLocking(this, isRecipeLockingEnabled()); + processingLogic.setInputFluids(getStoredFluids()); + setProcessingLogicPower(processingLogic); + if (isInputSeparationEnabled()) { + for (GT_MetaTileEntity_Hatch_InputBus bus : mInputBusses) { + List<ItemStack> inputItems = new ArrayList<>(); + for (int i = bus.getSizeInventory() - 1; i >= 0; i--) { + ItemStack stored = bus.getStackInSlot(i); + if (stored != null) { + inputItems.add(stored); + } + } + processingLogic.setInputItems(inputItems.toArray(new ItemStack[0])); + result = processingLogic.process(); + if (result.wasSuccessful()) break; + } + } else { + processingLogic.setInputItems(getStoredInputs()); + result = processingLogic.process(); + } + + // inputs are consumed by `process()` + updateSlots(); + + if (!result.wasSuccessful()) return result; + + mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + mEfficiencyIncrease = 10000; + + lEUt = processingLogic.getCalculatedEut(); + mMaxProgresstime = processingLogic.getDuration(); + + if (lEUt > 0) { + lEUt = (-lEUt); + } + + mOutputItems = processingLogic.getOutputItems(); + mOutputFluids = processingLogic.getOutputFluids(); + + return result; + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(GT_Utility.roundDownVoltage(getAverageInputVoltage())); + logic.setAvailableAmperage(getMaxInputAmps()); + } + + @Override public String[] getInfoData() { int mPollutionReduction = 0; for (GT_MetaTileEntity_Hatch_Muffler tHatch : mMufflerHatches) { 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 1c93779f01..0d383bc768 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 @@ -30,10 +30,12 @@ import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.TestOnly; import org.lwjgl.input.Keyboard; import com.google.common.collect.Iterables; +import com.gtnewhorizons.modularui.api.math.Alignment; import com.gtnewhorizons.modularui.api.math.Pos2d; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; @@ -60,26 +62,28 @@ import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.modularui.IBindPlayerInventoryUI; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SingleRecipeCheck; import gregtech.api.util.GT_ExoticEnergyInputHelper; import gregtech.api.util.GT_Log; -import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_ParallelHelper; import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Recipe.GT_Recipe_Map; -import gregtech.api.util.GT_Single_Recipe_Check; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import gregtech.api.util.OutputHatchWrapper; import gregtech.api.util.VoidProtectionHelper; import gregtech.client.GT_SoundLoop; import gregtech.common.GT_Pollution; +import gregtech.common.gui.modularui.widget.CheckRecipeResultSyncer; import gregtech.common.items.GT_MetaGenerated_Tool_01; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; -import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_DrillerBase; import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_LargeTurbine; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; @@ -105,11 +109,14 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity protected boolean inputSeparation = getDefaultInputSeparationMode(); protected VoidingMode voidingMode = getDefaultVoidingMode(); protected boolean batchMode = getDefaultBatchMode(); + private @Nonnull CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.NONE; + private boolean isScheduledForResetCheckRecipeResult; + protected static final String INPUT_SEPARATION_NBT_KEY = "inputSeparation"; protected static final String VOID_EXCESS_NBT_KEY = "voidExcess"; protected static final String VOIDING_MODE_NBT_KEY = "voidingMode"; protected static final String BATCH_MODE_NBT_KEY = "batchMode"; - public GT_Single_Recipe_Check mSingleRecipeCheck = null; + protected SingleRecipeCheck mSingleRecipeCheck = null; public ArrayList<GT_MetaTileEntity_Hatch_Input> mInputHatches = new ArrayList<>(); public ArrayList<GT_MetaTileEntity_Hatch_Output> mOutputHatches = new ArrayList<>(); @@ -120,6 +127,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public ArrayList<GT_MetaTileEntity_Hatch_Energy> mEnergyHatches = new ArrayList<>(); public ArrayList<GT_MetaTileEntity_Hatch_Maintenance> mMaintenanceHatches = new ArrayList<>(); protected List<GT_MetaTileEntity_Hatch> mExoticEnergyHatches = new ArrayList<>(); + protected final ProcessingLogic processingLogic; @SideOnly(Side.CLIENT) protected GT_SoundLoop activitySoundLoop; @@ -130,6 +138,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public GT_MetaTileEntity_MultiBlockBase(int aID, String aName, String aNameRegional) { super(aID, aName, aNameRegional, 2); + this.processingLogic = null; GT_MetaTileEntity_MultiBlockBase.disableMaintenance = GregTech_API.sMachineFile .get(ConfigCategories.machineconfig, "MultiBlockMachines.disableMaintenance", false); this.damageFactorLow = GregTech_API.sMachineFile @@ -141,6 +150,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public GT_MetaTileEntity_MultiBlockBase(String aName) { super(aName, 2); + this.processingLogic = createProcessingLogic(); GT_MetaTileEntity_MultiBlockBase.disableMaintenance = GregTech_API.sMachineFile .get(ConfigCategories.machineconfig, "MultiBlockMachines.disableMaintenance", false); this.damageFactorLow = GregTech_API.sMachineFile @@ -273,7 +283,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity if (supportsSingleRecipeLocking()) { mLockedToSingleRecipe = aNBT.getBoolean("mLockedToSingleRecipe"); if (mLockedToSingleRecipe && aNBT.hasKey("mSingleRecipeCheck", Constants.NBT.TAG_COMPOUND)) { - GT_Single_Recipe_Check c = loadSingleRecipeChecker(aNBT.getCompoundTag("mSingleRecipeCheck")); + SingleRecipeCheck c = loadSingleRecipeChecker(aNBT.getCompoundTag("mSingleRecipeCheck")); if (c != null) mSingleRecipeCheck = c; // the old recipe is gone. we disable the machine to prevent making garbage in case of shared inputs // maybe use a better way to inform player in the future. @@ -311,8 +321,8 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity mCrowbar = aNBT.getBoolean("mCrowbar"); } - protected GT_Single_Recipe_Check loadSingleRecipeChecker(NBTTagCompound aNBT) { - return GT_Single_Recipe_Check.tryLoad(this, aNBT); + protected SingleRecipeCheck loadSingleRecipeChecker(NBTTagCompound aNBT) { + return SingleRecipeCheck.tryLoad(getRecipeMap(), aNBT); } @Override @@ -411,6 +421,17 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } } + @Override + public void onTickFail(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onTickFail(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide()) { + aBaseMetaTileEntity.disableWorking(); + checkRecipeResult = CheckRecipeResultRegistry.CRASH; + // Don't let `onSetActive` to overwrite + isScheduledForResetCheckRecipeResult = false; + } + } + private void checkMaintenance() { if (disableMaintenance) { mWrench = true; @@ -444,14 +465,26 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } } - protected boolean checkRecipe() { + /** + * Starts checking recipe with some operations needed to actually run the check. Overriding this without due care + * may result in dupe of items, hence it's marked as final. + * <p> + * See {@link #createProcessingLogic()} or {@link #checkProcessing()} for what you want to override. + * + * @return If successfully found recipe and/or started processing + */ + protected final boolean checkRecipe() { startRecipeProcessing(); - boolean result = checkRecipe(mInventory[1]); - if (result && getProcessStartSound() != null) { - sendLoopStart(PROCESS_START_SOUND_INDEX); + CheckRecipeResult result = checkProcessing(); + if (!CheckRecipeResultRegistry.isRegistered(result.getID())) { + throw new RuntimeException(String.format("Result %s is not registered for registry", result.getID())); + } + if (result.wasSuccessful()) { + sendStartMultiBlockSoundLoop(); } + this.checkRecipeResult = result; endRecipeProcessing(); - return result; + return result.wasSuccessful(); } private boolean shouldCheckRecipeThisTick(long aTick) { @@ -544,6 +577,12 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return mPollution < 10000; } + protected void sendStartMultiBlockSoundLoop() { + if (getProcessStartSound() != null) { + sendLoopStart(PROCESS_START_SOUND_INDEX); + } + } + @Override public void doSound(byte aIndex, double aX, double aY, double aZ) { super.doSound(aIndex, aX, aY, aZ); @@ -631,9 +670,86 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity public abstract boolean isCorrectMachinePart(ItemStack aStack); /** - * Checks the Recipe + * @deprecated Use {@link #createProcessingLogic()} or {@link #checkProcessing()} + */ + @Deprecated + public boolean checkRecipe(ItemStack aStack) { + return false; + } + + /** + * Checks recipe and setup machine if it's successful. + * <p> + * For generic machine working with recipemap, use {@link #createProcessingLogic()} to make use of shared codebase. */ - public abstract boolean checkRecipe(ItemStack aStack); + @Nonnull + public CheckRecipeResult checkProcessing() { + // If no logic is found, try legacy checkRecipe + if (processingLogic == null) { + return checkRecipe(mInventory[1]) ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; + } + + CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE; + + processingLogic.clear(); + processingLogic.setMachine(this); + processingLogic.setRecipeMapSupplier(this::getRecipeMap); + processingLogic.setVoidProtection(protectsExcessItem(), protectsExcessFluid()); + processingLogic.setBatchSize(isBatchModeEnabled() ? getMaxBatchSize() : 1); + processingLogic.setRecipeLocking(this, isRecipeLockingEnabled()); + processingLogic.setInputFluids(getStoredFluids()); + setProcessingLogicPower(processingLogic); + if (isInputSeparationEnabled()) { + for (GT_MetaTileEntity_Hatch_InputBus bus : mInputBusses) { + List<ItemStack> inputItems = new ArrayList<>(); + for (int i = bus.getSizeInventory() - 1; i >= 0; i--) { + ItemStack stored = bus.getStackInSlot(i); + if (stored != null) { + inputItems.add(stored); + } + } + processingLogic.setInputItems(inputItems.toArray(new ItemStack[0])); + result = processingLogic.process(); + if (result.wasSuccessful()) break; + } + } else { + processingLogic.setInputItems(getStoredInputs()); + result = processingLogic.process(); + } + + // inputs are consumed by `process()` + updateSlots(); + + if (!result.wasSuccessful()) return result; + + mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + mEfficiencyIncrease = 10000; + + if (processingLogic.getCalculatedEut() > Integer.MAX_VALUE) { + return CheckRecipeResultRegistry.POWER_OVERFLOW; + } + mEUt = (int) processingLogic.getCalculatedEut(); + mMaxProgresstime = processingLogic.getDuration(); + + if (mEUt > 0) { + mEUt = (-mEUt); + } + + mOutputItems = processingLogic.getOutputItems(); + mOutputFluids = processingLogic.getOutputFluids(); + + return result; + } + + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(GT_Utility.roundDownVoltage(getMaxInputVoltage())); + logic.setAvailableAmperage(1); + } + + protected int getMaxBatchSize() { + return 128; + } /** * Checks the Machine. You have to assign the MetaTileEntities for the Hatches here. @@ -678,6 +794,7 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity mMaxProgresstime = 0; mEfficiencyIncrease = 0; getBaseMetaTileEntity().disableWorking(); + checkRecipeResult = CheckRecipeResultRegistry.NONE; } public void criticalStopMachine() { @@ -839,6 +956,9 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return injected > 0; } + /** + * Sums up voltage of energy hatches. Amperage does not matter. + */ public long getMaxInputVoltage() { long rVoltage = 0; for (GT_MetaTileEntity_Hatch_Energy tHatch : mEnergyHatches) @@ -847,6 +967,21 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return rVoltage; } + /** + * Sums up max input EU/t of energy hatches, amperage included. + */ + public long getMaxInputPower() { + long eut = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : mEnergyHatches) if (isValidMetaTileEntity(tHatch)) { + IGregTechTileEntity baseTile = tHatch.getBaseMetaTileEntity(); + eut += baseTile.getInputVoltage() * baseTile.getInputAmperage(); + } + return eut; + } + + /** + * Returns voltage tier of energy hatches. If multiple tiers are found, returns 0. + */ public long getInputVoltageTier() { long rTier = 0; if (mEnergyHatches.size() > 0) { @@ -1130,10 +1265,21 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity return rList; } + @Override public GT_Recipe_Map getRecipeMap() { return null; } + /** + * Creates logic to run recipe check based on recipemap. This runs only once, on class instantiation. + * <p> + * If this machine doesn't use recipemap or does some complex things, override {@link #checkProcessing()}. + */ + @ApiStatus.OverrideOnly + protected ProcessingLogic createProcessingLogic() { + return null; + } + public void updateSlots() { for (GT_MetaTileEntity_Hatch_Input tHatch : mInputHatches) if (isValidMetaTileEntity(tHatch)) tHatch.updateSlots(); @@ -1523,6 +1669,20 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity } } + @Override + public void onSetActive(boolean active) { + if (isScheduledForResetCheckRecipeResult && !active) { + checkRecipeResult = CheckRecipeResultRegistry.NONE; + isScheduledForResetCheckRecipeResult = false; + } + } + + @Override + public void onDisableWorking() { + // This prevents deleting result instantly when turning off machine + isScheduledForResetCheckRecipeResult = true; + } + protected void setMufflers(boolean state) { for (GT_MetaTileEntity_Hatch_Muffler aMuffler : mMufflerHatches) { final IGregTechTileEntity iGTTileEntity = aMuffler.getBaseMetaTileEntity(); @@ -1614,17 +1774,25 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity @Override public boolean isAllowedToWork() { - return getBaseMetaTileEntity().isAllowedToWork(); + return getBaseMetaTileEntity() != null && getBaseMetaTileEntity().isAllowedToWork(); } @Override public void disableWorking() { - getBaseMetaTileEntity().disableWorking(); + if (getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().disableWorking(); + } } @Override public void enableWorking() { - getBaseMetaTileEntity().enableWorking(); + if (getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().enableWorking(); + } + } + + public ItemStack getControllerSlot() { + return mInventory[1]; } @Override @@ -1764,7 +1932,20 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity @Override public void setRecipeLocking(boolean enabled) { - this.mLockedToSingleRecipe = enabled; + mLockedToSingleRecipe = enabled; + if (!enabled) { + setSingleRecipeCheck(null); + } + } + + @Override + public void setSingleRecipeCheck(SingleRecipeCheck recipeCheck) { + mSingleRecipeCheck = recipeCheck; + } + + @Override + public SingleRecipeCheck getSingleRecipeCheck() { + return mSingleRecipeCheck; } @Override @@ -1889,22 +2070,17 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity new TextWidget(GT_Utility.trans("142", "Running perfectly.")).setDefaultColor(COLOR_TEXT_WHITE.get()) .setEnabled( widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 && getBaseMetaTileEntity().isActive())); - screenElements.widget( - new TextWidget(GT_Utility.trans("143", "Missing Mining Pipe")).setDefaultColor(COLOR_TEXT_WHITE.get()) - .setEnabled(widget -> { - if (getBaseMetaTileEntity().getErrorDisplayID() == 0 - && this instanceof GT_MetaTileEntity_DrillerBase) { - final ItemStack tItem = inventorySlot.getMcSlot() - .getStack(); - return tItem == null - || !GT_Utility.areStacksEqual(tItem, GT_ModHandler.getIC2Item("miningPipe", 1L)); - } - return false; - })); + TextWidget.dynamicString(() -> checkRecipeResult.getDisplayString()) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> GT_Utility.isStringValid(checkRecipeResult.getDisplayString()))) + .widget(new CheckRecipeResultSyncer(() -> checkRecipeResult, (result) -> checkRecipeResult = result)); + screenElements.widget( new TextWidget(GT_Utility.trans("144", "Missing Turbine Rotor")).setDefaultColor(COLOR_TEXT_WHITE.get()) .setEnabled(widget -> { + if (getBaseMetaTileEntity().isAllowedToWork()) return false; if (getBaseMetaTileEntity().getErrorDisplayID() == 0 && this instanceof GT_MetaTileEntity_LargeTurbine) { final ItemStack tItem = inventorySlot.getMcSlot() diff --git a/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java index 61adafce13..b8ac727a91 100644 --- a/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java +++ b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java @@ -42,6 +42,7 @@ import gregtech.api.multitileentity.MultiTileEntityRegistry; import gregtech.api.multitileentity.base.TickableMultiTileEntity; import gregtech.api.multitileentity.interfaces.IMultiTileMachine; import gregtech.api.net.GT_Packet_MultiTileEntity; +import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Utility; import gregtech.client.GT_SoundLoop; @@ -539,17 +540,17 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } ProcessingLogic logic = ((ProcessingLogicHost) this).getProcessingLogic(); logic.clear(); - boolean result = logic.setInputItems(getInputItems()) + CheckRecipeResult result = logic.setInputItems(getInputItems()) .setInputFluids(getInputFluids()) .setCurrentOutputItems( outputInventory.getStacks() .toArray(new ItemStack[0])) .process(); setDuration(logic.getDuration()); - setEut(logic.getEut()); + setEut(logic.getCalculatedEut()); setItemOutputs(logic.getOutputItems()); setFluidOutputs(logic.getOutputFluids()); - return result; + return result.wasSuccessful(); } /** diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java index b96a822e4b..cdefa21e71 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java @@ -95,7 +95,10 @@ import gregtech.api.multitileentity.machine.MultiTileBasicMachine; import gregtech.api.multitileentity.multiblock.casing.FunctionalCasing; import gregtech.api.multitileentity.multiblock.casing.UpgradeCasing; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import gregtech.common.tileentities.casings.upgrade.Inventory; @@ -1675,7 +1678,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } ProcessingLogic logic = ((ProcessingLogicHost) this).getProcessingLogic(); logic.clear(); - boolean result = false; + CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE; if (isSeparateInputs()) { // TODO: Add separation with fluids for (Pair<ItemStack[], String> inventory : getItemInputsForEachInventory()) { @@ -1684,7 +1687,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic result = logic.setInputItems(inventory.getLeft()) .setCurrentOutputItems(getOutputItems()) .process(); - if (result) { + if (result.wasSuccessful()) { inventoryName = inventory.getRight(); break; } @@ -1698,10 +1701,10 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic .process(); } setDuration(logic.getDuration()); - setEut(logic.getEut()); + setEut(logic.getCalculatedEut()); setItemOutputs(logic.getOutputItems()); setFluidOutputs(logic.getOutputFluids()); - return result; + return result.wasSuccessful(); } public IItemHandlerModifiable getOutputInventory() { @@ -2067,6 +2070,11 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override + public GT_Recipe.GT_Recipe_Map getRecipeMap() { + return null; + } + + @Override public Pos2d getRecipeLockingButtonPos() { return new Pos2d(0, 0); } diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java new file mode 100644 index 0000000000..ab1db6ecd2 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java @@ -0,0 +1,42 @@ +package gregtech.api.recipe.check; + +import net.minecraft.network.PacketBuffer; + +/** + * Class to indicate the result of recipe check in the machine. It doesn't need to be actual result of recipemap check, + * but can also be status of whether to start the machine. Examples can be found at {@link CheckRecipeResultRegistry}. + * <p> + * Sample instance must be registered to {@link CheckRecipeResultRegistry}. + */ +public interface CheckRecipeResult { + + /** + * @return Unique registry ID + */ + String getID(); + + /** + * @return If recipe check is successful + */ + boolean wasSuccessful(); + + /** + * @return Actual text to show on client GUI + */ + String getDisplayString(); + + /** + * Create new instance to receive packet. + */ + CheckRecipeResult newInstance(); + + /** + * Encode value to sync. + */ + void encode(PacketBuffer buffer); + + /** + * Decode synced value. + */ + void decode(PacketBuffer buffer); +} diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java new file mode 100644 index 0000000000..26f9dedd7d --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java @@ -0,0 +1,111 @@ +package gregtech.api.recipe.check; + +import java.util.HashMap; +import java.util.Map; + +public final class CheckRecipeResultRegistry { + + private static final Map<String, CheckRecipeResult> registry = new HashMap<>(); + + /** + * Registers CheckRecipeResult. No duplicated IDs are allowed. + * + * @param sample Sample object to register + */ + public static void register(CheckRecipeResult sample) { + if (isRegistered(sample.getID())) { + throw new IllegalStateException( + String.format( + "ID %s is already registered for %s", + sample.getID(), + registry.get(sample.getID()) + .getClass() + .getCanonicalName())); + } + registry.put(sample.getID(), sample); + } + + public static CheckRecipeResult getSampleFromRegistry(String id) { + if (!isRegistered(id)) { + throw new RuntimeException("Unknown id: " + id); + } + return registry.get(id); + } + + public static boolean isRegistered(String id) { + return registry.containsKey(id); + } + + /** + * Successfully found recipe. + */ + public static final CheckRecipeResult SUCCESSFUL = SimpleCheckRecipeResult.ofSuccess("success"); + /** + * All requirements met to generator power. + */ + public static final CheckRecipeResult GENERATING = SimpleCheckRecipeResult.ofSuccess("generating"); + /** + * Cannot find recipe. + */ + public static final CheckRecipeResult NO_RECIPE = SimpleCheckRecipeResult.ofFailure("no_recipe"); + /** + * Cannot process recipe because output is full. + */ + public static final CheckRecipeResult OUTPUT_FULL = SimpleCheckRecipeResult.ofFailure("output_full"); + /** + * Default unknown state. + */ + public static final CheckRecipeResult NONE = SimpleCheckRecipeResult.ofFailure("none"); + /** + * Code crashed. + */ + public static final CheckRecipeResult CRASH = SimpleCheckRecipeResult.ofFailure("crash"); + /** + * Cannot find valid fuel for generator. + */ + public static final CheckRecipeResult NO_FUEL_FOUND = SimpleCheckRecipeResult.ofFailure("no_fuel"); + /** + * Cannot find valid turbine. + */ + public static final CheckRecipeResult NO_TURBINE_FOUND = SimpleCheckRecipeResult.ofFailure("no_turbine"); + /** + * No data sticks found for Assembly Line. + */ + public static final CheckRecipeResult NO_DATA_STICKS = SimpleCheckRecipeResult.ofFailure("no_data_sticks"); + /** + * EU/t overflowed. + */ + public static final CheckRecipeResult POWER_OVERFLOW = SimpleCheckRecipeResult.ofFailure("power_overflow"); + /** + * Progress time overflowed. + */ + public static final CheckRecipeResult DURATION_OVERFLOW = SimpleCheckRecipeResult.ofFailure("duration_overflow"); + + /** + * Cannot process recipe because the machine cannot handle required EUt. + */ + public static CheckRecipeResult insufficientPower(long required) { + return new ResultInsufficientPower(required); + } + + /** + * Cannot process recipe because the machine cannot handle its heat. + */ + public static CheckRecipeResult insufficientHeat(int required) { + return new ResultInsufficientHeat(required); + } + + /** + * Cannot process recipe because the machine is tiered and its tier is too low. + */ + public static CheckRecipeResult insufficientMachineTier(int required) { + return new ResultInsufficientMachineTier(required); + } + + static { + register(new SimpleCheckRecipeResult(false, "")); + register(new ResultInsufficientPower(0)); + register(new ResultInsufficientHeat(0)); + register(new ResultInsufficientMachineTier(0)); + } +} diff --git a/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java b/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java new file mode 100644 index 0000000000..5791cb05e1 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/FindRecipeResult.java @@ -0,0 +1,107 @@ +package gregtech.api.recipe.check; + +import java.util.Objects; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import gregtech.api.util.GT_Recipe; + +/** + * Wrapper class to get result of recipe search for recipemap. Note that this only validates recipe input and voltage, + * and does not involve in actual check in the machine such as output space or special value. + */ +public class FindRecipeResult { + + @Nonnull + private final State state; + @Nullable + private final GT_Recipe recipe; + + private FindRecipeResult(@Nonnull State state, @Nullable GT_Recipe recipe) { + this.state = state; + this.recipe = recipe; + } + + @Nonnull + public State getState() { + return state; + } + + public boolean isSuccessful() { + return state.success; + } + + /** + * If you already checked {@link #isSuccessful()}, you can use {@link #getRecipeNonNull()} instead. + */ + @Nullable + public GT_Recipe getRecipe() { + return recipe; + } + + /** + * You should use this ONLY WHEN state == FOUND or INSUFFICIENT_VOLTAGE. + */ + @Nonnull + public GT_Recipe getRecipeNonNull() { + return Objects.requireNonNull(recipe); + } + + /** + * Successfully found recipe. + */ + public static FindRecipeResult ofSuccess(@Nonnull GT_Recipe recipe) { + return new FindRecipeResult(State.FOUND, Objects.requireNonNull(recipe)); + } + + /** + * Recipe was found, but voltage is not sufficient to run. + */ + public static FindRecipeResult ofInsufficientVoltage(@Nonnull GT_Recipe recipe) { + return new FindRecipeResult(State.INSUFFICIENT_VOLTAGE, Objects.requireNonNull(recipe)); + } + + /** + * No recipe found. + */ + public static final FindRecipeResult NOT_FOUND = new FindRecipeResult(State.NOT_FOUND, null); + /** + * For Microwave. + */ + public static final FindRecipeResult EXPLODE = new FindRecipeResult(State.EXPLODE, null); + /** + * For Microwave. + */ + public static final FindRecipeResult ON_FIRE = new FindRecipeResult(State.ON_FIRE, null); + + public enum State { + + /** + * Successfully found recipe. + */ + FOUND(true), + /** + * Recipe was found, but voltage is not sufficient to run. + */ + INSUFFICIENT_VOLTAGE(false), + /** + * No recipe found. + */ + NOT_FOUND(false), + /** + * For Microwave. + */ + EXPLODE(false), + /** + * For Microwave. + */ + ON_FIRE(false); + + private final boolean success; + + State(boolean success) { + this.success = success; + } + } +} diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java new file mode 100644 index 0000000000..96c8955130 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java @@ -0,0 +1,57 @@ +package gregtech.api.recipe.check; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.StatCollector; + +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.util.GT_Utility; + +public class ResultInsufficientHeat implements CheckRecipeResult { + + private int required; + + ResultInsufficientHeat(int required) { + this.required = required; + } + + @Override + public String getID() { + return "insufficient_heat"; + } + + @Override + public boolean wasSuccessful() { + return false; + } + + @Override + public String getDisplayString() { + return StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_heat", + GT_Utility.formatNumbers(required), + HeatingCoilLevel.getDisplayNameFromHeat(required, true)); + } + + @Override + public CheckRecipeResult newInstance() { + return new ResultInsufficientHeat(0); + } + + @Override + public void encode(PacketBuffer buffer) { + buffer.writeVarIntToBuffer(required); + } + + @Override + public void decode(PacketBuffer buffer) { + required = buffer.readVarIntFromBuffer(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResultInsufficientHeat that = (ResultInsufficientHeat) o; + return required == that.required; + } +} diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java new file mode 100644 index 0000000000..1e00e791d1 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java @@ -0,0 +1,54 @@ +package gregtech.api.recipe.check; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.StatCollector; + +import gregtech.api.util.GT_Utility; + +public class ResultInsufficientMachineTier implements CheckRecipeResult { + + private int required; + + ResultInsufficientMachineTier(int required) { + this.required = required; + } + + @Override + public String getID() { + return "insufficient_machine_tier"; + } + + @Override + public boolean wasSuccessful() { + return false; + } + + @Override + public String getDisplayString() { + return StatCollector + .translateToLocalFormatted("GT5U.gui.text.insufficient_machine_tier", GT_Utility.formatNumbers(required)); + } + + @Override + public CheckRecipeResult newInstance() { + return new ResultInsufficientMachineTier(0); + } + + @Override + public void encode(PacketBuffer buffer) { + buffer.writeVarIntToBuffer(required); + } + + @Override + public void decode(PacketBuffer buffer) { + required = buffer.readVarIntFromBuffer(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResultInsufficientMachineTier that = (ResultInsufficientMachineTier) o; + return required == that.required; + } +} diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java new file mode 100644 index 0000000000..ca6b31ccef --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java @@ -0,0 +1,56 @@ +package gregtech.api.recipe.check; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.StatCollector; + +import gregtech.api.util.GT_Utility; + +public class ResultInsufficientPower implements CheckRecipeResult { + + private long required; + + ResultInsufficientPower(long required) { + this.required = required; + } + + @Override + public String getID() { + return "insufficient_power"; + } + + @Override + public boolean wasSuccessful() { + return false; + } + + @Override + public String getDisplayString() { + return StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_power", + GT_Utility.formatNumbers(required), + GT_Utility.getColoredTierNameFromVoltage(required)); + } + + @Override + public CheckRecipeResult newInstance() { + return new ResultInsufficientPower(0); + } + + @Override + public void encode(PacketBuffer buffer) { + buffer.writeLong(required); + } + + @Override + public void decode(PacketBuffer buffer) { + required = buffer.readLong(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResultInsufficientPower that = (ResultInsufficientPower) o; + return required == that.required; + } +} diff --git a/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java b/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java new file mode 100644 index 0000000000..767a168125 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java @@ -0,0 +1,78 @@ +package gregtech.api.recipe.check; + +import java.util.Objects; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.StatCollector; + +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; + +/** + * Simple implementation of {@link CheckRecipeResult}. You can create new object without registering it. + */ +public class SimpleCheckRecipeResult implements CheckRecipeResult { + + private boolean success; + private String key; + + SimpleCheckRecipeResult(boolean success, String key) { + this.success = success; + this.key = key; + } + + @Override + public String getID() { + return "simple_result"; + } + + @Override + public boolean wasSuccessful() { + return success; + } + + @Override + public String getDisplayString() { + return StatCollector.translateToLocal("GT5U.gui.text." + key); + } + + @Override + public CheckRecipeResult newInstance() { + return new SimpleCheckRecipeResult(false, ""); + } + + @Override + public void encode(PacketBuffer buffer) { + buffer.writeBoolean(success); + NetworkUtils.writeStringSafe(buffer, key); + } + + @Override + public void decode(PacketBuffer buffer) { + success = buffer.readBoolean(); + key = NetworkUtils.readStringSafe(buffer); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SimpleCheckRecipeResult that = (SimpleCheckRecipeResult) o; + return success == that.success && Objects.equals(key, that.key); + } + + /** + * Creates new result with successful state. Add your localized description with `GT5U.gui.text.{key}`. + * This is already registered to registry. + */ + public static CheckRecipeResult ofSuccess(String key) { + return new SimpleCheckRecipeResult(true, key); + } + + /** + * Creates new result object with failed state. Add your localized description with `GT5U.gui.text.{key}`. + * This is already registered to registry. + */ + public static CheckRecipeResult ofFailure(String key) { + return new SimpleCheckRecipeResult(false, key); + } +} diff --git a/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java b/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java new file mode 100644 index 0000000000..d0a952b8d5 --- /dev/null +++ b/src/main/java/gregtech/api/recipe/check/SingleRecipeCheck.java @@ -0,0 +1,404 @@ +package gregtech.api.recipe.check; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import com.google.common.collect.ImmutableMap; + +import gregtech.api.enums.GT_Values; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Utility.ItemId; + +/** + * Used by machines that are locked to a single recipe, for faster recipe check. + * <p> + * Computation time will be like these: + * <ul> + * Normal recipe check: + * <ul> + * {@link GT_Recipe.GT_Recipe_Map#findRecipeWithResult Find recipe from recipemap}: O(NCR) + * where N = number of machine inputs, C = average amount of recipe candidates found for specific input, + * R = computation time to {@link GT_Recipe#isRecipeInputEqual check if inputs match to recipe} + * </ul> + * <ul> + * {@link GT_Recipe#isRecipeInputEqual Check if inputs match to recipe}: O(NM) + * where N = number of machine inputs, M = number of recipe inputs + * </ul> + * </ul> + * <ul> + * {@link #checkRecipeInputs Single recipe check}: O(N + M) + * where N = number of machine inputs, M = number of recipe inputs + * </ul> + */ +public class SingleRecipeCheck { + + @Nonnull + private final GT_Recipe recipe; + @Nonnull + private final GT_Recipe.GT_Recipe_Map recipeMap; + @Nonnull + private final ImmutableMap<ItemId, Integer> itemCost; + @Nonnull + private final ImmutableMap<Fluid, Integer> fluidCost; + + private final int totalItemCost; + private final int totalFluidCost; + + private SingleRecipeCheck(@Nonnull GT_Recipe recipe, @Nonnull GT_Recipe.GT_Recipe_Map recipeMap, + @Nonnull ImmutableMap<ItemId, Integer> itemCost, @Nonnull ImmutableMap<Fluid, Integer> fluidCost) { + this.recipe = recipe; + this.recipeMap = recipeMap; + this.itemCost = itemCost; + this.fluidCost = fluidCost; + + this.totalItemCost = itemCost.values() + .stream() + .mapToInt(Integer::intValue) + .sum(); + this.totalFluidCost = fluidCost.values() + .stream() + .mapToInt(Integer::intValue) + .sum(); + } + + @Nonnull + public GT_Recipe getRecipe() { + return recipe; + } + + @Nonnull + public GT_Recipe.GT_Recipe_Map getRecipeMap() { + return recipeMap; + } + + /** + * Returns the number of parallel recipes, or 0 if recipe is not satisfied at all. + */ + public int checkRecipeInputs(boolean consumeInputs, int maxParallel, ItemStack[] itemInputs, + FluidStack[] fluidInputs) { + int currentParallel = maxParallel; + + if (totalItemCost > 0) { + // Create map for item -> stored amount + Map<ItemId, Integer> itemMap = new HashMap<>(); + for (ItemStack itemStack : itemInputs) { + if (itemStack == null) continue; + itemMap.merge(ItemId.createNoCopy(itemStack), itemStack.stackSize, Integer::sum); + } + + // Check how many parallels can it perform for each item + for (Map.Entry<ItemId, Integer> costEntry : itemCost.entrySet()) { + currentParallel = Math + .min(currentParallel, itemMap.getOrDefault(costEntry.getKey(), 0) / costEntry.getValue()); + if (currentParallel <= 0) { + return 0; + } + } + } + + if (totalFluidCost > 0) { + // Create map for fluid -> stored amount + Map<Fluid, Integer> fluidMap = new HashMap<>(); + for (FluidStack fluidStack : fluidInputs) { + if (fluidStack == null) continue; + fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); + } + + // Check how many parallels can it perform for each fluid + for (Map.Entry<Fluid, Integer> costEntry : fluidCost.entrySet()) { + currentParallel = Math + .min(currentParallel, fluidMap.getOrDefault(costEntry.getKey(), 0) / costEntry.getValue()); + if (currentParallel <= 0) { + return 0; + } + } + } + + final int finalParallel = currentParallel; + if (consumeInputs) { + if (totalItemCost > 0) { + int remainingItemCost = totalItemCost * finalParallel; + Map<ItemId, Integer> runningItemCost = itemCost.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() * finalParallel)); + + for (ItemStack itemStack : itemInputs) { + if (itemStack == null) continue; + ItemId key = ItemId.createNoCopy(itemStack); + int runningCost = runningItemCost.getOrDefault(key, 0); + int paid = Math.min(itemStack.stackSize, runningCost); + itemStack.stackSize -= paid; + runningItemCost.put(key, runningCost - paid); + + remainingItemCost -= paid; + // If all item costs are paid, we don't need to iterate inputs furthermore + if (remainingItemCost <= 0) { + break; + } + } + } + + if (totalFluidCost > 0) { + int remainingFluidCost = totalFluidCost * finalParallel; + Map<Fluid, Integer> runningFluidCost = fluidCost.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() * finalParallel)); + + for (FluidStack fluidStack : fluidInputs) { + if (fluidStack == null) continue; + Fluid key = fluidStack.getFluid(); + int runningCost = runningFluidCost.getOrDefault(key, 0); + int paid = Math.min(fluidStack.amount, runningCost); + fluidStack.amount -= paid; + runningFluidCost.put(key, runningCost - paid); + + remainingFluidCost -= paid; + // If all fluid costs are paid, we don't need to iterate inputs furthermore + if (remainingFluidCost <= 0) { + break; + } + } + } + } + + return finalParallel; + } + + public NBTTagCompound writeToNBT() { + // Here we encode recipe input, output and all other important values. + // At load time we do a recipe check again, so in case the recipe is gone, we can stop tracking. + // Of course the next step would be auto migrating to new recipe (if any), but given + // we don't yet have a mean to uniquely name a recipe, this will have to make do. + // Consider move serialization code to GT_Recipe once this has been proven to work + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("recipemap", recipeMap.mUnlocalizedName); + if (recipe.mInputs != null) { + tag.setTag("inputs", writeList(recipe.mInputs, GT_Utility::saveItem)); + } + if (recipe.mOutputs != null) { + tag.setTag("outputs", writeList(recipe.mOutputs, GT_Utility::saveItem)); + } + if (recipe.mChances != null) { + tag.setIntArray("chances", recipe.mChances); + } + if (recipe.mFluidInputs != null) { + tag.setTag( + "fInputs", + writeList( + recipe.mFluidInputs, + s -> s == null ? new NBTTagCompound() : s.writeToNBT(new NBTTagCompound()))); + } + if (recipe.mFluidOutputs != null) { + tag.setTag( + "fOutputs", + writeList( + recipe.mFluidOutputs, + s -> s == null ? new NBTTagCompound() : s.writeToNBT(new NBTTagCompound()))); + } + tag.setInteger("eut", recipe.mEUt); + tag.setInteger("duration", recipe.mDuration); + tag.setInteger("specialValue", recipe.mSpecialValue); + tag.setTag("itemCost", writeList(itemCost.entrySet(), e -> { + NBTTagCompound ret = new NBTTagCompound(); + ret.setTag( + "id", + e.getKey() + .writeToNBT()); + ret.setInteger("count", e.getValue()); + return ret; + })); + tag.setTag("fluidCost", writeList(fluidCost.entrySet(), e -> { + NBTTagCompound ret = new NBTTagCompound(); + ret.setString( + "id", + e.getKey() + .getName()); + ret.setInteger("count", e.getValue()); + return ret; + })); + return tag; + } + + private static <T, NBT extends NBTBase> NBTTagList writeList(T[] arr, Function<T, NBT> ser) { + return writeList(Arrays.asList(arr), ser); + } + + private static <T, NBT extends NBTBase> NBTTagList writeList(Collection<T> arr, Function<T, NBT> ser) { + NBTTagList l = new NBTTagList(); + for (T t : arr) { + l.appendTag(ser.apply(t)); + } + return l; + } + + @Nullable + public static SingleRecipeCheck tryLoad(GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag) { + if (tag == null || tag.hasNoTags()) return null; + + GT_Recipe.GT_Recipe_Map mapToUse; + if (tag.hasKey("recipemap")) { + String mapName = tag.getString("recipemap"); + GT_Recipe.GT_Recipe_Map foundMap = GT_Recipe.GT_Recipe_Map.findRecipeMap(mapName); + if (foundMap != null) { + mapToUse = foundMap; + } else { + mapToUse = recipeMap; + } + } else { + mapToUse = recipeMap; + } + if (mapToUse == null) { + return null; + } + + GT_Recipe foundRecipe = tryFindRecipe(mapToUse, tag); + if (foundRecipe == null) return null; + return new SingleRecipeCheck(foundRecipe, mapToUse, loadItemCost(tag), loadFluidCost(tag)); + } + + private static ImmutableMap<Fluid, Integer> loadFluidCost(NBTTagCompound tag) { + return GT_Utility.streamCompounds(tag.getTagList("fluidCost", Constants.NBT.TAG_COMPOUND)) + .collect( + GT_Utility + .toImmutableMapSerial(t -> FluidRegistry.getFluid(t.getString("id")), t -> t.getInteger("count"))); + } + + private static ImmutableMap<ItemId, Integer> loadItemCost(NBTTagCompound tag) { + return GT_Utility.streamCompounds(tag.getTagList("itemCost", Constants.NBT.TAG_COMPOUND)) + .collect( + GT_Utility + .toImmutableMapSerial(t -> ItemId.create(t.getCompoundTag("id")), t -> t.getInteger("count"))); + } + + private static GT_Recipe tryFindRecipe(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag) { + ItemStack[] inputs = GT_Utility.streamCompounds(tag.getTagList("inputs", Constants.NBT.TAG_COMPOUND)) + .map(GT_Utility::loadItem) + .toArray(ItemStack[]::new); + ItemStack[] outputs = GT_Utility.streamCompounds(tag.getTagList("outputs", Constants.NBT.TAG_COMPOUND)) + .map(GT_Utility::loadItem) + .toArray(ItemStack[]::new); + FluidStack[] fInputs = GT_Utility.streamCompounds(tag.getTagList("fInputs", Constants.NBT.TAG_COMPOUND)) + .map(FluidStack::loadFluidStackFromNBT) + .toArray(FluidStack[]::new); + FluidStack[] fOutputs = GT_Utility.streamCompounds(tag.getTagList("fOutputs", Constants.NBT.TAG_COMPOUND)) + .map(FluidStack::loadFluidStackFromNBT) + .toArray(FluidStack[]::new); + int eut = tag.getInteger("eut"); + GT_Recipe found = recipeMap.findRecipe(null, false, GT_Values.V[GT_Utility.getTier(eut)], fInputs, inputs); + int[] chances = tag.getIntArray("chances"); + if (chances.length == 0) chances = null; + if (found == null || !GT_Utility.equals(inputs, found.mInputs) + || !Arrays.equals(fInputs, found.mFluidInputs) + || !GT_Utility.equals(outputs, found.mOutputs) + || !Arrays.equals(fOutputs, found.mFluidOutputs) + || !Arrays.equals(chances, found.mChances) + || found.mDuration != tag.getInteger("duration") + || found.mEUt != eut + || found.mSpecialValue != tag.getInteger("specialValue")) return null; + return found; + } + + private static ImmutableMap<ItemId, Integer> buildItemMap(ItemStack[] inputs) { + Map<ItemId, Integer> itemMap = new HashMap<>(); + for (ItemStack itemStack : inputs) { + if (itemStack == null) continue; + itemMap.merge(ItemId.create(itemStack), itemStack.stackSize, Integer::sum); + } + return ImmutableMap.copyOf(itemMap); + } + + private static ImmutableMap<Fluid, Integer> buildFluidMap(FluidStack[] fluids) { + Map<Fluid, Integer> fluidMap = new HashMap<>(); + for (FluidStack fluidStack : fluids) { + if (fluidStack == null) continue; + fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); + } + return ImmutableMap.copyOf(fluidMap); + } + + public static Builder builder(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap) { + return new Builder(Objects.requireNonNull(recipeMap)); + } + + public static class Builder { + + private final GT_Recipe.GT_Recipe_Map recipeMap; + + // In order to compute which items and fluids are consumed by the recipe, we compare the + // multi-block's items and fluids before and after inputs are consumed by the recipe. + private Map<ItemId, Integer> beforeItems; + private Map<Fluid, Integer> beforeFluids; + private Map<ItemId, Integer> afterItems; + private Map<Fluid, Integer> afterFluids; + + private GT_Recipe recipe; + + private Builder(@Nonnull GT_Recipe.GT_Recipe_Map recipeMap) { + this.recipeMap = recipeMap; + } + + public Builder setBefore(ItemStack[] inputs, FluidStack[] fluids) { + beforeItems = buildItemMap(inputs); + beforeFluids = buildFluidMap(fluids); + return this; + } + + public Builder setAfter(ItemStack[] inputs, FluidStack[] fluids) { + afterItems = buildItemMap(inputs); + afterFluids = buildFluidMap(fluids); + return this; + } + + public Builder setRecipe(@Nonnull GT_Recipe recipe) { + this.recipe = recipe; + return this; + } + + private ImmutableMap<ItemId, Integer> buildItemCost() { + ImmutableMap.Builder<ItemId, Integer> itemCostBuilder = ImmutableMap.builder(); + for (Map.Entry<ItemId, Integer> entry : beforeItems.entrySet()) { + int cost = entry.getValue() - afterItems.getOrDefault(entry.getKey(), 0); + if (cost > 0) { + itemCostBuilder.put(entry.getKey(), cost); + } + } + return itemCostBuilder.build(); + } + + private ImmutableMap<Fluid, Integer> buildFluidCost() { + ImmutableMap.Builder<Fluid, Integer> fluidCostBuilder = ImmutableMap.builder(); + for (Map.Entry<Fluid, Integer> entry : beforeFluids.entrySet()) { + int cost = entry.getValue() - afterFluids.getOrDefault(entry.getKey(), 0); + if (cost > 0) { + fluidCostBuilder.put(entry.getKey(), cost); + } + } + return fluidCostBuilder.build(); + } + + public SingleRecipeCheck build() { + if (recipe == null) { + throw new IllegalStateException("recipe is not set"); + } + return new SingleRecipeCheck(recipe, recipeMap, buildItemCost(), buildFluidCost()); + } + } +} diff --git a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java index ba90240f14..6636b27bc7 100644 --- a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java +++ b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java @@ -1,5 +1,7 @@ package gregtech.api.util; +import javax.annotation.Nonnull; + public class GT_OverclockCalculator { /** @@ -15,7 +17,7 @@ public class GT_OverclockCalculator { * GT++ machines * mHeatDiscountAmount - The value used for discount final eut per 900 heat */ - private float mEUtDiscount = 1, mSpeedBoost = 1, mHeatDiscountAmount = 0.95f; + private double mEUtDiscount = 1, mSpeedBoost = 1, mHeatDiscountAmount = 0.95f; /** * mEUtIncreasePerOC - How much the bits should be moved to the left when it is overclocking (Going up, 2 meaning * it is multiplied with 4x) @@ -42,6 +44,15 @@ public class GT_OverclockCalculator { private static final int HEAT_PERFECT_OVERCLOCK_THRESHOLD = 1800; /** + * Creates calculator that doesn't do OC at all. + */ + public static GT_OverclockCalculator ofNoOverclock(@Nonnull GT_Recipe recipe) { + return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) + .setDuration(recipe.mDuration) + .setEUt(recipe.mEUt); + } + + /** * An Overclock helper for calculating overclocks in many different situations */ public GT_OverclockCalculator() {} diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java index 9ceec7af44..4c9f53745b 100644 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -1,11 +1,17 @@ package gregtech.api.util; +import java.util.Objects; + +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.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; import gregtech.api.objects.XSTR; +import gregtech.api.recipe.check.SingleRecipeCheck; @SuppressWarnings({ "unused", "UnusedReturnValue" }) public class GT_ParallelHelper { @@ -15,6 +21,14 @@ public class GT_ParallelHelper { */ 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 mRecipe; @@ -79,7 +93,7 @@ public class GT_ParallelHelper { /** * What is the duration multiplier with batch mode enabled */ - private float mDurationMultiplier; + private double mDurationMultiplier; /** * Modifier which is applied on the recipe eut. Useful for GT++ machines */ @@ -128,8 +142,14 @@ public class GT_ParallelHelper { /** * Sets the recipe, which will be used for the parallel calculation */ - public GT_ParallelHelper setRecipe(GT_Recipe aRecipe) { - mRecipe = aRecipe; + public GT_ParallelHelper setRecipe(@Nonnull GT_Recipe aRecipe) { + mRecipe = Objects.requireNonNull(aRecipe); + return this; + } + + public GT_ParallelHelper setRecipeLocked(IRecipeLockable singleRecipeMachine, boolean isRecipeLocked) { + this.singleRecipeMachine = singleRecipeMachine; + this.isRecipeLocked = isRecipeLocked; return this; } @@ -186,7 +206,7 @@ public class GT_ParallelHelper { * modifier of 1 does nothing */ public GT_ParallelHelper enableBatchMode(int aBatchModifier) { - mBatchMode = true; + mBatchMode = aBatchModifier > 1; mBatchModifier = aBatchModifier; return this; } @@ -207,6 +227,9 @@ public class GT_ParallelHelper { if (mBuilt) { throw new IllegalStateException("Tried to build twice"); } + if (mRecipe == null) { + throw new IllegalStateException("Recipe is not set"); + } mBuilt = true; determineParallel(); return this; @@ -225,7 +248,7 @@ public class GT_ParallelHelper { /** * @return The duration multiplier if batch mode was enabled for the multiblock */ - public float getDurationMultiplier() { + public double getDurationMultiplierDouble() { if (!mBuilt) { throw new IllegalStateException("Tried to get duration multiplier before building"); } @@ -236,6 +259,14 @@ public class GT_ParallelHelper { } /** + * @deprecated Use {@link #getDurationMultiplierDouble()} + */ + @Deprecated + public float getDurationMultiplier() { + return (float) getDurationMultiplierDouble(); + } + + /** * @return The ItemOutputs from the recipe */ public ItemStack[] getItemOutputs() { @@ -264,35 +295,50 @@ public class GT_ParallelHelper { if (mRecipe.mEUt > mAvailableEUt) { return; } - ItemStack[] tItemInputs = null; - FluidStack[] tFluidInputs = null; - long tCurrentUsage = 0; - // see if people want to consume their inputs with the Parallel Helper or not + if (mItemInputs == null) { + mItemInputs = new ItemStack[0]; + } + if (mFluidInputs == null) { + mFluidInputs = new FluidStack[0]; + } + + ItemStack[] tItemInputs; + FluidStack[] tFluidInputs; + // see if people want to consume their inputs or not if (mConsume) { tItemInputs = mItemInputs; tFluidInputs = mFluidInputs; } else { - if (mItemInputs == null) { - tItemInputs = new ItemStack[] {}; - } else { - tItemInputs = new ItemStack[mItemInputs.length]; - for (int i = 0; i < mItemInputs.length; i++) { - tItemInputs[i] = mItemInputs[i].copy(); - } + // copy to prevent consuming original inputs + tItemInputs = new ItemStack[mItemInputs.length]; + for (int i = 0; i < mItemInputs.length; i++) { + tItemInputs[i] = mItemInputs[i].copy(); } - - if (mFluidInputs == null) { - mFluidInputs = new FluidStack[] {}; - } else { - tFluidInputs = new FluidStack[mFluidInputs.length]; - for (int i = 0; i < mFluidInputs.length; i++) { - tFluidInputs[i] = mFluidInputs[i].copy(); - } + tFluidInputs = new FluidStack[mFluidInputs.length]; + for (int i = 0; i < mFluidInputs.length; i++) { + tFluidInputs[i] = mFluidInputs[i].copy(); } } + if (mBatchMode) { mMaxParallel *= mBatchModifier; } + + 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. + GT_Recipe.GT_Recipe_Map recipeMap = singleRecipeMachine.getRecipeMap(); + if (recipeMap != null) { + tSingleRecipeCheckBuilder = SingleRecipeCheck.builder(recipeMap) + .setBefore(tItemInputs, tFluidInputs); + } + } + } + // Let's look at how many parallels we can get with void protection if (protectExcessItem || protectExcessFluid) { if (machine == null) { @@ -307,31 +353,50 @@ public class GT_ParallelHelper { mMaxParallel = Math.min(voidProtectionHelper.getMaxParallel(), mMaxParallel); } - float tRecipeEUt = mRecipe.mEUt * mEUtModifier; + final int tRecipeEUt = (int) Math.ceil(mRecipe.mEUt * mEUtModifier); + final int batchCorrectedMaxParallel = mMaxParallel / mBatchModifier; // Consume inputs to determine normal parallel - for (; mCurrentParallel < mMaxParallel / mBatchModifier - && tCurrentUsage < (mAvailableEUt - tRecipeEUt); mCurrentParallel++) { - if (mRecipe.isRecipeInputEqual(true, false, tFluidInputs, tItemInputs)) { + if (recipeCheck != null) { + int actualMaxParallel = (int) Math.min(batchCorrectedMaxParallel, mAvailableEUt / tRecipeEUt); + mCurrentParallel = recipeCheck.checkRecipeInputs(true, actualMaxParallel, tItemInputs, tFluidInputs); + } else { + long tCurrentUsage = 0; + boolean builtRecipeCheck = false; + for (; mCurrentParallel < batchCorrectedMaxParallel + && tCurrentUsage < (mAvailableEUt - tRecipeEUt); mCurrentParallel++) { + if (!mRecipe.isRecipeInputEqual(true, false, tFluidInputs, tItemInputs)) { + break; + } tCurrentUsage += tRecipeEUt; - } else { - break; + if (tSingleRecipeCheckBuilder != null && !builtRecipeCheck) { + // If recipe checker is not built yet, build and set it + SingleRecipeCheck builtCheck = tSingleRecipeCheckBuilder.setAfter(tItemInputs, tFluidInputs) + .setRecipe(mRecipe) + .build(); + singleRecipeMachine.setSingleRecipeCheck(builtCheck); + builtRecipeCheck = true; + } } } // If Batch Mode is enabled determine how many extra parallels we can get - if (mBatchMode) { + if (mBatchMode && mCurrentParallel > 0) { int tExtraParallels = 0; - while (tExtraParallels < mCurrentParallel * (mBatchModifier - 1) - && mRecipe.isRecipeInputEqual(false, false, tFluidInputs, tItemInputs)) { - mRecipe.isRecipeInputEqual(true, false, tFluidInputs, tItemInputs); - tExtraParallels++; + final int maxExtraParallels = mCurrentParallel * (mBatchModifier - 1); + if (recipeCheck != null) { + tExtraParallels = recipeCheck.checkRecipeInputs(true, maxExtraParallels, tItemInputs, tFluidInputs); + } else { + while (tExtraParallels < maxExtraParallels + && mRecipe.isRecipeInputEqual(true, false, tFluidInputs, tItemInputs)) { + tExtraParallels++; + } } mDurationMultiplier = 1.0f + (float) tExtraParallels / mCurrentParallel; mCurrentParallel += tExtraParallels; } // If we want to calculate outputs we do it here - if (mCalculateOutputs) { + if (mCalculateOutputs && mCurrentParallel > 0) { if (mRecipe.mOutputs != null) { mItemOutputs = new ItemStack[mRecipe.mOutputs.length]; for (int i = 0; i < mRecipe.mOutputs.length; i++) { diff --git a/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java b/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java index 66bc16cae3..0ef28bd705 100644 --- a/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java +++ b/src/main/java/gregtech/api/util/GT_ProcessingArray_Manager.java @@ -2,6 +2,8 @@ package gregtech.api.util; import java.util.HashMap; +import net.minecraft.item.ItemStack; + import gregtech.api.enums.SoundResource; import gregtech.api.util.GT_Recipe.GT_Recipe_Map; @@ -38,4 +40,11 @@ public class GT_ProcessingArray_Manager { } return null; } + + public static String getMachineName(ItemStack stack) { + int length = stack.getUnlocalizedName() + .length(); + return stack.getUnlocalizedName() + .substring(17, length - 8); // trim "gt.blockmachines." and ".tier.xx" + } } diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index 748b922b44..d26b8105cf 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -9,6 +9,7 @@ import static gregtech.api.enums.Mods.GTPlusPlus; import static gregtech.api.enums.Mods.GregTech; import static gregtech.api.enums.Mods.NEICustomDiagrams; import static gregtech.api.enums.Mods.Railcraft; +import static gregtech.api.recipe.check.FindRecipeResult.*; import static gregtech.api.util.GT_RecipeBuilder.handleRecipeCollision; import static gregtech.api.util.GT_RecipeConstants.ADDITIVE_AMOUNT; import static gregtech.api.util.GT_RecipeMapUtil.FIRST_FLUIDSTACK_INPUT; @@ -104,11 +105,11 @@ import gregtech.api.gui.modularui.FallbackableSteamTexture; import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.gui.modularui.SteamTexture; import gregtech.api.interfaces.IGT_RecipeMap; -import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; import gregtech.api.objects.GT_ItemStack; import gregtech.api.objects.ItemData; import gregtech.api.objects.MaterialStack; +import gregtech.api.recipe.check.FindRecipeResult; import gregtech.api.util.extensions.ArrayExt; import gregtech.common.gui.modularui.UIHelper; import gregtech.common.items.GT_FluidDisplayItem; @@ -3051,6 +3052,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { .orElse(Collections.emptyList()))); } + @Nullable + public static GT_Recipe_Map findRecipeMap(@Nonnull String unlocalizedName) { + return sMappings.stream() + .filter(m -> unlocalizedName.equals(m.mUnlocalizedName)) + .findFirst() + .orElse(null); + } + /** * HashMap of Recipes based on their Items */ @@ -3105,6 +3114,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> { private boolean mUsesSpecialSlot = false; /** + * Whether this recipemap checks for equality of special slot when searching recipe. + */ + private boolean isSpecialSlotSensitive = false; + + /** * How many fluid inputs does this recipemap has at most. Currently used only for NEI slot placements and does * not actually restrict number of fluids used in the recipe. */ @@ -3188,6 +3202,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { private int neiTextColorOverride = -1; private INEISpecialInfoFormatter neiSpecialInfoFormatter; + private final boolean checkForCollision = true; private boolean allowNoInput; private boolean allowNoInputFluid; @@ -3293,6 +3308,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return this; } + public GT_Recipe_Map setSpecialSlotSensitive(boolean isSpecialSlotSensitive) { + this.isSpecialSlotSensitive = isSpecialSlotSensitive; + return this; + } + public GT_Recipe_Map setNEIUnificateOutput(boolean mNEIUnificateOutput) { this.mNEIUnificateOutput = mNEIUnificateOutput; return this; @@ -3882,12 +3902,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return aFluid != null && mRecipeFluidNameMap.contains(aFluid.getName()); } - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, long aVoltage, + @Nullable + public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { return findRecipe(aTileEntity, null, aNotUnificated, aVoltage, aFluids, null, aInputs); } - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, + @Nullable + public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { return findRecipe( aTileEntity, @@ -3900,13 +3922,16 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aInputs); } - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { + @Nullable + public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, + boolean aNotUnificated, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { return findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, null, aInputs); } - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack... aInputs) { + @Nullable + public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, + boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, + ItemStack... aInputs) { return findRecipe( aTileEntity, aRecipe, @@ -3918,16 +3943,32 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aInputs); } - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { + @Nullable + public final GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, + boolean aNotUnificated, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { return findRecipe(aTileEntity, aRecipe, aNotUnificated, false, aVoltage, aFluids, aSpecialSlot, aInputs); } + // TODO: make this final after migrating BW + @SuppressWarnings("unused") + @Nullable + public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + FindRecipeResult result = findRecipeWithResult( + aRecipe, + aNotUnificated, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); + return result.isSuccessful() ? result.getRecipe() : null; + } + /** * finds a Recipe matching the aFluid and ItemStack Inputs. * - * @param aTileEntity an Object representing the current coordinates of the executing - * Block/Entity/Whatever. This may be null, especially during Startup. * @param aRecipe in case this is != null it will try to use this Recipe first when looking things * up. * @param aNotUnificated if this is T the Recipe searcher will unificate the ItemStack Inputs @@ -3938,13 +3979,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { * @param aSpecialSlot the content of the Special Slot, the regular Manager doesn't do anything with * this, but some custom ones do. * @param aInputs the Item Inputs - * @return the Recipe it has found or null for no matching Recipe + * @return Result of the recipe search */ - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, + @Nonnull + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { // No Recipes? Well, nothing to be found then. - if (mRecipeList.isEmpty()) return null; + if (mRecipeList.isEmpty()) return NOT_FOUND; // Some Recipe Classes require a certain amount of Inputs of certain kinds. Like "at least 1 Fluid + 1 // Stack" or "at least 2 Stacks" before they start searching for Recipes. @@ -3952,16 +3994,16 @@ public class GT_Recipe implements Comparable<GT_Recipe> { // their Machines to select Sub Recipes. if (GregTech_API.sPostloadFinished) { if (mMinimalInputFluids > 0) { - if (aFluids == null) return null; + if (aFluids == null) return NOT_FOUND; int tAmount = 0; for (FluidStack aFluid : aFluids) if (aFluid != null) tAmount++; - if (tAmount < mMinimalInputFluids) return null; + if (tAmount < mMinimalInputFluids) return NOT_FOUND; } if (mMinimalInputItems > 0) { - if (aInputs == null) return null; + if (aInputs == null) return NOT_FOUND; int tAmount = 0; for (ItemStack aInput : aInputs) if (aInput != null) tAmount++; - if (tAmount < mMinimalInputItems) return null; + if (tAmount < mMinimalInputItems) return NOT_FOUND; } } @@ -3970,19 +4012,37 @@ public class GT_Recipe implements Comparable<GT_Recipe> { // Check the Recipe which has been used last time in order to not have to search for it again, if possible. if (aRecipe != null) if (!aRecipe.mFakeRecipe && aRecipe.mCanBeBuffered - && aRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) - return aRecipe.mEnabled && aVoltage * mAmperage >= aRecipe.mEUt ? aRecipe : null; + && aRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { + if (!isSpecialSlotSensitive + || GT_Utility.areStacksEqualOrNull((ItemStack) aRecipe.mSpecialItems, aSpecialSlot)) { + return aRecipe.mEnabled && aVoltage * mAmperage >= aRecipe.mEUt + ? FindRecipeResult.ofSuccess(aRecipe) + : FindRecipeResult.ofInsufficientVoltage(aRecipe); + } + } // Now look for the Recipes inside the Item HashMaps, but only when the Recipes usually have Items. if (mUsualInputCount > 0 && aInputs != null) for (ItemStack tStack : aInputs) if (tStack != null) { Collection<GT_Recipe> tRecipes = mRecipeItemMap.get(new GT_ItemStack(tStack)); if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) - return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt ? tRecipe : null; + && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { + if (!isSpecialSlotSensitive + || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { + return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt + ? FindRecipeResult.ofSuccess(tRecipe) + : FindRecipeResult.ofInsufficientVoltage(tRecipe); + } + } tRecipes = mRecipeItemMap.get(new GT_ItemStack(tStack, true)); if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) - return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt ? tRecipe : null; + && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { + if (!isSpecialSlotSensitive + || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { + return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt + ? FindRecipeResult.ofSuccess(tRecipe) + : FindRecipeResult.ofInsufficientVoltage(tRecipe); + } + } } // If the minimal Amount of Items for the Recipe is 0, then it could be a Fluid-Only Recipe, so check that @@ -3990,12 +4050,18 @@ public class GT_Recipe implements Comparable<GT_Recipe> { if (mMinimalInputItems == 0 && aFluids != null) for (FluidStack aFluid : aFluids) if (aFluid != null) { Collection<GT_Recipe> tRecipes = mRecipeFluidMap.get(aFluid.getFluid()); if (tRecipes != null) for (GT_Recipe tRecipe : tRecipes) if (!tRecipe.mFakeRecipe - && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) - return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt ? tRecipe : null; + && tRecipe.isRecipeInputEqual(false, aDontCheckStackSizes, aFluids, aInputs)) { + if (!isSpecialSlotSensitive + || GT_Utility.areStacksEqualOrNull((ItemStack) tRecipe.mSpecialItems, aSpecialSlot)) { + return tRecipe.mEnabled && aVoltage * mAmperage >= tRecipe.mEUt + ? FindRecipeResult.ofSuccess(tRecipe) + : FindRecipeResult.ofInsufficientVoltage(tRecipe); + } + } } // And nothing has been found. - return null; + return NOT_FOUND; } protected GT_Recipe addToItemMap(GT_Recipe aRecipe) { @@ -4854,24 +4920,28 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; + if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) + return FindRecipeResult.ofSuccess(aRecipe); ItemStack tOutput = GT_ModHandler.getSmeltingOutput(aInputs[0], false, null); - return tOutput == null ? null - : new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - null, - null, - 128, - 4, - 0); + return tOutput == null ? NOT_FOUND + : FindRecipeResult.ofSuccess( + new GT_Recipe( + false, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { tOutput }, + null, + null, + null, + null, + 128, + 4, + 0)); } @Override @@ -4907,25 +4977,30 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; + if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) + return FindRecipeResult.ofSuccess(aRecipe); ItemStack tOutput = GT_ModHandler.getSmeltingOutput(aInputs[0], false, null); if (GT_Utility.areStacksEqual(aInputs[0], new ItemStack(Items.book, 1, W))) { - return new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { GT_Utility.getWrittenBook("Manual_Microwave", ItemList.Book_Written_03.get(1)) }, - null, - null, - null, - null, - 32, - 4, - 0); + return FindRecipeResult.ofSuccess( + new GT_Recipe( + false, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { + GT_Utility.getWrittenBook("Manual_Microwave", ItemList.Book_Written_03.get(1)) }, + null, + null, + null, + null, + 32, + 4, + 0)); } // Check Container Item of Input since it is around the Input, then the Input itself, then Container Item of @@ -4938,12 +5013,9 @@ public class GT_Recipe implements Comparable<GT_Recipe> { || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.firework_charge, 1, W), true) || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.fireworks, 1, W), true) || GT_Utility.areStacksEqual(tStack, new ItemStack(Items.fire_charge, 1, W), true)) { - if (aTileEntity instanceof IGregTechTileEntity) { - GT_Log.exp.println( - "Microwave Explosion due to TNT || EGG || FIREWORKCHARGE || FIREWORK || FIRE CHARGE"); - ((IGregTechTileEntity) aTileEntity).doExplosion(aVoltage * 4); - } - return null; + GT_Log.exp.println( + "Microwave Explosion due to TNT || EGG || FIREWORKCHARGE || FIREWORK || FIRE CHARGE"); + return EXPLODE; } ItemData tData = GT_OreDictUnificator.getItemData(tStack); @@ -4951,59 +5023,45 @@ public class GT_Recipe implements Comparable<GT_Recipe> { if (tData.mMaterial != null && tData.mMaterial.mMaterial != null) { if (tData.mMaterial.mMaterial.contains(SubTag.METAL) || tData.mMaterial.mMaterial.contains(SubTag.EXPLOSIVE)) { - if (aTileEntity instanceof IGregTechTileEntity) { - GT_Log.exp.println("Microwave Explosion due to METAL insertion"); - ((IGregTechTileEntity) aTileEntity).doExplosion(aVoltage * 4); - } - return null; + GT_Log.exp.println("Microwave Explosion due to METAL insertion"); + return EXPLODE; } if (tData.mMaterial.mMaterial.contains(SubTag.FLAMMABLE)) { - if (aTileEntity instanceof IGregTechTileEntity) { - GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); - ((IGregTechTileEntity) aTileEntity).setOnFire(); - } - return null; + GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); + return ON_FIRE; } } for (MaterialStack tMaterial : tData.mByProducts) if (tMaterial != null) { if (tMaterial.mMaterial.contains(SubTag.METAL) || tMaterial.mMaterial.contains(SubTag.EXPLOSIVE)) { - if (aTileEntity instanceof IGregTechTileEntity) { - GT_Log.exp.println("Microwave Explosion due to METAL insertion"); - ((IGregTechTileEntity) aTileEntity).doExplosion(aVoltage * 4); - } - return null; + GT_Log.exp.println("Microwave Explosion due to METAL insertion"); + return EXPLODE; } if (tMaterial.mMaterial.contains(SubTag.FLAMMABLE)) { - if (aTileEntity instanceof IGregTechTileEntity) { - ((IGregTechTileEntity) aTileEntity).setOnFire(); - GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); - } - return null; + GT_Log.exp.println("Microwave INFLAMMATION due to FLAMMABLE insertion"); + return ON_FIRE; } } } if (TileEntityFurnace.getItemBurnTime(tStack) > 0) { - if (aTileEntity instanceof IGregTechTileEntity) { - ((IGregTechTileEntity) aTileEntity).setOnFire(); - GT_Log.exp.println("Microwave INFLAMMATION due to BURNABLE insertion"); - } - return null; + GT_Log.exp.println("Microwave INFLAMMATION due to BURNABLE insertion"); + return ON_FIRE; } } - return tOutput == null ? null - : new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - null, - null, - 32, - 4, - 0); + return tOutput == null ? NOT_FOUND + : FindRecipeResult.ofSuccess( + new GT_Recipe( + false, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { tOutput }, + null, + null, + null, + null, + 32, + 4, + 0)); } @Override @@ -5039,14 +5097,29 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { if (aInputs == null || aInputs.length == 0 || !ItemList.IC2_Scrapbox.isStackEqual(aInputs[0], false, true)) - return super.findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, aSpecialSlot, aInputs); + return super.findRecipeWithResult( + aRecipe, + aNotUnificated, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); ItemStack tOutput = GT_ModHandler.getRandomScrapboxDrop(); - if (tOutput == null) - return super.findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, aSpecialSlot, aInputs); + if (tOutput == null) return super.findRecipeWithResult( + aRecipe, + aNotUnificated, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); GT_Recipe rRecipe = new GT_Recipe( false, new ItemStack[] { ItemList.IC2_Scrapbox.get(1) }, @@ -5063,7 +5136,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { // Due to its randomness it is not good if there are Items in the Output Slot, because those Items could // manipulate the outcome. rRecipe.mNeedsEmptyOutput = true; - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } @Override @@ -5099,39 +5172,46 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - GT_Recipe rRecipe = super.findRecipe( - aTileEntity, + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + FindRecipeResult result = super.findRecipeWithResult( aRecipe, aNotUnificated, + aDontCheckStackSizes, aVoltage, aFluids, aSpecialSlot, aInputs); if (aInputs == null || aInputs.length == 0 || aInputs[0] == null - || rRecipe != null - || !GregTech_API.sPostloadFinished) return rRecipe; + || result.isSuccessful() + || !GregTech_API.sPostloadFinished) return result; + if (aFluids != null && aFluids.length > 0 && aFluids[0] != null) { ItemStack tOutput = GT_Utility.fillFluidContainer(aFluids[0], aInputs[0], false, true); FluidStack tFluid = GT_Utility.getFluidForFilledItem(tOutput, true); - if (tFluid != null) rRecipe = new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { tFluid }, - null, - Math.max(tFluid.amount / 64, 16), - 1, - 0); + if (tFluid != null) { + GT_Recipe recipe = new GT_Recipe( + false, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { tOutput }, + null, + null, + new FluidStack[] { tFluid }, + null, + Math.max(tFluid.amount / 64, 16), + 1, + 0); + recipe.mCanBeBuffered = false; + return FindRecipeResult.ofSuccess(recipe); + } } - if (rRecipe == null) { - FluidStack tFluid = GT_Utility.getFluidForFilledItem(aInputs[0], true); - if (tFluid != null) rRecipe = new GT_Recipe( + FluidStack tFluid = GT_Utility.getFluidForFilledItem(aInputs[0], true); + if (tFluid != null) { + GT_Recipe recipe = new GT_Recipe( false, new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, new ItemStack[] { GT_Utility.getContainerItem(aInputs[0], true) }, @@ -5142,9 +5222,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { Math.max(tFluid.amount / 64, 16), 1, 0); + recipe.mCanBeBuffered = false; + return FindRecipeResult.ofSuccess(recipe); } - if (rRecipe != null) rRecipe.mCanBeBuffered = false; - return rRecipe; + return NOT_FOUND; } @Override @@ -5191,329 +5272,31 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; - return new GT_Recipe( - false, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { GT_ModHandler.getRecyclerOutput(aInputs[0], 0) }, - null, - new int[] { 1250 }, - null, - null, - 45, - 1, - 0); - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_ModHandler.getRecyclerOutput(aStack, 0) != null; - } - } - - /** - * Special Class for Compressor Recipe handling. - */ - public static class GT_Recipe_Map_Compressor extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_Compressor(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; - ItemStack tComparedInput = GT_Utility.copyOrNull(aInputs[0]); - ItemStack[] tOutputItems = GT_ModHandler.getMachineOutput( - tComparedInput, - ic2.api.recipe.Recipes.compressor.getRecipes(), - true, - new NBTTagCompound(), - null, - null, - null); - return GT_Utility.arrayContainsNonNull(tOutputItems) - ? new GT_Recipe( - false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, - null, - null, - null, - null, - 400, - 2, - 0) - : null; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_Utility.arrayContainsNonNull( - GT_ModHandler.getMachineOutput( - GT_Utility.copyAmount(64, aStack), - ic2.api.recipe.Recipes.compressor.getRecipes(), - false, - new NBTTagCompound(), - null, - null, - null)); - } - } - - /** - * Special Class for Extractor Recipe handling. - */ - public static class GT_Recipe_Map_Extractor extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_Extractor(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; - ItemStack tComparedInput = GT_Utility.copyOrNull(aInputs[0]); - ItemStack[] tOutputItems = GT_ModHandler.getMachineOutput( - tComparedInput, - ic2.api.recipe.Recipes.extractor.getRecipes(), - true, - new NBTTagCompound(), - null, - null, - null); - return GT_Utility.arrayContainsNonNull(tOutputItems) - ? new GT_Recipe( - false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, - null, - null, - null, - null, - 400, - 2, - 0) - : null; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_Utility.arrayContainsNonNull( - GT_ModHandler.getMachineOutput( - GT_Utility.copyAmount(64, aStack), - ic2.api.recipe.Recipes.extractor.getRecipes(), - false, - new NBTTagCompound(), - null, - null, - null)); - } - } - - /** - * Special Class for Thermal Centrifuge Recipe handling. - */ - public static class GT_Recipe_Map_ThermalCentrifuge extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_ThermalCentrifuge(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, - String aLocalName, String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, - int aMinimalInputItems, int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, - int aNEISpecialValueMultiplier, String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, - boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; - ItemStack tComparedInput = GT_Utility.copyOrNull(aInputs[0]); - ItemStack[] tOutputItems = GT_ModHandler.getMachineOutput( - tComparedInput, - ic2.api.recipe.Recipes.centrifuge.getRecipes(), - true, - new NBTTagCompound(), - null, - null, - null); - return GT_Utility.arrayContainsNonNull(tOutputItems) - ? new GT_Recipe( - false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, - null, - null, - null, - null, - 400, - 48, - 0) - : null; - } - - @Override - public boolean containsInput(ItemStack aStack) { - return GT_Utility.arrayContainsNonNull( - GT_ModHandler.getMachineOutput( - GT_Utility.copyAmount(64, aStack), - ic2.api.recipe.Recipes.centrifuge.getRecipes(), - false, - new NBTTagCompound(), - null, - null, - null)); - } - } - - /** - * Special Class for Ore Washer Recipe handling. - */ - public static class GT_Recipe_Map_OreWasher extends GT_Recipe_Map_NonGTRecipes { - - public GT_Recipe_Map_OreWasher(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName, String aLocalName, - String aNEIName, String aNEIGUIPath, int aUsualInputCount, int aUsualOutputCount, int aMinimalInputItems, - int aMinimalInputFluids, int aAmperage, String aNEISpecialValuePre, int aNEISpecialValueMultiplier, - String aNEISpecialValuePost, boolean aShowVoltageAmperageInNEI, boolean aNEIAllowed) { - super( - aRecipeList, - aUnlocalizedName, - aLocalName, - aNEIName, - aNEIGUIPath, - aUsualInputCount, - aUsualOutputCount, - aMinimalInputItems, - aMinimalInputFluids, - aAmperage, - aNEISpecialValuePre, - aNEISpecialValueMultiplier, - aNEISpecialValuePost, - aShowVoltageAmperageInNEI, - aNEIAllowed); - } - - @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - if (aInputs == null || aInputs.length == 0 - || aInputs[0] == null - || aFluids == null - || aFluids.length < 1 - || !GT_ModHandler.isWater(aFluids[0])) return null; - if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) return aRecipe; - ItemStack tComparedInput = GT_Utility.copyOrNull(aInputs[0]); - NBTTagCompound aRecipeMetaData = new NBTTagCompound(); - ItemStack[] tOutputItems = GT_ModHandler.getMachineOutput( - tComparedInput, - ic2.api.recipe.Recipes.oreWashing.getRecipes(), - true, - aRecipeMetaData, - null, - null, - null); - return GT_Utility.arrayContainsNonNull(tOutputItems) - ? new GT_Recipe( + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + if (aInputs == null || aInputs.length == 0 || aInputs[0] == null) return NOT_FOUND; + if (aRecipe != null && aRecipe.isRecipeInputEqual(false, true, aFluids, aInputs)) + return FindRecipeResult.ofSuccess(aRecipe); + return FindRecipeResult.ofSuccess( + new GT_Recipe( false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { GT_ModHandler.getRecyclerOutput(aInputs[0], 0) }, null, + new int[] { 1250 }, null, - new FluidStack[] { new FluidStack( - aFluids[0].getFluid(), - ((NBTTagCompound) aRecipeMetaData.getTag("return")).getInteger("amount")) }, null, - 400, - 16, - 0) - : null; + 45, + 1, + 0)); } @Override public boolean containsInput(ItemStack aStack) { - return GT_Utility.arrayContainsNonNull( - GT_ModHandler.getMachineOutput( - GT_Utility.copyAmount(64, aStack), - ic2.api.recipe.Recipes.oreWashing.getRecipes(), - false, - new NBTTagCompound(), - null, - null, - null)); - } - - @Override - public boolean containsInput(FluidStack aFluid) { - return GT_ModHandler.isWater(aFluid); - } - - @Override - public boolean containsInput(Fluid aFluid) { - return GT_ModHandler.isWater(new FluidStack(aFluid, 0)); + return GT_ModHandler.getRecyclerOutput(aStack, 0) != null; } } @@ -5544,20 +5327,36 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { if (aInputs == null || aInputs.length == 0 || aInputs[0] == null || !GregTech_API.sPostloadFinished) - return super.findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, aSpecialSlot, aInputs); - aRecipe = super.findRecipe(aTileEntity, aRecipe, aNotUnificated, aVoltage, aFluids, aSpecialSlot, aInputs); - if (aRecipe != null) return aRecipe; + return super.findRecipeWithResult( + aRecipe, + aNotUnificated, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); + FindRecipeResult result = super.findRecipeWithResult( + aRecipe, + aNotUnificated, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); + if (result.isSuccessful()) return result; try { List<ItemStack> tRecipeOutputs = mods.railcraft.api.crafting.RailcraftCraftingManager.rockCrusher .getRecipe(GT_Utility.copyAmount(1, aInputs[0])) .getRandomizedOuputs(); if (tRecipeOutputs != null) { - aRecipe = new GT_Recipe( + GT_Recipe recipe = new GT_Recipe( false, new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, tRecipeOutputs.toArray(new ItemStack[0]), @@ -5568,9 +5367,9 @@ public class GT_Recipe implements Comparable<GT_Recipe> { 800, 2, 0); - aRecipe.mCanBeBuffered = false; - aRecipe.mNeedsEmptyOutput = true; - return aRecipe; + recipe.mCanBeBuffered = false; + recipe.mNeedsEmptyOutput = true; + return FindRecipeResult.ofSuccess(recipe); } } catch (NoClassDefFoundError e) { if (D1) GT_Log.err.println("Railcraft Not loaded"); @@ -5587,20 +5386,22 @@ public class GT_Recipe implements Comparable<GT_Recipe> { null, null, null); - return GT_Utility.arrayContainsNonNull(tOutputItems) - ? new GT_Recipe( - false, - new ItemStack[] { - GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, - tOutputItems, - null, - null, - null, - null, - 400, - 2, - 0) - : null; + if (tComparedInput != null && GT_Utility.arrayContainsNonNull(tOutputItems)) { + return FindRecipeResult.ofSuccess( + new GT_Recipe( + false, + new ItemStack[] { + GT_Utility.copyAmount(aInputs[0].stackSize - tComparedInput.stackSize, aInputs[0]) }, + tOutputItems, + null, + null, + null, + null, + 400, + 2, + 0)); + } + return NOT_FOUND; } @Override @@ -5644,11 +5445,20 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { - GT_Recipe rRecipe = super.findRecipe(aTileEntity, aRecipe, true, aVoltage, aFluids, aSpecialSlot, aInputs); + FindRecipeResult result = super.findRecipeWithResult( + aRecipe, + true, + aDontCheckStackSizes, + aVoltage, + aFluids, + aSpecialSlot, + aInputs); /* * Doesnt work, keep it as a reminder tho if (rRecipe == null){ Set<ItemStack> aInputs2 = new * TreeSet<ItemStack>(); for (ItemStack aInput : aInputs) { aInputs2.add(aInput); } for (ItemStack aInput : @@ -5662,9 +5472,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { */ if (aInputs == null || aInputs.length == 0 || aInputs[0] == null - || rRecipe == null - || !GregTech_API.sPostloadFinished) return rRecipe; + || !result.isSuccessful() + || !GregTech_API.sPostloadFinished) return result; + GT_Recipe rRecipe = result.getRecipeNonNull(); for (ItemStack aInput : aInputs) { if (ItemList.Paper_Printed_Pages.isStackEqual(aInput, false, true)) { rRecipe = rRecipe.copy(); @@ -5672,7 +5483,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { rRecipe.mOutputs[0].setTagCompound(aInput.getTagCompound()); } } - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } } @@ -5703,12 +5514,12 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - GT_Recipe rRecipe = super.findRecipe( - aTileEntity, + FindRecipeResult result = super.findRecipeWithResult( aRecipe, aNotUnificated, aDontCheckStackSizes, @@ -5716,8 +5527,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aFluids, aSpecialSlot, aInputs); - if (aInputs == null || aInputs.length < 2 || !GregTech_API.sPostloadFinished) return rRecipe; - if (rRecipe == null) return findRenamingRecipe(aInputs); + if (aInputs == null || aInputs.length < 2 || !GregTech_API.sPostloadFinished) return result; + if (!result.isSuccessful()) { + return findRenamingRecipe(aInputs); + } for (ItemStack aMold : aInputs) { if (ItemList.Shape_Mold_Credit.isStackEqual(aMold, false, true)) { NBTTagCompound tNBT = aMold.getTagCompound(); @@ -5725,13 +5538,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { if (!tNBT.hasKey("credit_security_id")) tNBT.setLong("credit_security_id", System.nanoTime()); aMold.setTagCompound(tNBT); + GT_Recipe rRecipe = result.getRecipeNonNull(); rRecipe = rRecipe.copy(); rRecipe.mCanBeBuffered = false; rRecipe.mOutputs[0].setTagCompound(tNBT); - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } } - return rRecipe; + return result; } private ItemStack findNameMoldIndex(ItemStack[] inputs) { @@ -5749,12 +5563,14 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return null; } - private GT_Recipe findRenamingRecipe(ItemStack[] inputs) { + @Nonnull + private FindRecipeResult findRenamingRecipe(ItemStack[] inputs) { ItemStack mold = findNameMoldIndex(inputs); - if (mold == null) return null; + if (mold == null) return NOT_FOUND; ItemStack input = findStackToRename(inputs, mold); - if (input == null) return null; + if (input == null) return NOT_FOUND; ItemStack output = GT_Utility.copyAmount(1, input); + if (output == null) return NOT_FOUND; output.setStackDisplayName(mold.getDisplayName()); GT_Recipe recipe = new GT_Recipe( false, @@ -5768,7 +5584,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { 8, 0); recipe.mCanBeBuffered = false; - return recipe; + return FindRecipeResult.ofSuccess(recipe); } } @@ -5799,13 +5615,15 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aNEIAllowed); } + @Nonnull @Override - public GT_Recipe findRecipe(IHasWorldObjectAndCoords aTileEntity, GT_Recipe aRecipe, boolean aNotUnificated, - long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, ItemStack... aInputs) { - GT_Recipe rRecipe = super.findRecipe( - aTileEntity, + public FindRecipeResult findRecipeWithResult(GT_Recipe aRecipe, boolean aNotUnificated, + boolean aDontCheckStackSizes, long aVoltage, FluidStack[] aFluids, ItemStack aSpecialSlot, + ItemStack... aInputs) { + FindRecipeResult result = super.findRecipeWithResult( aRecipe, aNotUnificated, + aDontCheckStackSizes, aVoltage, aFluids, aSpecialSlot, @@ -5815,7 +5633,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { || aFluids == null || aFluids.length == 0 || aFluids[0] == null - || !GregTech_API.sPostloadFinished) return rRecipe; + || !GregTech_API.sPostloadFinished) return result; Dyes aDye = null; for (Dyes tDye : Dyes.VALUES) if (tDye.isFluidDye(aFluids[0])) { @@ -5823,11 +5641,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> { break; } - if (aDye == null) return rRecipe; + if (aDye == null) return result; - if (rRecipe == null) { + if (!result.isSuccessful()) { ItemStack tOutput = GT_ModHandler.getAllRecipeOutput( - aTileEntity == null ? null : aTileEntity.getWorld(), + null, aInputs[0], aInputs[0], aInputs[0], @@ -5837,67 +5655,72 @@ public class GT_Recipe implements Comparable<GT_Recipe> { aInputs[0], aInputs[0], aInputs[0]); - if (tOutput != null) return addRecipe( - new GT_Recipe( - true, - new ItemStack[] { GT_Utility.copyAmount(8, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, - null, - 256, - 2, - 0), - false, - false, - true); + if (tOutput != null) { + GT_Recipe recipe = addRecipe( + new GT_Recipe( + true, + new ItemStack[] { GT_Utility.copyAmount(8, aInputs[0]) }, + new ItemStack[] { tOutput }, + null, + null, + new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, + null, + 256, + 2, + 0), + false, + false, + true); + return recipe != null ? FindRecipeResult.ofSuccess(recipe) : NOT_FOUND; + } - tOutput = GT_ModHandler.getAllRecipeOutput( - aTileEntity == null ? null : aTileEntity.getWorld(), - aInputs[0], - ItemList.DYE_ONLY_ITEMS[aDye.mIndex].get(1)); - if (tOutput != null) return addRecipe( - new GT_Recipe( - true, - new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, - new ItemStack[] { tOutput }, - null, - null, - new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, - null, - 32, - 2, - 0), - false, - false, - true); + tOutput = GT_ModHandler + .getAllRecipeOutput(null, aInputs[0], ItemList.DYE_ONLY_ITEMS[aDye.mIndex].get(1)); + if (tOutput != null) { + GT_Recipe recipe = addRecipe( + new GT_Recipe( + true, + new ItemStack[] { GT_Utility.copyAmount(1, aInputs[0]) }, + new ItemStack[] { tOutput }, + null, + null, + new FluidStack[] { new FluidStack(aFluids[0].getFluid(), (int) L) }, + null, + 32, + 2, + 0), + false, + false, + true); + return recipe != null ? FindRecipeResult.ofSuccess(recipe) : NOT_FOUND; + } } else { + GT_Recipe rRecipe = result.getRecipeNonNull(); if (aInputs[0].getItem() == Items.paper) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return null; + if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); if (tNBT == null || GT_Utility.isStringInvalid(tNBT.getString("title")) - || GT_Utility.isStringInvalid(tNBT.getString("author"))) return null; + || GT_Utility.isStringInvalid(tNBT.getString("author"))) return NOT_FOUND; rRecipe = rRecipe.copy(); rRecipe.mCanBeBuffered = false; rRecipe.mOutputs[0].setTagCompound(tNBT); - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } if (aInputs[0].getItem() == Items.map) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return null; + if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); - if (tNBT == null || !tNBT.hasKey("map_id")) return null; + if (tNBT == null || !tNBT.hasKey("map_id")) return NOT_FOUND; rRecipe = rRecipe.copy(); rRecipe.mCanBeBuffered = false; rRecipe.mOutputs[0].setItemDamage(tNBT.getShort("map_id")); - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } if (ItemList.Paper_Punch_Card_Empty.isStackEqual(aInputs[0], false, true)) { - if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return null; + if (!ItemList.Tool_DataStick.isStackEqual(aSpecialSlot, false, true)) return NOT_FOUND; NBTTagCompound tNBT = aSpecialSlot.getTagCompound(); - if (tNBT == null || !tNBT.hasKey("GT.PunchCardData")) return null; + if (tNBT == null || !tNBT.hasKey("GT.PunchCardData")) return NOT_FOUND; rRecipe = rRecipe.copy(); rRecipe.mCanBeBuffered = false; @@ -5906,10 +5729,10 @@ public class GT_Recipe implements Comparable<GT_Recipe> { new NBTTagCompound(), "GT.PunchCardData", tNBT.getString("GT.PunchCardData"))); - return rRecipe; + return FindRecipeResult.ofSuccess(rRecipe); } } - return rRecipe; + return result; } @Override diff --git a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java deleted file mode 100644 index f939275e6c..0000000000 --- a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check.java +++ /dev/null @@ -1,421 +0,0 @@ -package gregtech.api.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import javax.annotation.Nullable; - -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidRegistry; -import net.minecraftforge.fluids.FluidStack; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; - -import gregtech.api.enums.GT_Values; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; - -/** Used by machines that are locked to a single recipe, for fast computation. */ -public class GT_Single_Recipe_Check { - - protected final GT_MetaTileEntity_MultiBlockBase multiBlockBase; - protected final GT_Recipe recipe; - protected final ImmutableMap<GT_Utility.ItemId, Integer> itemCost; - protected final ImmutableMap<Fluid, Integer> fluidCost; - - protected final int totalItemCost; - protected final int totalFluidCost; - - protected GT_Single_Recipe_Check(GT_MetaTileEntity_MultiBlockBase multiBlockBase, GT_Recipe recipe, - ImmutableMap<GT_Utility.ItemId, Integer> itemCost, ImmutableMap<Fluid, Integer> fluidCost) { - this.multiBlockBase = multiBlockBase; - this.recipe = recipe; - this.itemCost = itemCost; - this.fluidCost = fluidCost; - - this.totalItemCost = itemCost.values() - .stream() - .mapToInt(Integer::intValue) - .sum(); - this.totalFluidCost = fluidCost.values() - .stream() - .mapToInt(Integer::intValue) - .sum(); - } - - public GT_Recipe getRecipe() { - return recipe; - } - - /** - * Use this method if recipes cannot require more than a single stack of any item or fluid. In particular, - * {@link GT_MetaTileEntity_MultiBlockBase#getCompactedInputs()} and - * {@link GT_MetaTileEntity_MultiBlockBase#getCompactedFluids()} both enforce this single-stack restriction, so any - * multi-block that calls those can use this method. - */ - @SuppressWarnings("JavadocReference") - public boolean checkRecipeInputsSingleStack(boolean consumeInputs) { - Map<GT_Utility.ItemId, ItemStack> itemMap = null; - if (totalItemCost > 0) { - itemMap = new HashMap<>(); - for (ItemStack itemStack : multiBlockBase.getStoredInputs()) { - itemMap.merge( - GT_Utility.ItemId.createNoCopy(itemStack), - itemStack, - (a, b) -> a.stackSize >= b.stackSize ? a : b); - } - - for (Map.Entry<GT_Utility.ItemId, Integer> entry : itemCost.entrySet()) { - ItemStack itemStack = itemMap.get(entry.getKey()); - if (itemStack == null || itemStack.stackSize < entry.getValue()) { - return false; - } - } - } - - Map<Fluid, FluidStack> fluidMap = null; - if (totalFluidCost > 0) { - fluidMap = new HashMap<>(); - for (FluidStack fluidStack : multiBlockBase.getStoredFluids()) { - fluidMap.merge(fluidStack.getFluid(), fluidStack, (a, b) -> a.amount >= b.amount ? a : b); - } - - for (Map.Entry<Fluid, Integer> entry : fluidCost.entrySet()) { - FluidStack fluidStack = fluidMap.get(entry.getKey()); - if (fluidStack == null || fluidStack.amount < entry.getValue()) { - return false; - } - } - } - - if (consumeInputs) { - if (totalItemCost > 0) { - for (Map.Entry<GT_Utility.ItemId, Integer> entry : itemCost.entrySet()) { - itemMap.get(entry.getKey()).stackSize -= entry.getValue(); - } - } - - if (totalFluidCost > 0) { - for (Map.Entry<Fluid, Integer> entry : fluidCost.entrySet()) { - fluidMap.get(entry.getKey()).amount -= entry.getValue(); - } - } - } - - return true; - } - - /** - * Use this method if recipes can require more than a single stack of any item or fluid. It is less efficient, - * though. - */ - public boolean checkRecipeInputs(boolean consumeInputs) { - List<ItemStack> items = null; - if (totalItemCost > 0) { - items = multiBlockBase.getStoredInputs(); - - Map<GT_Utility.ItemId, Integer> itemMap = new HashMap<>(); - for (ItemStack itemStack : items) { - itemMap.merge(GT_Utility.ItemId.createNoCopy(itemStack), itemStack.stackSize, Integer::sum); - } - - for (Map.Entry<GT_Utility.ItemId, Integer> entry : itemCost.entrySet()) { - if (itemMap.getOrDefault(entry.getKey(), 0) < entry.getValue()) { - return false; - } - } - } - - List<FluidStack> fluids = null; - if (totalFluidCost > 0) { - fluids = multiBlockBase.getStoredFluids(); - - Map<Fluid, Integer> fluidMap = new HashMap<>(); - for (FluidStack fluidStack : fluids) { - fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); - } - - for (Map.Entry<Fluid, Integer> entry : fluidCost.entrySet()) { - if (fluidMap.getOrDefault(entry.getKey(), 0) < entry.getValue()) { - return false; - } - } - } - - if (consumeInputs) { - if (totalItemCost > 0) { - int remainingItemCost = totalItemCost; - Map<GT_Utility.ItemId, Integer> runningItemCost = Maps.newHashMap(itemCost); - for (ItemStack itemStack : items) { - GT_Utility.ItemId key = GT_Utility.ItemId.createNoCopy(itemStack); - int runningCost = runningItemCost.getOrDefault(key, 0); - int paid = Math.min(itemStack.stackSize, runningCost); - itemStack.stackSize -= paid; - runningItemCost.put(key, runningCost - paid); - - remainingItemCost -= paid; - if (remainingItemCost <= 0) { - break; - } - } - } - - if (totalFluidCost > 0) { - int remainingFluidCost = totalFluidCost; - Map<Fluid, Integer> runningFluidCost = Maps.newHashMap(fluidCost); - for (FluidStack fluidStack : fluids) { - Fluid key = fluidStack.getFluid(); - int runningCost = runningFluidCost.getOrDefault(key, 0); - int paid = Math.min(fluidStack.amount, runningCost); - fluidStack.amount -= paid; - runningFluidCost.put(key, runningCost - paid); - - remainingFluidCost -= paid; - if (remainingFluidCost <= 0) { - break; - } - } - } - } - - return true; - } - - public NBTTagCompound writeToNBT() { - // here we encode recipe input, output and all other important values - // at load time we do a recipe check again, so in case the recipe is gone, we can stop tracking - // of course the next step would be auto migrating to new recipe (if any), but given - // we don't yet have a mean to uniquely name a recipe, this will have to make do. - // consider move serialization code to GT_Recipe once this has been proven to work - NBTTagCompound tag = new NBTTagCompound(); - if (recipe == null) return tag; - - if (recipe.mInputs != null) { - tag.setTag("inputs", writeList(recipe.mInputs, GT_Utility::saveItem)); - } - if (recipe.mOutputs != null) { - tag.setTag("outputs", writeList(recipe.mOutputs, GT_Utility::saveItem)); - } - if (recipe.mChances != null) { - tag.setIntArray("chances", recipe.mChances); - } - if (recipe.mFluidInputs != null) { - tag.setTag( - "fInputs", - writeList( - recipe.mFluidInputs, - s -> s == null ? new NBTTagCompound() : s.writeToNBT(new NBTTagCompound()))); - } - if (recipe.mFluidOutputs != null) { - tag.setTag( - "fOutputs", - writeList( - recipe.mFluidOutputs, - s -> s == null ? new NBTTagCompound() : s.writeToNBT(new NBTTagCompound()))); - } - tag.setInteger("eut", recipe.mEUt); - tag.setInteger("duration", recipe.mDuration); - tag.setInteger("specialValue", recipe.mSpecialValue); - if (itemCost != null) { - tag.setTag("itemCost", writeList(itemCost.entrySet(), e -> { - NBTTagCompound ret = new NBTTagCompound(); - ret.setTag( - "id", - e.getKey() - .writeToNBT()); - ret.setInteger("count", e.getValue()); - return ret; - })); - } - if (fluidCost != null) { - tag.setTag("fluidCost", writeList(fluidCost.entrySet(), e -> { - NBTTagCompound ret = new NBTTagCompound(); - ret.setString( - "id", - e.getKey() - .getName()); - ret.setInteger("count", e.getValue()); - return ret; - })); - } - return tag; - } - - private static <T, NBT extends NBTBase> NBTTagList writeList(T[] arr, Function<T, NBT> ser) { - return writeList(Arrays.asList(arr), ser); - } - - private static <T, NBT extends NBTBase> NBTTagList writeList(Collection<T> arr, Function<T, NBT> ser) { - NBTTagList l = new NBTTagList(); - for (T t : arr) { - l.appendTag(ser.apply(t)); - } - return l; - } - - @Nullable - public static GT_Single_Recipe_Check tryLoad(GT_MetaTileEntity_MultiBlockBase parent, NBTTagCompound tag) { - return tryLoad(parent, parent.getRecipeMap(), tag); - } - - @Nullable - - public static GT_Single_Recipe_Check tryLoad(GT_MetaTileEntity_MultiBlockBase parent, - GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag) { - GT_Recipe found = tryFindRecipe(parent, recipeMap, tag); - if (found == null) return null; - return new GT_Single_Recipe_Check(parent, found, loadItemCost(tag), loadFluidCost(tag)); - } - - protected static ImmutableMap<Fluid, Integer> loadFluidCost(NBTTagCompound tag) { - return GT_Utility.streamCompounds(tag.getTagList("fluidCost", Constants.NBT.TAG_COMPOUND)) - .collect( - GT_Utility - .toImmutableMapSerial(t -> FluidRegistry.getFluid(t.getString("id")), t -> t.getInteger("count"))); - } - - protected static ImmutableMap<GT_Utility.ItemId, Integer> loadItemCost(NBTTagCompound tag) { - return GT_Utility.streamCompounds(tag.getTagList("itemCost", Constants.NBT.TAG_COMPOUND)) - .collect( - GT_Utility.toImmutableMapSerial( - t -> GT_Utility.ItemId.create(t.getCompoundTag("id")), - t -> t.getInteger("count"))); - } - - protected static GT_Recipe tryFindRecipe(GT_MetaTileEntity_MultiBlockBase parent, GT_Recipe.GT_Recipe_Map recipeMap, - NBTTagCompound tag) { - if (tag == null || tag.hasNoTags()) return null; - ItemStack[] inputs = GT_Utility.streamCompounds(tag.getTagList("inputs", Constants.NBT.TAG_COMPOUND)) - .map(GT_Utility::loadItem) - .toArray(ItemStack[]::new); - ItemStack[] outputs = GT_Utility.streamCompounds(tag.getTagList("outputs", Constants.NBT.TAG_COMPOUND)) - .map(GT_Utility::loadItem) - .toArray(ItemStack[]::new); - FluidStack[] fInputs = GT_Utility.streamCompounds(tag.getTagList("fInputs", Constants.NBT.TAG_COMPOUND)) - .map(FluidStack::loadFluidStackFromNBT) - .toArray(FluidStack[]::new); - FluidStack[] fOutputs = GT_Utility.streamCompounds(tag.getTagList("fOutputs", Constants.NBT.TAG_COMPOUND)) - .map(FluidStack::loadFluidStackFromNBT) - .toArray(FluidStack[]::new); - int eut = tag.getInteger("eut"); - GT_Recipe found = recipeMap - .findRecipe(parent.getBaseMetaTileEntity(), false, GT_Values.V[GT_Utility.getTier(eut)], fInputs, inputs); - int[] chances = tag.getIntArray("chances"); - if (chances.length == 0) chances = null; - if (found == null || !GT_Utility.equals(inputs, found.mInputs) - || !Arrays.equals(fInputs, found.mFluidInputs) - || !GT_Utility.equals(outputs, found.mOutputs) - || !Arrays.equals(fOutputs, found.mFluidOutputs) - || !Arrays.equals(chances, found.mChances) - || found.mDuration != tag.getInteger("duration") - || found.mEUt != eut - || found.mSpecialValue != tag.getInteger("specialValue")) return null; - return found; - } - - protected static Map<GT_Utility.ItemId, Integer> buildItemMap(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - Map<GT_Utility.ItemId, Integer> itemMap = new HashMap<>(); - for (ItemStack itemStack : multiBlockBase.getStoredInputs()) { - itemMap.merge(GT_Utility.ItemId.create(itemStack), itemStack.stackSize, Integer::sum); - } - return itemMap; - } - - protected static Map<Fluid, Integer> buildFluidMap(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - Map<Fluid, Integer> fluidMap = new HashMap<>(); - for (FluidStack fluidStack : multiBlockBase.getStoredFluids()) { - fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); - } - return fluidMap; - } - - public static Builder builder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - return new Builder(multiBlockBase); - } - - public static final class Builder { - - private final GT_MetaTileEntity_MultiBlockBase multiBlockBase; - - // In order to compute which items and fluids are consumed by the recipe, we compare the - // multi-block's items and fluids before and after inputs are consumed by the recipe. - private Map<GT_Utility.ItemId, Integer> beforeItems; - private Map<Fluid, Integer> beforeFluids; - private Map<GT_Utility.ItemId, Integer> afterItems; - private Map<Fluid, Integer> afterFluids; - - private GT_Recipe recipe; - - private Builder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - this.multiBlockBase = multiBlockBase; - } - - /** Call this before inputs are consumed by the recipe. */ - public Builder setBefore(ItemStack[] inputs, FluidStack[] fluids) { - beforeItems = buildItemMapDirect(inputs); - beforeFluids = buildFluidMapDirect(fluids); - return this; - } - - /** Call this after inputs are consumed by the recipe. */ - public Builder setAfter(ItemStack[] inputs, FluidStack[] fluids) { - afterItems = buildItemMapDirect(inputs); - afterFluids = buildFluidMapDirect(fluids); - return this; - } - - public Builder setRecipe(GT_Recipe recipe) { - this.recipe = recipe; - return this; - } - - static Map<GT_Utility.ItemId, Integer> buildItemMapDirect(ItemStack[] inputs) { - Map<GT_Utility.ItemId, Integer> itemMap = new HashMap<>(); - for (ItemStack itemStack : inputs) { - itemMap.merge(GT_Utility.ItemId.create(itemStack), itemStack.stackSize, Integer::sum); - } - return itemMap; - } - - static Map<Fluid, Integer> buildFluidMapDirect(FluidStack[] fluids) { - Map<Fluid, Integer> fluidMap = new HashMap<>(); - for (FluidStack fluidStack : fluids) { - fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); - } - return fluidMap; - } - - public GT_Single_Recipe_Check build() { - ImmutableMap.Builder<GT_Utility.ItemId, Integer> itemCostBuilder = ImmutableMap.builder(); - for (Map.Entry<GT_Utility.ItemId, Integer> entry : beforeItems.entrySet()) { - int cost = entry.getValue() - afterItems.getOrDefault(entry.getKey(), 0); - if (cost > 0) { - itemCostBuilder.put(entry.getKey(), cost); - } - } - - ImmutableMap.Builder<Fluid, Integer> fluidCostBuilder = ImmutableMap.builder(); - for (Map.Entry<Fluid, Integer> entry : beforeFluids.entrySet()) { - int cost = entry.getValue() - afterFluids.getOrDefault(entry.getKey(), 0); - if (cost > 0) { - fluidCostBuilder.put(entry.getKey(), cost); - } - } - - return new GT_Single_Recipe_Check( - multiBlockBase, - recipe, - itemCostBuilder.build(), - fluidCostBuilder.build()); - } - } -} diff --git a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java b/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java deleted file mode 100644 index ad0ca76a6d..0000000000 --- a/src/main/java/gregtech/api/util/GT_Single_Recipe_Check_Processing_Array.java +++ /dev/null @@ -1,244 +0,0 @@ -package gregtech.api.util; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; - -import com.google.common.collect.ImmutableMap; - -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; - -/** Processing Array-specialized version of {@link gregtech.api.util.GT_Single_Recipe_Check}. */ -public class GT_Single_Recipe_Check_Processing_Array extends GT_Single_Recipe_Check { - - protected final int recipeAmperage; - - /** - * The machine type that the locked recipe is for. We will not allow running with other machines. - */ - protected final ItemStack machineStack; - - protected GT_Single_Recipe_Check_Processing_Array(GT_MetaTileEntity_MultiBlockBase multiBlockBase, GT_Recipe recipe, - ImmutableMap<GT_Utility.ItemId, Integer> itemCost, ImmutableMap<Fluid, Integer> fluidCost, int recipeAmperage, - ItemStack machineStack) { - super(multiBlockBase, recipe, itemCost, fluidCost); - - this.recipeAmperage = recipeAmperage; - this.machineStack = machineStack; - } - - public int getRecipeAmperage() { - return recipeAmperage; - } - - @Override - public boolean checkRecipeInputsSingleStack(boolean consumeInputs) { - throw new UnsupportedOperationException("Use checkRecipeInputs(boolean, int) instead."); - } - - @Override - public boolean checkRecipeInputs(boolean consumeInputs) { - throw new UnsupportedOperationException("Use checkRecipeInputs(boolean, int) instead."); - } - - /** Returns the number of parallel recipes, or 0 if recipe is not satisfied at all. */ - public int checkRecipeInputs(boolean consumeInputs, int maxParallel) { - if (!GT_Utility.areStacksEqual(machineStack, multiBlockBase.mInventory[1])) { - // Machine stack was modified. This is not allowed, so stop processing. - return 0; - } - int parallel = maxParallel; - - List<ItemStack> items = null; - if (totalItemCost > 0) { - items = multiBlockBase.getStoredInputs(); - - Map<GT_Utility.ItemId, Integer> itemMap = new HashMap<>(); - for (ItemStack itemStack : items) { - itemMap.merge(GT_Utility.ItemId.createNoCopy(itemStack), itemStack.stackSize, Integer::sum); - } - - for (Map.Entry<GT_Utility.ItemId, Integer> entry : itemCost.entrySet()) { - parallel = Math.min(parallel, itemMap.getOrDefault(entry.getKey(), 0) / entry.getValue()); - if (parallel <= 0) { - return 0; - } - } - } - - List<FluidStack> fluids = null; - if (totalFluidCost > 0) { - fluids = multiBlockBase.getStoredFluids(); - - Map<Fluid, Integer> fluidMap = new HashMap<>(); - for (FluidStack fluidStack : fluids) { - fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); - } - - for (Map.Entry<Fluid, Integer> entry : fluidCost.entrySet()) { - parallel = Math.min(parallel, fluidMap.getOrDefault(entry.getKey(), 0) / entry.getValue()); - if (parallel <= 0) { - return 0; - } - } - } - - final int finalParallel = parallel; - if (consumeInputs) { - if (totalItemCost > 0) { - int remainingItemCost = totalItemCost * finalParallel; - Map<GT_Utility.ItemId, Integer> runningItemCost = itemCost.entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() * finalParallel)); - - for (ItemStack itemStack : items) { - GT_Utility.ItemId key = GT_Utility.ItemId.createNoCopy(itemStack); - int runningCost = runningItemCost.getOrDefault(key, 0); - int paid = Math.min(itemStack.stackSize, runningCost); - itemStack.stackSize -= paid; - runningItemCost.put(key, runningCost - paid); - - remainingItemCost -= paid; - if (remainingItemCost <= 0) { - break; - } - } - } - - if (totalFluidCost > 0) { - int remainingFluidCost = totalFluidCost * finalParallel; - Map<Fluid, Integer> runningFluidCost = fluidCost.entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() * finalParallel)); - - for (FluidStack fluidStack : fluids) { - Fluid key = fluidStack.getFluid(); - int runningCost = runningFluidCost.getOrDefault(key, 0); - int paid = Math.min(fluidStack.amount, runningCost); - fluidStack.amount -= paid; - runningFluidCost.put(key, runningCost - paid); - - remainingFluidCost -= paid; - if (remainingFluidCost <= 0) { - break; - } - } - } - } - - return finalParallel; - } - - @Nullable - - public static GT_Single_Recipe_Check tryLoad(GT_MetaTileEntity_MultiBlockBase parent, - GT_Recipe.GT_Recipe_Map recipeMap, NBTTagCompound tag, ItemStack machineStack) { - if (recipeMap == null || machineStack == null) return null; - GT_Recipe found = tryFindRecipe(parent, recipeMap, tag); - if (found == null) return null; - return new GT_Single_Recipe_Check_Processing_Array( - parent, - found, - loadItemCost(tag), - loadFluidCost(tag), - recipeMap.mAmperage, - machineStack.copy()); - } - - public static Builder processingArrayBuilder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - return new Builder(multiBlockBase); - } - - public static final class Builder { - - private final GT_MetaTileEntity_MultiBlockBase multiBlockBase; - - // In order to compute which items and fluids are consumed by the recipe, we compare the - // multi-block's items and fluids before and after inputs are consumed by the recipe. - private Map<GT_Utility.ItemId, Integer> beforeItems; - private Map<Fluid, Integer> beforeFluids; - private Map<GT_Utility.ItemId, Integer> afterItems; - private Map<Fluid, Integer> afterFluids; - - private GT_Recipe recipe; - private int recipeAmperage; - - private Builder(GT_MetaTileEntity_MultiBlockBase multiBlockBase) { - this.multiBlockBase = multiBlockBase; - } - - /** Call this before inputs are consumed by the recipe. */ - public Builder setBefore(ItemStack[] inputs, FluidStack[] fluids) { - beforeItems = buildItemMapDirect(inputs); - beforeFluids = buildFluidMapDirect(fluids); - return this; - } - - static Map<GT_Utility.ItemId, Integer> buildItemMapDirect(ItemStack[] inputs) { - Map<GT_Utility.ItemId, Integer> itemMap = new HashMap<>(); - for (ItemStack itemStack : inputs) { - itemMap.merge(GT_Utility.ItemId.create(itemStack), itemStack.stackSize, Integer::sum); - } - return itemMap; - } - - static Map<Fluid, Integer> buildFluidMapDirect(FluidStack[] fluids) { - Map<Fluid, Integer> fluidMap = new HashMap<>(); - for (FluidStack fluidStack : fluids) { - fluidMap.merge(fluidStack.getFluid(), fluidStack.amount, Integer::sum); - } - return fluidMap; - } - - /** Call this after inputs are consumed by the recipe. */ - public Builder setAfter(ItemStack[] inputs, FluidStack[] fluids) { - afterItems = buildItemMapDirect(inputs); - afterFluids = buildFluidMapDirect(fluids); - return this; - } - - public Builder setRecipe(GT_Recipe recipe) { - this.recipe = recipe; - return this; - } - - public Builder setRecipeAmperage(int recipeAmperage) { - this.recipeAmperage = recipeAmperage; - return this; - } - - public GT_Single_Recipe_Check_Processing_Array build() { - ImmutableMap.Builder<GT_Utility.ItemId, Integer> itemCostBuilder = ImmutableMap.builder(); - for (Map.Entry<GT_Utility.ItemId, Integer> entry : beforeItems.entrySet()) { - int cost = entry.getValue() - afterItems.getOrDefault(entry.getKey(), 0); - if (cost > 0) { - itemCostBuilder.put(entry.getKey(), cost); - } - } - - ImmutableMap.Builder<Fluid, Integer> fluidCostBuilder = ImmutableMap.builder(); - for (Map.Entry<Fluid, Integer> entry : beforeFluids.entrySet()) { - int cost = entry.getValue() - afterFluids.getOrDefault(entry.getKey(), 0); - if (cost > 0) { - fluidCostBuilder.put(entry.getKey(), cost); - } - } - - return new GT_Single_Recipe_Check_Processing_Array( - multiBlockBase, - recipe, - itemCostBuilder.build(), - fluidCostBuilder.build(), - recipeAmperage, - multiBlockBase.mInventory[1].copy()); - } - } -} diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java index d891545122..108b9dc2d9 100644 --- a/src/main/java/gregtech/api/util/GT_Utility.java +++ b/src/main/java/gregtech/api/util/GT_Utility.java @@ -493,6 +493,16 @@ public class GT_Utility { return ceilDiv(voltage, GT_Values.V[tier]); } + /** + * Rounds down partial voltage that exceeds tiered voltage, e.g. 4096 -> 2048 (EV) + */ + public static long roundDownVoltage(long voltage) { + if (voltage > V[V.length - 1]) { + return voltage; + } + return V[GT_Utility.getTier(voltage)]; + } + public static String getColoredTierNameFromVoltage(long voltage) { return getColoredTierNameFromTier(getTier(voltage)); } @@ -501,6 +511,9 @@ public class GT_Utility { return GT_Values.TIER_COLORS[tier] + GT_Values.VN[tier] + EnumChatFormatting.RESET; } + /** + * @return e.g. {@code " (LV)"} + */ @Nonnull public static String getTierNameWithParentheses(long voltage) { byte tier = getTier(voltage); @@ -1713,6 +1726,10 @@ public class GT_Utility { || Items.feather.getDamage(aStack2) == W); } + public static boolean areStacksEqualOrNull(ItemStack stack1, ItemStack stack2) { + return (stack1 == null && stack2 == null) || GT_Utility.areStacksEqual(stack1, stack2); + } + /** * Treat both null list, or both null item stack at same list position as equal. * <p> diff --git a/src/main/java/gregtech/api/util/VoidProtectionHelper.java b/src/main/java/gregtech/api/util/VoidProtectionHelper.java index 94c2dfcaaf..3ca9621f06 100644 --- a/src/main/java/gregtech/api/util/VoidProtectionHelper.java +++ b/src/main/java/gregtech/api/util/VoidProtectionHelper.java @@ -243,6 +243,8 @@ public class VoidProtectionHelper { Map<ItemStack, ParallelData> tParallels = new ItemStackMap<>(); int tSlotsFree = 0; for (ItemStack tItem : itemOutputs) { + // GT_RecipeBuilder doesn't handle null item output + if (tItem == null) continue; tItemOutputMap.merge(tItem, tItem.stackSize, Integer::sum); tParallels.put(tItem, new ParallelData(0, 0)); } diff --git a/src/main/java/gregtech/common/gui/modularui/widget/CheckRecipeResultSyncer.java b/src/main/java/gregtech/common/gui/modularui/widget/CheckRecipeResultSyncer.java new file mode 100644 index 0000000000..9028c66be8 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/widget/CheckRecipeResultSyncer.java @@ -0,0 +1,26 @@ +package gregtech.common.gui.modularui.widget; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; + +public class CheckRecipeResultSyncer extends FakeSyncWidget<CheckRecipeResult> { + + public CheckRecipeResultSyncer(Supplier<CheckRecipeResult> getter, Consumer<CheckRecipeResult> setter) { + super(getter, setter, (buffer, result) -> { + NetworkUtils.writeStringSafe(buffer, result.getID()); + result.encode(buffer); + }, buffer -> { + String id = NetworkUtils.readStringSafe(buffer); + CheckRecipeResult result = CheckRecipeResultRegistry.getSampleFromRegistry(id) + .newInstance(); + result.decode(buffer); + return result; + }); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java index 454f04066f..5575b0f9f1 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java @@ -24,6 +24,8 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; @@ -32,7 +34,6 @@ import com.gtnewhorizon.structurelib.structure.StructureDefinition; import gregtech.api.GregTech_API; import gregtech.api.enums.GT_Values; import gregtech.api.enums.ItemList; -import gregtech.api.enums.SoundResource; import gregtech.api.enums.Textures; import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.IHatchElement; @@ -45,6 +46,8 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_DataA import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_AssemblyLineUtils; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -185,13 +188,14 @@ public class GT_MetaTileEntity_AssemblyLine } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { if (GT_Values.D1) { GT_FML_LOGGER.info("Start ALine recipe check"); } ArrayList<ItemStack> tDataStickList = getDataItems(2); if (tDataStickList.isEmpty()) { - return false; + return CheckRecipeResultRegistry.NO_DATA_STICKS; } if (GT_Values.D1) { GT_FML_LOGGER.info("Stick accepted, " + tDataStickList.size() + " Data Sticks found"); @@ -305,7 +309,7 @@ public class GT_MetaTileEntity_AssemblyLine // Best not to run this recipe. if (!foundRecipe || tStack.length == 0) { - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } if (GT_Values.D1) { @@ -340,7 +344,7 @@ public class GT_MetaTileEntity_AssemblyLine if (GT_Values.D1) { GT_FML_LOGGER.info("Recipe successful"); } - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } private static int isStackValidIngredient(ItemStack aSlotStack, ItemStack aIngredient, ItemStack[] alts) { @@ -367,14 +371,6 @@ public class GT_MetaTileEntity_AssemblyLine } @Override - public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { - super.startSoundLoop(aIndex, aX, aY, aZ); - if (aIndex == 20) { - GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_MAGNETIZER_LOOP, 10, 1.0F, aX, aY, aZ); - } - } - - @Override public IStructureDefinition<GT_MetaTileEntity_AssemblyLine> getStructureDefinition() { return STRUCTURE_DEFINITION; } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java index 6250b11300..392b77eb74 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java @@ -9,6 +9,8 @@ import static gregtech.api.objects.XSTR.XSTR_INSTANCE; import java.util.ArrayList; +import javax.annotation.Nonnull; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; @@ -27,6 +29,8 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TooltipMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; @@ -62,14 +66,15 @@ public class GT_MetaTileEntity_Charcoal_Pit extends GT_MetaTileEntity_TooltipMul return true; } + @Nonnull @Override - public boolean checkRecipe(ItemStack aStack) { + public CheckRecipeResult checkProcessing() { if (!checkRecursiveBlocks()) { mEfficiency = 0; mEfficiencyIncrease = 0; mMaxProgresstime = 0; running = false; - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } if (mEfficiency == 0) { @@ -79,13 +84,13 @@ public class GT_MetaTileEntity_Charcoal_Pit extends GT_MetaTileEntity_TooltipMul // adds all the pollution at once when the recipe starts GT_Pollution.addPollution(getBaseMetaTileEntity(), mMaxProgresstime * getPollutionPerTick(null)); - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } else { mEfficiency = 0; mEfficiencyIncrease = 0; mMaxProgresstime = 0; + return CheckRecipeResultRegistry.NO_RECIPE; } - return false; } private boolean checkRecursiveBlocks() { diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java index 07023bfdcf..4c308370aa 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java @@ -12,6 +12,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; + import net.minecraft.block.Block; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -33,6 +35,8 @@ import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TooltipMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -116,15 +120,16 @@ public class GT_MetaTileEntity_Cleanroom extends GT_MetaTileEntity_TooltipMultiB return new String[] { "The base can be rectangular." }; } + @Nonnull @Override - public boolean checkRecipe(ItemStack aStack) { + public CheckRecipeResult checkProcessing() { mEfficiencyIncrease = 100; // use the standard overclock mechanism to determine duration and estimate a maximum consumption calculateOverclockedNessMultiInternal(40, 45 * Math.max(1, mHeight - 1), 1, getMaxInputVoltage(), false); // negate it to trigger the special energy consumption function. divide by 10 to get the actual final // consumption. mEUt /= -10; - return true; + return SimpleCheckRecipeResult.ofSuccess("cleanroom_running"); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java index ff28a9e40a..ff8fa7eeb1 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java @@ -24,6 +24,8 @@ import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; @@ -38,6 +40,9 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; @@ -183,7 +188,8 @@ public class GT_MetaTileEntity_DieselEngine } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { ArrayList<FluidStack> tFluids = getStoredFluids(); // fast track lookup @@ -219,30 +225,30 @@ public class GT_MetaTileEntity_DieselEngine } // Deplete that amount - if (!depleteInput(tLiquid)) return false; + if (!depleteInput(tLiquid)) return CheckRecipeResultRegistry.NO_FUEL_FOUND; boostEu = depleteInput(getBooster().getGas(2L * getAdditiveFactor())); // Check to prevent burning HOG without consuming it, if not boosted if (!boostEu && fuelValue > getNominalOutput()) { - return false; + return SimpleCheckRecipeResult.ofFailure("fuel_quality_too_high"); } // Deplete Lubricant. 1000L should = 1 hour of runtime (if baseEU = 2048) if ((mRuntime % 72 == 0 || mRuntime == 0) && !depleteInput(Materials.Lubricant.getFluid((boostEu ? 2L : 1L) * getAdditiveFactor()))) - return false; + return SimpleCheckRecipeResult.ofFailure("no_lubricant"); fuelRemaining = tFluid.amount; // Record available fuel this.mEUt = mEfficiency < 2000 ? 0 : getNominalOutput(); // Output 0 if startup is less than 20% this.mProgresstime = 1; this.mMaxProgresstime = 1; this.mEfficiencyIncrease = getEfficiencyIncrease(); - return true; + return CheckRecipeResultRegistry.GENERATING; } } this.mEUt = 0; this.mEfficiency = 0; - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java index 3a75cab071..e368e43518 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java @@ -40,12 +40,12 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_DistillationTower extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_DistillationTower> implements ISurvivalConstructable { @@ -191,72 +191,8 @@ public class GT_MetaTileEntity_DistillationTower extends } @Override - public boolean checkRecipe(ItemStack aStack) { - GT_Recipe tRecipe; - - ArrayList<ItemStack> tInputList = getStoredInputs(); - int tInputList_sS = tInputList.size(); - for (int i = 0; i < tInputList_sS - 1; i++) { - for (int j = i + 1; j < tInputList_sS; j++) { - if (GT_Utility.areStacksEqual(tInputList.get(i), tInputList.get(j))) { - if (tInputList.get(i).stackSize >= tInputList.get(j).stackSize) { - tInputList.remove(j--); - tInputList_sS = tInputList.size(); - } else { - tInputList.remove(i--); - tInputList_sS = tInputList.size(); - break; - } - } - } - } - ItemStack[] inputs = tInputList.toArray(new ItemStack[0]); - - ArrayList<FluidStack> tFluidList = getStoredFluids(); - for (int i = 0; i < tFluidList.size() - 1; i++) { - for (int j = i + 1; j < tFluidList.size(); j++) { - if (GT_Utility.areFluidsEqual(tFluidList.get(i), tFluidList.get(j))) { - if (tFluidList.get(i).amount >= tFluidList.get(j).amount) { - tFluidList.remove(j--); - } else { - tFluidList.remove(i--); - break; - } - } - } - } - - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(0, GT_Utility.getTier(tVoltage)); - FluidStack[] tFluids = tFluidList.toArray(new FluidStack[0]); - for (FluidStack tFluid : tFluids) { - tRecipe = GT_Recipe.GT_Recipe_Map.sDistillationRecipes.findRecipe( - getBaseMetaTileEntity(), - false, - gregtech.api.enums.GT_Values.V[tTier], - new FluidStack[] { tFluid }, - inputs); - if (tRecipe != null) { - if (!canOutputAll(tRecipe)) continue; - if (tRecipe.isRecipeInputEqual(true, tFluids, inputs)) { - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage, false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - if (this.mEUt > 0) { - this.mEUt = (-this.mEUt); - } - this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); - this.mOutputItems = new ItemStack[] { tRecipe.getOutput(0) }; - this.mOutputFluids = tRecipe.mFluidOutputs.clone(); - updateSlots(); - return true; - } - } - } - - return false; + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); } protected void onCasingFound() { diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java index 8c671f69a8..77b5073c86 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java @@ -33,6 +33,8 @@ import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.ForgeDirection; +import org.jetbrains.annotations.NotNull; + import com.google.common.collect.ImmutableList; import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; @@ -53,6 +55,8 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_DataAccess; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Utility; @@ -414,21 +418,38 @@ public abstract class GT_MetaTileEntity_DrillerBase } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerStack = getControllerSlot(); // Public pipe actions setElectricityStats(); int oldYHead = yHead; if (!checkPipesAndSetYHead() || !isEnergyEnough()) { stopMachine(); - return false; + return SimpleCheckRecipeResult.ofFailure("no_mining_pipe"); } putMiningPipesFromInputsInController(); - return switch (workState) { - case STATE_DOWNWARD -> workingDownward(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead); - case STATE_AT_BOTTOM -> workingAtBottom(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead); - case STATE_UPWARD -> workingUpward(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead); - default -> false; - }; + switch (workState) { + case STATE_DOWNWARD -> { + return workingDownward(controllerStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead) + ? SimpleCheckRecipeResult.ofSuccess("drilling") + : SimpleCheckRecipeResult.ofFailure("extracting_pipe"); + + } + case STATE_AT_BOTTOM -> { + return workingAtBottom(controllerStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead) + ? SimpleCheckRecipeResult.ofSuccess("drilling") + : SimpleCheckRecipeResult.ofFailure("no_mining_pipe"); + } + case STATE_UPWARD -> { + return workingUpward(controllerStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead) + ? SimpleCheckRecipeResult.ofSuccess("retracting_pipe") + : SimpleCheckRecipeResult.ofFailure("no_mining_pipe"); + } + default -> { + return SimpleCheckRecipeResult.ofFailure("no_mining_pipe"); + } + } } @Override 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 0557128b60..65890b0cc0 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 @@ -8,7 +8,6 @@ import static gregtech.api.enums.GT_HatchElement.Maintenance; import static gregtech.api.enums.GT_HatchElement.Muffler; import static gregtech.api.enums.GT_HatchElement.OutputBus; import static gregtech.api.enums.GT_HatchElement.OutputHatch; -import static gregtech.api.enums.GT_Values.V; import static gregtech.api.enums.GT_Values.VN; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_ACTIVE; @@ -46,13 +45,17 @@ import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.check.CheckRecipeResult; +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; @@ -187,128 +190,29 @@ public class GT_MetaTileEntity_ElectricBlastFurnace extends } @Override - public boolean checkRecipe(ItemStack aStack) { - if (inputSeparation) { - FluidStack[] tFluids = getStoredFluids().toArray(new FluidStack[0]); - for (GT_MetaTileEntity_Hatch_InputBus tBus : mInputBusses) { - ArrayList<ItemStack> tInputs = new ArrayList<>(); - tBus.mRecipeMap = getRecipeMap(); - - if (isValidMetaTileEntity(tBus)) { - for (int i = tBus.getBaseMetaTileEntity() - .getSizeInventory() - 1; i >= 0; i--) { - if (tBus.getBaseMetaTileEntity() - .getStackInSlot(i) != null) { - tInputs.add( - tBus.getBaseMetaTileEntity() - .getStackInSlot(i)); - } - } - } - ItemStack[] tItems = tInputs.toArray(new ItemStack[0]); - if (processRecipe(tItems, tFluids)) { - return true; - } + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, + @Nonnull GT_ParallelHelper helper) { + return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) + .setDuration(recipe.mDuration) + .setEUt(availableVoltage) + .setRecipeHeat(recipe.mSpecialValue) + .setMultiHeat(mHeatingCapacity) + .enableHeatOC() + .enableHeatDiscount() + .calculate(); } - return false; - } else { - return processRecipe(getCompactedInputs(), getCompactedFluids()); - } - } - - protected boolean processRecipe(ItemStack[] tItems, FluidStack[] tFluids) { - if (tItems.length == 0) return false; - - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - - GT_Recipe tRecipe = GT_Recipe.GT_Recipe_Map.sBlastRecipes - .findRecipe(getBaseMetaTileEntity(), false, V[tTier], tFluids, tItems); - if (tRecipe == null) return false; - if (this.mHeatingCapacity < tRecipe.mSpecialValue) return false; - if (!canOutputAll(tRecipe.mOutputs, getPollutionMultiplierAppliedFluids(tRecipe.mFluidOutputs))) return false; - if (!tRecipe.isRecipeInputEqual(true, tFluids, tItems)) return false; - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - - int tHeatCapacityDivTiers = (mHeatingCapacity - tRecipe.mSpecialValue) / 900; - byte overclockCount = calculateOverclockednessEBF(tRecipe.mEUt, tRecipe.mDuration, tVoltage); - if (this.mEUt > 0) { - this.mEUt = (-this.mEUt); - } - if (tHeatCapacityDivTiers > 0) { - this.mEUt = (int) (this.mEUt * (Math.pow(0.95, tHeatCapacityDivTiers))); - this.mMaxProgresstime >>= Math.min(tHeatCapacityDivTiers / 2, overclockCount); // extra free overclocking if - // possible - if (this.mMaxProgresstime < 1) this.mMaxProgresstime = 1; // no eu efficiency correction - } - this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); - this.mOutputItems = new ItemStack[] { tRecipe.getOutput(0), tRecipe.getOutput(1) }; - this.mOutputFluids = new FluidStack[] { tRecipe.getFluidOutput(0) }; - updateSlots(); - return true; - } - - /** - * Calcualtes overclocked ness using long integers - * - * @param aEUt - recipe EUt - * @param aDuration - recipe Duration - */ - protected byte calculateOverclockednessEBF(int aEUt, int aDuration, long maxInputVoltage) { - byte mTier = (byte) Math.max(0, GT_Utility.getTier(maxInputVoltage)), timesOverclocked = 0; - if (mTier == 0) { - // Long time calculation - long xMaxProgresstime = ((long) aDuration) << 1; - if (xMaxProgresstime > Integer.MAX_VALUE - 1) { - // make impossible if too long - mEUt = Integer.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUt = aEUt >> 2; - mMaxProgresstime = (int) xMaxProgresstime; - } - // return 0; - } else { - // Long EUt calculation - long xEUt = aEUt; - // Isnt too low EUt check? - long tempEUt = Math.max(xEUt, V[1]); - - mMaxProgresstime = aDuration; - - while (tempEUt <= V[mTier - 1]) { - tempEUt <<= 2; // this actually controls overclocking - // xEUt *= 4;//this is effect of everclocking - mMaxProgresstime >>= 1; // this is effect of overclocking - xEUt = mMaxProgresstime == 0 ? xEUt >> 1 : xEUt << 2; // U know, if the time is less than 1 tick make - // the machine use less power - timesOverclocked++; - } - if (xEUt > Integer.MAX_VALUE - 1) { - mEUt = Integer.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUt = (int) xEUt; - if (mEUt == 0) mEUt = 1; - if (mMaxProgresstime == 0) mMaxProgresstime = 1; // set time to 1 tick + @Override + protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return recipe.mSpecialValue <= mHeatingCapacity ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue); } - } - return timesOverclocked; - } - - private FluidStack[] getPollutionMultiplierAppliedFluids(FluidStack[] original) { - FluidStack[] fluids = GT_Utility.copyFluidArray(original); - for (FluidStack fluid : fluids) { - if (isPollutionFluid(fluid)) { - multiplyPollutionFluidAmount(fluid); - } - } - return fluids; + }; } public boolean addOutputHatchToTopList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { @@ -481,6 +385,7 @@ public class GT_MetaTileEntity_ElectricBlastFurnace extends public void loadNBTData(final NBTTagCompound aNBT) { super.loadNBTData(aNBT); if (aNBT.hasKey("isBussesSeparate")) { + // backward compatibility inputSeparation = aNBT.getBoolean("isBussesSeparate"); } } 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 d7b51c8de6..fd77caa201 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 @@ -22,6 +22,8 @@ import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.google.common.collect.ImmutableMap; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -52,6 +54,8 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; @@ -284,7 +288,8 @@ public abstract class GT_MetaTileEntity_FusionComputer } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { ArrayList<FluidStack> tFluidList = getStoredFluids(); int tFluidList_sS = tFluidList.size(); for (int i = 0; i < tFluidList_sS - 1; i++) { @@ -315,9 +320,9 @@ public abstract class GT_MetaTileEntity_FusionComputer if ((tRecipe == null && !mRunningOnLoad) || (maxEUStore() < tRecipe.mSpecialValue)) { turnCasingActive(false); this.mLastRecipe = null; - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } - if (!canOutputAll(tRecipe)) return false; + if (!canOutputAll(tRecipe)) return CheckRecipeResultRegistry.OUTPUT_FULL; if (mRunningOnLoad || tRecipe.isRecipeInputEqual(true, tFluids)) { this.mLastRecipe = tRecipe; this.mEUt = (this.mLastRecipe.mEUt * overclock(this.mLastRecipe.mSpecialValue)); @@ -326,10 +331,10 @@ public abstract class GT_MetaTileEntity_FusionComputer this.mOutputFluids = this.mLastRecipe.mFluidOutputs; turnCasingActive(true); mRunningOnLoad = false; - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } } - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } public abstract int tierOverclock(); diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java index d3c1267f3f..90413888b2 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java @@ -23,6 +23,8 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -38,6 +40,8 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMul import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_ModHandler; @@ -176,8 +180,9 @@ public class GT_MetaTileEntity_HeatExchanger extends } @Override - public boolean checkRecipe(ItemStack aStack) { - if (mInputHotFluidHatch.getFluid() == null) return true; + @NotNull + public CheckRecipeResult checkProcessing() { + if (mInputHotFluidHatch.getFluid() == null) return CheckRecipeResultRegistry.NO_RECIPE; int fluidAmountToConsume = mInputHotFluidHatch.getFluidAmount(); // how much fluid is in hatch @@ -224,7 +229,7 @@ public class GT_MetaTileEntity_HeatExchanger extends } else { // If we're working with neither, fail out superheated_threshold = 0; - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } superheated = fluidAmountToConsume >= superheated_threshold; // set the internal superheated flag if we have @@ -243,7 +248,7 @@ public class GT_MetaTileEntity_HeatExchanger extends mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("molten.solarsaltcold", fluidAmountToConsume), true); } this.mEfficiencyIncrease = 80; - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } private int useWater(int steam) { diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java index 3cceb98bf0..4fe75734c3 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java @@ -7,8 +7,6 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COM import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR_ACTIVE_GLOW; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR_GLOW; -import java.util.ArrayList; - import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; @@ -22,11 +20,11 @@ import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_CubicMultiBlockBase; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_ImplosionCompressor extends GT_MetaTileEntity_CubicMultiBlockBase<GT_MetaTileEntity_ImplosionCompressor> { @@ -108,44 +106,8 @@ public class GT_MetaTileEntity_ImplosionCompressor } @Override - public boolean checkRecipe(ItemStack aStack) { - ArrayList<ItemStack> tInputList = getStoredInputs(); - int tInputList_sS = tInputList.size(); - for (int i = 0; i < tInputList_sS - 1; i++) { - for (int j = i + 1; j < tInputList_sS; j++) { - if (GT_Utility.areStacksEqual(tInputList.get(i), tInputList.get(j))) { - if (tInputList.get(i).stackSize >= tInputList.get(j).stackSize) { - tInputList.remove(j--); - tInputList_sS = tInputList.size(); - } else { - tInputList.remove(i--); - tInputList_sS = tInputList.size(); - break; - } - } - } - } - ItemStack[] tInputs = tInputList.toArray(new ItemStack[0]); - if (!tInputList.isEmpty()) { - GT_Recipe tRecipe = GT_Recipe.GT_Recipe_Map.sImplosionRecipes - .findRecipe(getBaseMetaTileEntity(), false, 9223372036854775807L, null, tInputs); - if ((tRecipe != null) && canOutputAll(tRecipe) && tRecipe.isRecipeInputEqual(true, null, tInputs)) { - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - // OC THAT EXPLOSIVE SHIT!!! - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, getMaxInputVoltage(), false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - if (this.mEUt > 0) { - this.mEUt = (-this.mEUt); - } - this.mOutputItems = new ItemStack[] { tRecipe.getOutput(0), tRecipe.getOutput(1) }; - sendLoopStart((byte) 20); - updateSlots(); - return true; - } - } - return false; + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java index 438aa80219..af467e067b 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java @@ -36,6 +36,8 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.oredict.OreDictionary; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -54,6 +56,8 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -256,7 +260,8 @@ public class GT_MetaTileEntity_IntegratedOreFactory extends } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { if (!isInit) { initHash(); isInit = true; @@ -311,7 +316,7 @@ public class GT_MetaTileEntity_IntegratedOreFactory extends setCurrentParallelism(tRealUsed); if (tRealUsed == 0) { - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } depleteInput(GT_ModHandler.getDistilledWater(tRealUsed * 200L)); @@ -349,7 +354,7 @@ public class GT_MetaTileEntity_IntegratedOreFactory extends doCentrifuge(isImpureDust, isPureDust); } default -> { - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } } @@ -362,7 +367,7 @@ public class GT_MetaTileEntity_IntegratedOreFactory extends } this.updateSlots(); - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } @SafeVarargs diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java index 37495c60ea..8d165e34f4 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java @@ -27,6 +27,8 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; @@ -40,6 +42,8 @@ import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_ModHandler; @@ -239,8 +243,9 @@ public abstract class GT_MetaTileEntity_LargeBoiler } @Override - public boolean checkRecipe(ItemStack aStack) { - if (!isFuelValid()) return false; + @NotNull + public CheckRecipeResult checkProcessing() { + if (!isFuelValid()) return CheckRecipeResultRegistry.NO_FUEL_FOUND; // Do we have an integrated circuit with a valid configuration? if (Circuit_Integrated.isStackEqual(mInventory[1], true, true)) { int circuit_config = mInventory[1].getItemDamage(); @@ -263,7 +268,7 @@ public abstract class GT_MetaTileEntity_LargeBoiler this.mMaxProgresstime = adjustBurnTimeForConfig(runtimeBoost(tRecipe.mSpecialValue / 2)); this.mEUt = adjustEUtForConfig(getEUt()); this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease() * 4; - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } } } @@ -276,7 +281,7 @@ public abstract class GT_MetaTileEntity_LargeBoiler Math.max(1, runtimeBoost(tRecipe.mSpecialValue * 2))); this.mEUt = adjustEUtForConfig(getEUt()); this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease(); - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } } } @@ -302,7 +307,7 @@ public abstract class GT_MetaTileEntity_LargeBoiler this.mEfficiencyIncrease = 0; this.mSuperEfficencyIncrease = 20; } - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } } } @@ -328,7 +333,7 @@ public abstract class GT_MetaTileEntity_LargeBoiler this.mEfficiencyIncrease = 0; this.mSuperEfficencyIncrease = 20; } - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } } } @@ -336,7 +341,7 @@ public abstract class GT_MetaTileEntity_LargeBoiler } this.mMaxProgresstime = 0; this.mEUt = 0; - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } abstract int runtimeBoost(int mTime); diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java index 2c647aa458..ded2621fec 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java @@ -16,7 +16,6 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_CHEMICA import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; -import java.util.ArrayList; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -27,7 +26,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.IChatComponent; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; import com.gtnewhorizon.structurelib.StructureLibAPI; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; @@ -46,12 +44,11 @@ import gregtech.api.interfaces.IHeatingCoil; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Single_Recipe_Check; -import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_LargeChemicalReactor extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_LargeChemicalReactor> implements ISurvivalConstructable { @@ -169,68 +166,8 @@ public class GT_MetaTileEntity_LargeChemicalReactor extends } @Override - public boolean checkRecipe(ItemStack aStack) { - long tVoltage = getMaxInputVoltage(); - byte tier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - GT_Recipe tRecipe; - - if (mLockedToSingleRecipe && mSingleRecipeCheck != null) { - if (!mSingleRecipeCheck.checkRecipeInputsSingleStack(true)) { - return false; - } - tRecipe = mSingleRecipeCheck.getRecipe(); - } else { - ArrayList<ItemStack> tInputList = getStoredInputs(); - ArrayList<FluidStack> tFluidList = getStoredFluids(); - - ItemStack[] inputs = tInputList.toArray(new ItemStack[0]); - FluidStack[] fluids = tFluidList.toArray(new FluidStack[0]); - - if (inputs.length == 0 && fluids.length == 0) { - return false; - } - - GT_Single_Recipe_Check.Builder tSingleRecipeCheckBuilder = null; - if (mLockedToSingleRecipe) { - // We're locked to a single recipe, but haven't built the recipe checker yet. - // Build the checker on next successful recipe. - tSingleRecipeCheckBuilder = GT_Single_Recipe_Check.builder(this) - .setBefore(inputs, fluids); - } - - tRecipe = GT_Recipe.GT_Recipe_Map.sMultiblockChemicalRecipes.findRecipe( - getBaseMetaTileEntity(), - false, - false, - gregtech.api.enums.GT_Values.V[tier], - fluids, - inputs); - - if (tRecipe == null || !canOutputAll(tRecipe) || !tRecipe.isRecipeInputEqual(true, fluids, inputs)) { - return false; - } - - if (mLockedToSingleRecipe) { - mSingleRecipeCheck = tSingleRecipeCheckBuilder.setAfter(inputs, fluids) - .setRecipe(tRecipe) - .build(); - } - } - - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage, true); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - if (this.mEUt > 0) { - this.mEUt = (-this.mEUt); - } - - this.mOutputItems = tRecipe.mOutputs; - this.mOutputFluids = tRecipe.mFluidOutputs; - this.updateSlots(); - return true; + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic().enablePerfectOverclock(); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java index f31967674c..a8961ce542 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java @@ -28,6 +28,8 @@ import net.minecraft.world.IBlockAccess; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -41,6 +43,8 @@ import gregtech.api.items.GT_MetaGenerated_Tool; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_Utility; import gregtech.api.util.LightingHelper; import gregtech.common.items.GT_MetaGenerated_Tool_01; @@ -226,12 +230,15 @@ public abstract class GT_MetaTileEntity_LargeTurbine } @Override - public boolean checkRecipe(ItemStack aStack) { - if ((counter & 7) == 0 && (aStack == null || !(aStack.getItem() instanceof GT_MetaGenerated_Tool) - || aStack.getItemDamage() < 170 - || aStack.getItemDamage() > 179)) { + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerSlot = getControllerSlot(); + if ((counter & 7) == 0 + && (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool) + || controllerSlot.getItemDamage() < 170 + || controllerSlot.getItemDamage() > 179)) { stopMachine(); - return false; + return CheckRecipeResultRegistry.NO_TURBINE_FOUND; } ArrayList<FluidStack> tFluids = getStoredFluids(); if (!tFluids.isEmpty()) { @@ -244,24 +251,25 @@ public abstract class GT_MetaTileEntity_LargeTurbine .hasInventoryBeenModified()) { counter = 0; baseEff = GT_Utility.safeInt( - (long) ((5F + ((GT_MetaGenerated_Tool) aStack.getItem()).getToolCombatDamage(aStack)) * 1000F)); - optFlow = GT_Utility - .safeInt( - (long) Math.max( - Float.MIN_NORMAL, - ((GT_MetaGenerated_Tool) aStack.getItem()).getToolStats(aStack) - .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mToolSpeed - * 50)); - - overflowMultiplier = getOverflowMultiplier(aStack); - - flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mSteamMultiplier; - flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mGasMultiplier; - flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mPlasmaMultiplier; + (long) ((5F + + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolCombatDamage(controllerSlot)) + * 1000F)); + optFlow = GT_Utility.safeInt( + (long) Math.max( + Float.MIN_NORMAL, + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolStats(controllerSlot) + .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mToolSpeed + * 50)); + + overflowMultiplier = getOverflowMultiplier(controllerSlot); + + flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mSteamMultiplier; + flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mGasMultiplier; + flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mPlasmaMultiplier; if (optFlow <= 0 || baseEff <= 0) { stopMachine(); // in case the turbine got removed - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } } else { counter++; @@ -288,12 +296,12 @@ public abstract class GT_MetaTileEntity_LargeTurbine // stopMachine(); this.mEUt = 0; this.mEfficiency = 0; - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } else { this.mMaxProgresstime = 1; this.mEfficiencyIncrease = 10; // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here. - return true; + return CheckRecipeResultRegistry.GENERATING; } } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java index 9e54fe11a5..0eec9ef238 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java @@ -16,6 +16,8 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import gregtech.api.GregTech_API; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; @@ -23,6 +25,8 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.items.GT_MetaGenerated_Tool; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; @@ -202,12 +206,15 @@ public class GT_MetaTileEntity_LargeTurbine_Plasma extends GT_MetaTileEntity_Lar } @Override - public boolean checkRecipe(ItemStack aStack) { - if ((counter & 7) == 0 && (aStack == null || !(aStack.getItem() instanceof GT_MetaGenerated_Tool) - || aStack.getItemDamage() < 170 - || aStack.getItemDamage() > 179)) { + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerSlot = getControllerSlot(); + if ((counter & 7) == 0 + && (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool) + || controllerSlot.getItemDamage() < 170 + || controllerSlot.getItemDamage() > 179)) { stopMachine(); - return false; + return CheckRecipeResultRegistry.NO_TURBINE_FOUND; } ArrayList<FluidStack> tFluids = getStoredFluids(); if (!tFluids.isEmpty()) { @@ -219,19 +226,20 @@ public class GT_MetaTileEntity_LargeTurbine_Plasma extends GT_MetaTileEntity_Lar .hasInventoryBeenModified()) { counter = 0; baseEff = GT_Utility.safeInt( - (long) ((5F + ((GT_MetaGenerated_Tool) aStack.getItem()).getToolCombatDamage(aStack)) * 1000F)); - optFlow = GT_Utility - .safeInt( - (long) Math.max( - Float.MIN_NORMAL, - ((GT_MetaGenerated_Tool) aStack.getItem()).getToolStats(aStack) - .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mToolSpeed - * 50)); - overflowMultiplier = getOverflowMultiplier(aStack); - - flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mSteamMultiplier; - flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mGasMultiplier; - flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mPlasmaMultiplier; + (long) ((5F + + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolCombatDamage(controllerSlot)) + * 1000F)); + optFlow = GT_Utility.safeInt( + (long) Math.max( + Float.MIN_NORMAL, + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolStats(controllerSlot) + .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mToolSpeed + * 50)); + overflowMultiplier = getOverflowMultiplier(controllerSlot); + + flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mSteamMultiplier; + flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mGasMultiplier; + flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mPlasmaMultiplier; } else { counter++; } @@ -239,7 +247,7 @@ public class GT_MetaTileEntity_LargeTurbine_Plasma extends GT_MetaTileEntity_Lar if (optFlow <= 0 || baseEff <= 0) { stopMachine(); // in case the turbine got removed - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } int newPower = fluidIntoPower(tFluids, optFlow, baseEff, overflowMultiplier, flowMultipliers); // How much the @@ -263,13 +271,13 @@ public class GT_MetaTileEntity_LargeTurbine_Plasma extends GT_MetaTileEntity_Lar // stopMachine(); this.mEUt = 0; this.mEfficiency = 0; - return false; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; } else { this.mMaxProgresstime = 20; this.mEfficiencyIncrease = 200; // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here. - return true; + return CheckRecipeResultRegistry.GENERATING; } } diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java index e04255c28b..c80062ff09 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java @@ -22,6 +22,8 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; @@ -35,6 +37,8 @@ import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -142,9 +146,10 @@ public class GT_MetaTileEntity_MultiFurnace } @Override - public boolean checkRecipe(ItemStack aStack) { + @NotNull + public CheckRecipeResult checkProcessing() { ArrayList<ItemStack> tInputList = getStoredInputs(); - if (tInputList.isEmpty()) return false; + if (tInputList.isEmpty()) return CheckRecipeResultRegistry.NO_RECIPE; int mVolatage = GT_Utility.safeInt(getMaxInputVoltage()); int tMaxParallel = this.mLevel; @@ -182,15 +187,16 @@ public class GT_MetaTileEntity_MultiFurnace this.mEfficiencyIncrease = 10000; calculateOverclockedNessMultiInternal(4, 512, 1, mVolatage, false); // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return CheckRecipeResultRegistry.NO_RECIPE; this.mEUt = GT_Utility.safeInt(((long) mEUt) * (this.mLevel / 8) / (long) this.mCostDiscount, 1); - if (mEUt == Integer.MAX_VALUE - 1) return false; + if (mEUt == Integer.MAX_VALUE - 1) return CheckRecipeResultRegistry.NO_RECIPE; if (this.mEUt > 0) this.mEUt = (-this.mEUt); } updateSlots(); - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } @Override 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 6018cb7450..ca68d3ad4c 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 @@ -16,7 +16,7 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; import static gregtech.api.util.GT_StructureUtility.ofFrame; -import java.util.ArrayList; +import javax.annotation.Nonnull; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -24,7 +24,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; @@ -44,8 +43,10 @@ import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; @@ -232,72 +233,21 @@ public class GT_MetaTileEntity_NanoForge extends } @Override - public boolean checkRecipe(ItemStack aStack) { - GT_Recipe.GT_Recipe_Map map = getRecipeMap(); - FluidStack[] tFluidInputs = getCompactedFluids(); - if (inputSeparation) { - ArrayList<ItemStack> tInputList = new ArrayList<>(); - for (GT_MetaTileEntity_Hatch_InputBus tBus : mInputBusses) { - for (int i = tBus.getSizeInventory() - 1; i >= 0; i--) { - if (tBus.getStackInSlot(i) != null) tInputList.add(tBus.getStackInSlot(i)); - } - ItemStack[] tInputs = tInputList.toArray(new ItemStack[0]); - if (processRecipe(tInputs, tFluidInputs, map)) return true; - else tInputList.clear(); - } - } else { - ItemStack[] tItemInputs = getStoredInputs().toArray(new ItemStack[0]); - return processRecipe(tItemInputs, tFluidInputs, map); - } - return false; - } - - private boolean processRecipe(ItemStack[] tItemInputs, FluidStack[] tFluidInputs, GT_Recipe.GT_Recipe_Map map) { - lEUt = 0; - mOutputItems = null; - mOutputFluids = null; - long tTotalEU = getMaxInputEu(); - GT_Recipe tRecipe = map - .findRecipe(getBaseMetaTileEntity(), null, false, false, tTotalEU, tFluidInputs, null, tItemInputs); - - if (tRecipe == null) return false; - if (tRecipe.mSpecialValue > mSpecialTier) return false; - if (!canOutputAll(tRecipe)) return false; - - if (tRecipe.isRecipeInputEqual(true, tFluidInputs, tItemInputs)) { - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - this.mMaxProgresstime = tRecipe.mDuration; - this.lEUt = -tRecipe.mEUt; - calculateOverclockedNessMultiInternal( - tRecipe.mEUt, - tRecipe.mDuration, - 1, - tTotalEU, - tRecipe.mSpecialValue < mSpecialTier); - - if (this.lEUt == Long.MAX_VALUE - 1 || this.mMaxProgresstime == Integer.MAX_VALUE - 1) return false; - - if (this.lEUt > 0) { - this.lEUt *= -1; - } + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { - ArrayList<ItemStack> tOutputs = new ArrayList<>(); - for (int i = 0; i < tRecipe.mOutputs.length; i++) { - if (getBaseMetaTileEntity().getRandomNumber(10000) < tRecipe.getOutputChance(i)) { - tOutputs.add(tRecipe.getOutput(i)); - } + @Override + protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return recipe.mSpecialValue <= mSpecialTier ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; } + }; + } - this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); - mOutputItems = tOutputs.toArray(new ItemStack[0]); - mOutputFluids = tRecipe.mFluidOutputs.clone(); - updateSlots(); - - return true; - } - - return false; + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(getMaxInputEu()); + logic.setAvailableAmperage(1); } @Override @@ -371,7 +321,8 @@ public class GT_MetaTileEntity_NanoForge extends @Override public void loadNBTData(final NBTTagCompound aNBT) { super.loadNBTData(aNBT); - if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) { + if (aNBT.hasKey("mSeparate")) { + // backward compatibility inputSeparation = aNBT.getBoolean("mSeparate"); } mSpecialTier = aNBT.getByte("mSpecialTier"); diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java index 2e82efa4f9..e531108e1a 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java @@ -14,6 +14,8 @@ import static gregtech.api.util.GT_StructureUtility.ofCoil; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; + import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; @@ -29,14 +31,16 @@ import gregtech.api.enums.HeatingCoilLevel; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; 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; public class GT_MetaTileEntity_OilCracker extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_OilCracker> implements ISurvivalConstructable { @@ -168,42 +172,17 @@ public class GT_MetaTileEntity_OilCracker extends GT_MetaTileEntity_EnhancedMult } @Override - public boolean checkRecipe(ItemStack aStack) { - ArrayList<FluidStack> tInputList = getStoredFluids(); - FluidStack[] tFluidInputs = tInputList.toArray(new FluidStack[0]); - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - - GT_Recipe tRecipe = getRecipeMap().findRecipe( - getBaseMetaTileEntity(), - false, - gregtech.api.enums.GT_Values.V[tTier], - tFluidInputs, - mInventory[1]); - - if (tRecipe == null) return false; - if (!canOutputAll(tRecipe)) return false; - - if (tRecipe.isRecipeInputEqual(true, tFluidInputs, mInventory[1])) { - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage, false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - - // heatLevel.getTier() starts at 0 - if (this.heatLevel.getTier() < 5) { - this.mEUt *= 1 - (0.1D * (this.heatLevel.getTier() + 1)); - } else { - this.mEUt *= 0.5; + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, + @Nonnull GT_ParallelHelper helper) { + return super.createOverclockCalculator(recipe, helper) + .setEUtDiscount(Math.max((0.1F * (heatLevel.getTier() + 1.0F)), 0.5F)); } - - if (this.mEUt > 0) this.mEUt = (-this.mEUt); - - this.mOutputFluids = new FluidStack[] { tRecipe.getFluidOutput(0) }; - return true; - } - return 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 8605f3643f..2cfbd1a30e 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 @@ -9,7 +9,6 @@ import static gregtech.api.enums.GT_HatchElement.InputHatch; import static gregtech.api.enums.GT_HatchElement.Maintenance; import static gregtech.api.enums.GT_HatchElement.OutputBus; import static gregtech.api.enums.GT_Values.AuthorBlueWeabo; -import static gregtech.api.enums.GT_Values.V; import static gregtech.api.enums.GT_Values.VN; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE; @@ -21,6 +20,8 @@ import static gregtech.api.util.GT_StructureUtility.ofFrame; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; + import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -31,6 +32,8 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; @@ -63,13 +66,17 @@ import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.GregTechTileClientEvents; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -515,141 +522,116 @@ public class GT_MetaTileEntity_PCBFactory extends } @Override - public boolean checkRecipe(ItemStack aStack) { - mCurrentParallel = 0; - GT_Recipe.GT_Recipe_Map aMap = getRecipeMap(); - FluidStack[] tFluidInputs = getStoredFluids().toArray(new FluidStack[0]); - if (inputSeparation) { - ArrayList<ItemStack> tInputList = new ArrayList<>(); - for (GT_MetaTileEntity_Hatch_InputBus tBus : mInputBusses) { - for (int i = tBus.getSizeInventory() - 1; i >= 0; i--) { - if (tBus.getStackInSlot(i) != null) tInputList.add(tBus.getStackInSlot(i)); + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + // Here we check the dynamic parallels, which depend on the recipe + int numberOfNanites = 0; + ItemStack aNanite = recipe.getRepresentativeInput(1); + ItemData naniteData = GT_OreDictUnificator.getAssociation(aNanite); + if (naniteData != null && naniteData.mPrefix != null && naniteData.mPrefix.equals(OrePrefixes.nanite)) { + for (ItemStack aItem : inputItems) { + if (aItem != null && aItem.isItemEqual(aNanite)) { + numberOfNanites += aItem.stackSize; + } + } } - ItemStack[] tInputs = tInputList.toArray(new ItemStack[0]); - if (processRecipe(aStack, tInputs, tFluidInputs, aMap)) return true; - else tInputList.clear(); - } - } else { - ItemStack[] tItemInputs = getStoredInputs().toArray(new ItemStack[0]); - return processRecipe(aStack, tItemInputs, tFluidInputs, aMap); - } + maxParallel = (int) Math.max(Math.ceil(Math.log(numberOfNanites) / Math.log(2) + 0.00001), 1); + mMaxParallel = maxParallel; - return false; - } - - private boolean processRecipe(ItemStack aStack, ItemStack[] aItemInputs, FluidStack[] aFluidInputs, - GT_Recipe.GT_Recipe_Map aMap) { - mOutputItems = null; - mOutputFluids = null; - if (aItemInputs == null || aFluidInputs == null) { - return false; - } + int recipeBitMap = recipe.mSpecialValue; - long voltage = getAverageInputVoltage(); - long amps = getMaxInputAmps(); - int tier = GT_Utility.getTier(voltage); + if (((recipeBitMap & mBioBitMap) == mBioBitMap && !mBioUpgrade)) + return SimpleCheckRecipeResult.ofFailure("bio_upgrade_missing"); - GT_Recipe tRecipe = aMap - .findRecipe(getBaseMetaTileEntity(), null, true, false, V[tier], aFluidInputs, aStack, aItemInputs); + int requiredPCBTier = 0; + if ((recipeBitMap & mTier3BitMap) == mTier3BitMap) requiredPCBTier = 3; + if ((recipeBitMap & mTier2BitMap) == mTier2BitMap) requiredPCBTier = 2; + if ((recipeBitMap & mTier1BitMap) == mTier1BitMap) requiredPCBTier = 1; - if (tRecipe == null) { - return false; - } + if (requiredPCBTier > mTier) return CheckRecipeResultRegistry.insufficientMachineTier(requiredPCBTier); - int recipeBitMap = tRecipe.mSpecialValue; + return CheckRecipeResultRegistry.SUCCESSFUL; + } - int aNanitesOfRecipe = 0; + @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); + } - ItemStack aNanite = tRecipe.getRepresentativeInput(1); - if (GT_OreDictUnificator.getAssociation(aNanite).mPrefix.equals(OrePrefixes.nanite)) { - for (ItemStack aItem : aItemInputs) { - if (aItem.isItemEqual(aNanite)) { - aNanitesOfRecipe += aItem.stackSize; + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, + @Nonnull GT_ParallelHelper helper) { + if (isNoOC()) { + return GT_OverclockCalculator.ofNoOverclock(recipe); + } + GT_OverclockCalculator calculator = super.createOverclockCalculator(recipe, helper) + .setEUtDiscount((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) + .setSpeedBoost(getDurationMultiplierFromRoughness()); + if (mOCTier2) { + calculator.enablePerfectOC(); } + return calculator; } - } - int aMaxParallel = (int) Math.max(Math.ceil(Math.log(aNanitesOfRecipe) / Math.log(2) + 0.00001), 1); - mMaxParallel = aMaxParallel; - float aExtraPower = (float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled); + @Nonnull + @Override + protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) { + return super.createParallelHelper(recipe) + .setEUtModifier((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)); + } - if (tRecipe.mEUt > voltage) { - return false; - } + @NotNull + @Override + public CheckRecipeResult process() { + CheckRecipeResult result = super.process(); - boolean recipeAllowed = (((recipeBitMap & mTier1BitMap) == mTier1BitMap && (mTier >= 1)) - || ((recipeBitMap & mTier2BitMap) == mTier2BitMap && (mTier >= 2)) - || ((recipeBitMap & mTier3BitMap) == mTier3BitMap && (mTier >= 3))) - && ((recipeBitMap & mBioBitMap) == 0 || ((recipeBitMap & mBioBitMap) == mBioBitMap && mBioUpgrade)); - - if (recipeAllowed) { - GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(tRecipe) - .setMachine(this) - .setItemInputs(aItemInputs) - .setFluidInputs(aFluidInputs) - .setMaxParallel(aMaxParallel) - .setAvailableEUt(getMaxInputEu()) - .setEUtModifier(aExtraPower) - .enableConsumption() - .build(); - mCurrentParallel = helper.getCurrentParallel(); - - if (mCurrentParallel > 0) { - this.mEfficiency = (getMaxEfficiency(aStack) - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = getMaxEfficiency(aStack); - this.lEUt = -(long) Math.ceil(tRecipe.mEUt * mCurrentParallel * aExtraPower); - this.mMaxProgresstime = (int) Math.ceil(tRecipe.mDuration * Math.pow(mRoughnessMultiplier, 2)); - - if (mOCTier1 || mOCTier2) { - GT_OverclockCalculator calc = new GT_OverclockCalculator().setRecipeEUt(tRecipe.mEUt) - .setDuration(tRecipe.mDuration) - .setEUt(voltage) - .setAmperage(amps) - .setEUtDiscount(aExtraPower) - .setSpeedBoost((float) Math.pow(mRoughnessMultiplier, 2)); - if (mOCTier2) { - calc.enablePerfectOC(); - } - calc.calculate(); - this.lEUt = calc.getConsumption(); - this.mMaxProgresstime = calc.getDuration(); + if (!result.wasSuccessful()) { + return result; } - if (this.lEUt == Long.MAX_VALUE - 1 || this.mProgresstime == Integer.MAX_VALUE - 1) return false; + mCurrentParallel = calculatedParallels; - if (this.lEUt > 0) { - this.lEUt *= -1; - } + ItemStack controllerStack = getControllerSlot(); - ArrayList<ItemStack> tOutputs = new ArrayList<>(); - int remainingEfficiency = getMaxEfficiency(aStack); - for (int j = 0; j < (int) Math.ceil(getMaxEfficiency(aStack) / 10000.0f); j++) { - int chanced = getBaseMetaTileEntity().getRandomNumber(10000); - if (chanced >= remainingEfficiency) { - continue; - } - for (ItemStack tOutput : tRecipe.mOutputs) { - if (tOutput == null) { - break; + 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; + } + chancedOutputs.add(tOutput); } - tOutputs.add(tOutput.copy()); + remainingEfficiency -= 10000; } - remainingEfficiency -= 10000; + setOutputItems(chancedOutputs.toArray(new ItemStack[0])); } - for (ItemStack itemStack : tOutputs) { - itemStack.stackSize *= mCurrentParallel; - } - - mOutputItems = tOutputs.toArray(new ItemStack[0]); - mOutputFluids = tRecipe.mFluidOutputs.clone(); - updateSlots(); - - return true; + return result; } - } + }; + } - return false; + private boolean isNoOC() { + return !mOCTier1 && !mOCTier2; + } + + private float getDurationMultiplierFromRoughness() { + return (float) Math.pow(mRoughnessMultiplier, 2); } private int ticker = 0; @@ -810,44 +792,6 @@ public class GT_MetaTileEntity_PCBFactory extends } @Override - protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, - boolean perfectOC) { - int hatches = Math.max(getExoticEnergyHatches().size(), 1); - long zTime = aDuration; - long zEUt = aEUt; - if (maxInputVoltage < zEUt) { - this.lEUt = Long.MAX_VALUE - 1; - this.mMaxProgresstime = Integer.MAX_VALUE - 1; - return; - } - - while (zEUt < maxInputVoltage) { - zEUt = zEUt << 2; - zTime = zTime >> (perfectOC ? 2 : 1); - if (zTime <= 1) { - break; - } - } - - if (zTime <= 0) { - zTime = 1; - } - - while (zEUt * mAmperage > maxInputVoltage * getMaxInputAmps() / hatches) { - zEUt = zEUt >> 2; - zTime = zTime << (perfectOC ? 2 : 1); - } - - if (zEUt > maxInputVoltage) { - zEUt = zEUt >> 2; - zTime = zTime << (perfectOC ? 2 : 1); - } - - this.lEUt = zEUt * mAmperage; - this.mMaxProgresstime = (int) zTime; - } - - @Override protected long getActualEnergyUsage() { return (-this.lEUt * 10000) / Math.min(Math.max(1000, mEfficiency), 10000); } @@ -1071,7 +1015,8 @@ public class GT_MetaTileEntity_PCBFactory extends @Override public void loadNBTData(final NBTTagCompound aNBT) { super.loadNBTData(aNBT); - if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) { + if (aNBT.hasKey("mSeparate")) { + // backward compatibility inputSeparation = aNBT.getBoolean("mSeparate"); } mBioUpgrade = aNBT.getBoolean("mBioUpgrade"); diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java index 2a92fff523..d1a2a9dd7f 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java @@ -33,6 +33,8 @@ import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; @@ -50,6 +52,8 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_ExoticEnergyInputHelper; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; @@ -661,18 +665,19 @@ public class GT_MetaTileEntity_PlasmaForge extends GT_MetaTileEntity_AbstractMul } @Override - public boolean checkRecipe(ItemStack aStack) { - boolean recipe_process = processRecipe(getCompactedInputs(), getCompactedFluids()); + @NotNull + public CheckRecipeResult checkProcessing() { + CheckRecipeResult recipe_process = processRecipe(getCompactedInputs(), getCompactedFluids()); // If recipe cannot be found then continuity is broken and reset running time to 0. - if (!recipe_process) { + if (!recipe_process.wasSuccessful()) { resetDiscount(); } return recipe_process; } - protected boolean processRecipe(ItemStack[] tItems, FluidStack[] tFluids) { + protected CheckRecipeResult processRecipe(ItemStack[] tItems, FluidStack[] tFluids) { // Gets the EU input of the long tTotalEU = GT_ExoticEnergyInputHelper.getTotalEuMulti(getExoticAndNormalEnergyHatchList()); @@ -682,10 +687,11 @@ public class GT_MetaTileEntity_PlasmaForge extends GT_MetaTileEntity_AbstractMul .findRecipe(getBaseMetaTileEntity(), false, tTotalEU, tFluids, tItems); // Check if recipe found. - if (tRecipe_0 == null) return false; + if (tRecipe_0 == null) return CheckRecipeResultRegistry.NO_RECIPE; // If coil heat capacity is too low, refuse to start recipe. - if (mHeatingCapacity <= tRecipe_0.mSpecialValue) return false; + if (mHeatingCapacity <= tRecipe_0.mSpecialValue) + return CheckRecipeResultRegistry.insufficientHeat(tRecipe_0.mSpecialValue); // Reduce fuel quantity if machine has been running for long enough. GT_Recipe tRecipe_1 = tRecipe_0.copy(); @@ -705,9 +711,9 @@ public class GT_MetaTileEntity_PlasmaForge extends GT_MetaTileEntity_AbstractMul } } - if (!canOutputAll(tRecipe_1)) return false; + if (!canOutputAll(tRecipe_1)) return CheckRecipeResultRegistry.OUTPUT_FULL; // Takes items/fluids from hatches/busses. - if (!tRecipe_1.isRecipeInputEqual(true, tFluids, tItems)) return false; + if (!tRecipe_1.isRecipeInputEqual(true, tFluids, tItems)) return CheckRecipeResultRegistry.NO_RECIPE; // Logic for overclocking calculations. double EU_input_tier = log(tTotalEU) / log4; @@ -727,7 +733,7 @@ public class GT_MetaTileEntity_PlasmaForge extends GT_MetaTileEntity_AbstractMul // All conditions met so increment running_time. running_time += mMaxProgresstime; - return true; + return CheckRecipeResultRegistry.SUCCESSFUL; } @Override 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 1c4374fd34..ff918fe196 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 @@ -1,6 +1,10 @@ package gregtech.common.tileentities.machines.multi; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; import static gregtech.api.enums.GT_HatchElement.Energy; import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; import static gregtech.api.enums.GT_HatchElement.InputBus; @@ -8,8 +12,7 @@ import static gregtech.api.enums.GT_HatchElement.InputHatch; import static gregtech.api.enums.GT_HatchElement.Maintenance; import static gregtech.api.enums.GT_HatchElement.OutputBus; import static gregtech.api.enums.GT_HatchElement.OutputHatch; -import static gregtech.api.enums.GT_Values.V; -import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.GT_Values.*; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE_GLOW; @@ -17,11 +20,9 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_AR import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; import static gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine.isValidForLowGravity; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; + +import javax.annotation.Nonnull; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -29,10 +30,14 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; import com.google.common.collect.ImmutableList; -import com.gtnewhorizon.structurelib.structure.IStructureElement; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; import com.gtnewhorizons.modularui.api.drawable.IDrawable; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; @@ -50,33 +55,55 @@ import gregtech.api.interfaces.IHatchElement; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_CubicMultiBlockBase; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +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; -import gregtech.api.util.GT_Single_Recipe_Check; -import gregtech.api.util.GT_Single_Recipe_Check_Processing_Array; +import gregtech.api.util.GT_StructureUtility; import gregtech.api.util.GT_Utility; import gregtech.common.blocks.GT_Item_Machines; -public class GT_MetaTileEntity_ProcessingArray - extends GT_MetaTileEntity_CubicMultiBlockBase<GT_MetaTileEntity_ProcessingArray> { +public class GT_MetaTileEntity_ProcessingArray extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_ProcessingArray> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_ProcessingArray> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_ProcessingArray>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose(new String[][] { { "hhh", "hhh", "hhh" }, { "h~h", "h-h", "hhh" }, { "hhh", "hhh", "hhh" }, })) + .addElement( + 'h', + ofChain( + lazy( + t -> GT_StructureUtility.<GT_MetaTileEntity_ProcessingArray>buildHatchAdder() + .atLeastList(t.getAllowedHatches()) + .casingIndex(48) + .dot(1) + .build()), + onElementPass(t -> t.mCasingAmount++, ofBlock(GregTech_API.sBlockCasings4, 0)))) + .build(); + + private int mCasingAmount = 0; private GT_Recipe_Map mLastRecipeMap; - private GT_Recipe mLastRecipe; + private ItemStack lastControllerStack; private int tTier = 0; private int mMult = 0; private boolean downtierUEV = true; - private String mMachineName = ""; - // Value needed so that the PA can use energy above MAX voltage - private long mEUPerTick = 0; public GT_MetaTileEntity_ProcessingArray(int aID, String aName, String aNameRegional) { super(aID, aName, aNameRegional); @@ -148,24 +175,12 @@ public class GT_MetaTileEntity_ProcessingArray return new ITexture[] { Textures.BlockIcons.casingTexturePages[0][48] }; } - // TODO: Expand so it also does the non recipe map recipes - /* - * public void remoteRecipeCheck() { if (mInventory[1] == null) return; String tmp = - * mInventory[1].getUnlocalizedName().replaceAll("gt.blockmachines.basicmachine.", ""); if - * (tmp.startsWith("replicator")) { } else if (tmp.startsWith("brewery")) { } else if (tmp.startsWith("packer")) { } - * else if (tmp.startsWith("printer")) { } else if (tmp.startsWith("disassembler")) { } else if - * (tmp.startsWith("massfab")) { } else if (tmp.startsWith("scanner")) { } } - */ - - // Gets the recipe map for the given machine through its unlocalized name @Override public GT_Recipe_Map getRecipeMap() { - if (isCorrectMachinePart(mInventory[1])) { - int length = mInventory[1].getUnlocalizedName() - .length(); - String aMachineName = mInventory[1].getUnlocalizedName() - .substring(17, length - 8); - return GT_ProcessingArray_Manager.giveRecipeMap(aMachineName); + if (isCorrectMachinePart(getControllerSlot())) { + // Gets the recipe map for the given machine through its unlocalized name + return GT_ProcessingArray_Manager + .giveRecipeMap(GT_ProcessingArray_Manager.getMachineName(getControllerSlot())); } return null; } @@ -177,8 +192,12 @@ public class GT_MetaTileEntity_ProcessingArray } @Override - public boolean supportsSingleRecipeLocking() { - return true; + protected void sendStartMultiBlockSoundLoop() { + SoundResource sound = GT_ProcessingArray_Manager + .getSoundResource(GT_ProcessingArray_Manager.getMachineName(getControllerSlot())); + if (sound != null) { + sendLoopStart((byte) sound.id); + } } @Override @@ -191,220 +210,85 @@ public class GT_MetaTileEntity_ProcessingArray } @Override - protected boolean checkRecipe() { - startRecipeProcessing(); - boolean result = checkRecipe(mInventory[1]); - if (result) { - int length = mInventory[1].getUnlocalizedName() - .length(); - String aMachineName = mInventory[1].getUnlocalizedName() - .substring(17, length - 8); - SoundResource sound = GT_ProcessingArray_Manager.getSoundResource(aMachineName); - if (sound != null) { - sendLoopStart((byte) sound.id); - } - } - endRecipeProcessing(); - return result; - } - - @Override - public boolean checkRecipe(ItemStack aStack) { - if (mLockedToSingleRecipe && mSingleRecipeCheck != null) { - return processLockedRecipe(); - } - - if (!isCorrectMachinePart(mInventory[1])) { - return false; - } - GT_Recipe.GT_Recipe_Map map = getRecipeMap(); - if (map == null) return false; - - if (!mMachineName.equals(mInventory[1].getUnlocalizedName())) { - mLastRecipe = null; - mMachineName = mInventory[1].getUnlocalizedName(); - } - - if (mLastRecipe == null) { + @NotNull + public CheckRecipeResult checkProcessing() { + if (!GT_Utility.areStacksEqual(lastControllerStack, getControllerSlot())) { + // controller slot has changed + lastControllerStack = getControllerSlot(); + mLastRecipeMap = getRecipeMap(); setTierAndMult(); } - ArrayList<FluidStack> tFluidList = getStoredFluids(); - FluidStack[] tFluids = tFluidList.toArray(new FluidStack[0]); - if (inputSeparation) { - ArrayList<ItemStack> tInputList = new ArrayList<>(); - for (GT_MetaTileEntity_Hatch_InputBus tHatch : mInputBusses) { - IGregTechTileEntity tInputBus = tHatch.getBaseMetaTileEntity(); - for (int i = tInputBus.getSizeInventory() - 1; i >= 0; i--) { - if (tInputBus.getStackInSlot(i) != null) tInputList.add(tInputBus.getStackInSlot(i)); - } - ItemStack[] tInputs = tInputList.toArray(new ItemStack[0]); - if (processRecipe(tInputs, tFluids, map)) return true; - else tInputList.clear(); + if (mLastRecipeMap == null) return SimpleCheckRecipeResult.ofFailure("no_machine"); + if (mLockedToSingleRecipe && mSingleRecipeCheck != null) { + if (mSingleRecipeCheck.getRecipeMap() != mLastRecipeMap) { + return SimpleCheckRecipeResult.ofFailure("machine_mismatch"); } - } else { - ArrayList<ItemStack> tInputList = getStoredInputs(); - ItemStack[] tInputs = tInputList.toArray(new ItemStack[0]); - return processRecipe(tInputs, tFluids, map); } - return false; - } - private void setTierAndMult() { - IMetaTileEntity aMachine = GT_Item_Machines.getMetaTileEntity(mInventory[1]); - if (aMachine != null) tTier = ((GT_MetaTileEntity_TieredMachineBlock) aMachine).mTier; - mMult = 0; - if (downtierUEV && tTier > 9) { - tTier--; // Lowers down the tier by 1 to allow for bigger parallel - mMult = 2; // Multiplies Parallels by 4x, keeping the energy cost - } + return super.checkProcessing(); } - public boolean processLockedRecipe() { - GT_Single_Recipe_Check_Processing_Array tSingleRecipeCheck = (GT_Single_Recipe_Check_Processing_Array) mSingleRecipeCheck; - - if (mLastRecipe == null) { - setTierAndMult(); - mLastRecipe = tSingleRecipeCheck.getRecipe(); - } + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { - int machines = mInventory[1].stackSize << mMult; - int parallel = tSingleRecipeCheck.checkRecipeInputs(true, machines); - - return processRecipeOutputs( - tSingleRecipeCheck.getRecipe(), - tSingleRecipeCheck.getRecipeAmperage(), - parallel, - 1); - } - - public boolean processRecipe(ItemStack[] tInputs, FluidStack[] tFluids, GT_Recipe.GT_Recipe_Map map) { - if (tInputs.length == 0 && tFluids.length == 0) return false; - GT_Recipe tRecipe = map.findRecipe( - getBaseMetaTileEntity(), - mLastRecipe, - false, - gregtech.api.enums.GT_Values.V[tTier], - tFluids, - tInputs); - if (tRecipe == null) return false; - if (GT_Mod.gregtechproxy.mLowGravProcessing && tRecipe.mSpecialValue == -100 - && !isValidForLowGravity(tRecipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) return false; - - GT_Single_Recipe_Check_Processing_Array.Builder tSingleRecipeCheckBuilder = null; - if (mLockedToSingleRecipe) { - // We're locked to a single recipe, but haven't built the recipe checker yet. - // Build the checker on next successful recipe. - tSingleRecipeCheckBuilder = GT_Single_Recipe_Check_Processing_Array.processingArrayBuilder(this) - .setBefore(tInputs, tFluids); - } + @Override + protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, + @Nonnull GT_OverclockCalculator calculator) { + return calculator.getDuration(); + } - boolean recipeLocked = false; - mLastRecipe = tRecipe; - int machines = mInventory[1].stackSize << mMult; - int i = 0; - for (; i < machines; i++) { - if (!tRecipe.isRecipeInputEqual(true, tFluids, tInputs)) { - break; - } else if (mLockedToSingleRecipe && !recipeLocked) { - // We want to lock to a single run of the recipe. - mSingleRecipeCheck = tSingleRecipeCheckBuilder.setAfter(tInputs, tFluids) - .setRecipe(tRecipe) - .setRecipeAmperage(map.mAmperage) - .build(); - recipeLocked = true; + @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); } - } - // Check how many times we can run the same recipe - int multiplier = 1; - if (batchMode && i == machines) { - for (; multiplier < 128; ++multiplier) { - if (!tRecipe.isRecipeInputEqual(true, false, machines, tFluids, tInputs)) { - break; + @Nonnull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + if (GT_Mod.gregtechproxy.mLowGravProcessing && recipe.mSpecialValue == -100 + && !isValidForLowGravity(recipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) { + return SimpleCheckRecipeResult.ofFailure("high_gravity"); } + return CheckRecipeResultRegistry.SUCCESSFUL; } - } - return processRecipeOutputs(tRecipe, map.mAmperage, i, multiplier); + }.setMaxParallelSupplier(this::getMaxParallel); } - public boolean processRecipeOutputs(GT_Recipe aRecipe, int aAmperage, int parallel, int multiplier) { - this.mEUPerTick = 0; - this.mOutputItems = null; - this.mOutputFluids = null; - if (parallel == 0) { - return false; - } + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + GT_Recipe_Map recipeMap = getRecipeMap(); + logic.setAvailableVoltage(GT_Values.V[tTier] * (recipeMap != null ? recipeMap.mAmperage : 1)); + logic.setAvailableAmperage(getMaxParallel()); + } - this.mMaxProgresstime = aRecipe.mDuration * multiplier; - - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - ProcessingArrayCalculateOverclock( - aRecipe.mEUt, - aRecipe.mDuration * multiplier, - aAmperage, - GT_Values.V[tTier], - false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUPerTick == Long.MAX_VALUE - 1) return false; - mEUPerTick = mEUPerTick * parallel; - if (mEUPerTick == Long.MAX_VALUE - 1) return false; - - if (mEUPerTick > 0) { - mEUPerTick = (-mEUPerTick); - } - ItemStack[] tOut = new ItemStack[aRecipe.mOutputs.length]; - for (int h = 0; h < aRecipe.mOutputs.length; h++) { - if (aRecipe.getOutput(h) != null) { - tOut[h] = aRecipe.getOutput(h) - .copy(); - tOut[h].stackSize = 0; - } - } - FluidStack[] tFOut = new FluidStack[aRecipe.mFluidOutputs.length]; - for (int i = 0; i < aRecipe.mFluidOutputs.length; i++) - if (aRecipe.getFluidOutput(i) != null) tFOut[i] = aRecipe.getFluidOutput(i) - .copy(); - for (int f = 0; f < tOut.length; f++) { - if (aRecipe.mOutputs[f] != null && tOut[f] != null) { - for (int g = 0; g < parallel * multiplier; g++) { - if (getBaseMetaTileEntity().getRandomNumber(10000) < aRecipe.getOutputChance(f)) - tOut[f].stackSize += aRecipe.mOutputs[f].stackSize; - } - } + private void setTierAndMult() { + IMetaTileEntity aMachine = GT_Item_Machines.getMetaTileEntity(getControllerSlot()); + if (aMachine instanceof GT_MetaTileEntity_TieredMachineBlock) { + tTier = ((GT_MetaTileEntity_TieredMachineBlock) aMachine).mTier; + } else { + tTier = 0; } - byte oNumber = 0; - for (FluidStack fluidStack : tFOut) { - if (fluidStack != null) { - int tSize = fluidStack.amount; - tFOut[oNumber].amount = tSize * parallel * multiplier; - } - oNumber++; + mMult = 0; + if (downtierUEV && tTier > 9) { + tTier--; // Lowers down the tier by 1 to allow for bigger parallel + mMult = 2; // Multiplies Parallels by 4x, keeping the energy cost } - this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); - this.mOutputItems = Arrays.stream(tOut) - .filter(Objects::nonNull) - .flatMap(GT_MetaTileEntity_ProcessingArray::splitOversizedStack) - .filter(is -> is.stackSize > 0) - .toArray(ItemStack[]::new); - this.mOutputFluids = tFOut; - updateSlots(); - return true; } - private static Stream<ItemStack> splitOversizedStack(ItemStack aStack) { - int tMaxStackSize = aStack.getMaxStackSize(); - if (aStack.stackSize <= tMaxStackSize) return Stream.of(aStack); - int tRepeat = aStack.stackSize / tMaxStackSize; - aStack.stackSize = aStack.stackSize % tMaxStackSize; - Stream.Builder<ItemStack> tBuilder = Stream.builder(); - tBuilder.add(aStack); - for (int i = 0; i < tRepeat; i++) { - ItemStack rStack = aStack.copy(); - rStack.stackSize = tMaxStackSize; - tBuilder.add(rStack); + private int getMaxParallel() { + if (getControllerSlot() == null) { + return 0; } - return tBuilder.build(); + return getControllerSlot().stackSize << mMult; } @Override @@ -421,43 +305,43 @@ public class GT_MetaTileEntity_ProcessingArray } @Override - protected IStructureElement<GT_MetaTileEntity_CubicMultiBlockBase<?>> getCasingElement() { - return ofBlock(GregTech_API.sBlockCasings4, 0); + public IStructureDefinition<GT_MetaTileEntity_ProcessingArray> getStructureDefinition() { + return STRUCTURE_DEFINITION; } @Override - protected int getHatchTextureIndex() { - return 48; + public void construct(ItemStack aStack, boolean aHintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, aStack, aHintsOnly, 1, 1, 0); } @Override - protected int getRequiredCasingCount() { - return 14; + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 1, 0, elementBudget, env, false, true); + } + + private boolean checkHatches() { + return mMaintenanceHatches.size() == 1; } @Override public void saveNBTData(NBTTagCompound aNBT) { super.saveNBTData(aNBT); aNBT.setBoolean("downtierUEV", downtierUEV); - aNBT.setLong("mEUPerTick", mEUPerTick); } @Override public void loadNBTData(final NBTTagCompound aNBT) { super.loadNBTData(aNBT); - if (!aNBT.hasKey(INPUT_SEPARATION_NBT_KEY)) { + if (aNBT.hasKey("mSeparate")) { + // backward compatibility inputSeparation = aNBT.getBoolean("mSeparate"); } - if (!aNBT.hasKey(BATCH_MODE_NBT_KEY)) { + if (aNBT.hasKey("mUseMultiparallelMode")) { + // backward compatibility batchMode = aNBT.getBoolean("mUseMultiparallelMode"); } downtierUEV = aNBT.getBoolean("downtierUEV"); - mEUPerTick = aNBT.getLong("mEUPerTick"); - } - - @Override - protected GT_Single_Recipe_Check loadSingleRecipeChecker(NBTTagCompound aNBT) { - return GT_Single_Recipe_Check_Processing_Array.tryLoad(this, getRecipeMap(), aNBT, mInventory[1]); } @Override @@ -483,13 +367,11 @@ public class GT_MetaTileEntity_ProcessingArray } else { GT_Utility.sendChatToPlayer(aPlayer, "Don't batch recipes"); } - return true; } else { downtierUEV = !downtierUEV; - mLastRecipe = null; // clears last recipe GT_Utility.sendChatToPlayer(aPlayer, "Treat UEV+ machines as multiple UHV " + downtierUEV); - return true; } + return true; } @Override @@ -507,20 +389,15 @@ public class GT_MetaTileEntity_ProcessingArray return false; } - @Override - protected List<IHatchElement<? super GT_MetaTileEntity_CubicMultiBlockBase<?>>> getAllowedHatches() { + private List<IHatchElement<? super GT_MetaTileEntity_ProcessingArray>> getAllowedHatches() { return ImmutableList.of(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy, ExoticEnergy); } @Override public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { mExoticEnergyHatches.clear(); - return super.checkMachine(aBaseMetaTileEntity, aStack); - } - - @Override - public boolean drainEnergyInput(long aEU) { - return GT_ExoticEnergyInputHelper.drainEnergy(aEU, getExoticAndNormalEnergyHatchList()); + mCasingAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 1, 0) && mCasingAmount >= 14 && checkHatches(); } @Override @@ -557,7 +434,7 @@ public class GT_MetaTileEntity_ProcessingArray + " EU", StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + EnumChatFormatting.RED - + GT_Utility.formatNumbers(-mEUPerTick) + + GT_Utility.formatNumbers(-lEUt) + EnumChatFormatting.RESET + " EU/t", StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " @@ -599,84 +476,22 @@ public class GT_MetaTileEntity_ProcessingArray + " x", StatCollector.translateToLocal("GT5U.PA.parallel") + ": " + EnumChatFormatting.GREEN - + GT_Utility.formatNumbers((mInventory[1] != null) ? ((long) mInventory[1].stackSize << mMult) : 0) + + GT_Utility.formatNumbers(getMaxParallel()) + EnumChatFormatting.RESET }; } - public List<GT_MetaTileEntity_Hatch> getExoticAndNormalEnergyHatchList() { - List<GT_MetaTileEntity_Hatch> tHatches = new ArrayList<>(); - tHatches.addAll(mExoticEnergyHatches); - tHatches.addAll(mEnergyHatches); - return tHatches; - } - @Override - public boolean onRunningTick(ItemStack aStack) { - if (mEUPerTick < 0) { - if (!drainEnergyInput(-mEUPerTick)) { - mEUPerTick = 0; - criticalStopMachine(); - return false; - } - } + public boolean supportsInputSeparation() { return true; } - protected void ProcessingArrayCalculateOverclock(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, - boolean perfectOC) { - byte mTier = (byte) Math.max(0, GT_Utility.getTier(maxInputVoltage)); - if (mTier == 0) { - // Long time calculation - long xMaxProgresstime = ((long) aDuration) << 1; - if (xMaxProgresstime > Integer.MAX_VALUE - 1) { - // make impossible if too long - mEUPerTick = Long.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUPerTick = aEUt >> 2; - mMaxProgresstime = (int) xMaxProgresstime; - } - } else { - // Long EUt calculation - long xEUt = aEUt; - // Isnt too low EUt check? - long tempEUt = Math.max(xEUt, V[1]); - - mMaxProgresstime = aDuration; - - final int ocTimeShift = perfectOC ? 2 : 1; - - while (tempEUt <= V[mTier - 1] * mAmperage) { - tempEUt <<= 2; // this actually controls overclocking - // xEUt *= 4;//this is effect of everclocking - int oldTime = mMaxProgresstime; - mMaxProgresstime >>= ocTimeShift; // this is effect of overclocking - if (mMaxProgresstime < 1) { - if (oldTime == 1) break; - xEUt *= (long) oldTime * (perfectOC ? 1 : 2); - break; - } else { - xEUt <<= 2; - } - } - if (xEUt > Long.MAX_VALUE - 1) { - mEUPerTick = Long.MAX_VALUE - 1; - mMaxProgresstime = Integer.MAX_VALUE - 1; - } else { - mEUPerTick = xEUt; - if (mEUPerTick == 0) mEUPerTick = 1; - if (mMaxProgresstime == 0) mMaxProgresstime = 1; // set time to 1 tick - } - } - } - @Override - public boolean supportsInputSeparation() { + public boolean supportsBatchMode() { return true; } @Override - public boolean supportsBatchMode() { + public boolean supportsSingleRecipeLocking() { return true; } @@ -684,22 +499,24 @@ public class GT_MetaTileEntity_ProcessingArray public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { super.addUIWidgets(builder, buildContext); - builder.widget( - new ButtonWidget().setOnClick((clickData, widget) -> downtierUEV = !downtierUEV) - .setPlayClickSound(true) - .setBackground(() -> { - if (downtierUEV) { - return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, - GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_ON }; - } else { - return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, - GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_OFF }; - } - }) - .setPos(80, 91) - .setSize(16, 16) - .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.down_tier")) - .setTooltipShowUpDelay(TOOLTIP_DELAY)) + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + downtierUEV = !downtierUEV; + setTierAndMult(); + }) + .setPlayClickSound(true) + .setBackground(() -> { + if (downtierUEV) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_ON }; + } else { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_OFF }; + } + }) + .setPos(80, 91) + .setSize(16, 16) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.down_tier")) + .setTooltipShowUpDelay(TOOLTIP_DELAY)) .widget(new FakeSyncWidget.BooleanSyncer(() -> downtierUEV, val -> downtierUEV = val)); } } 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 2a36377acc..c76ac32863 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 @@ -21,7 +21,8 @@ import static gregtech.api.util.GT_StructureUtility.ofCoil; import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -37,12 +38,12 @@ import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Single_Recipe_Check; -import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_PyrolyseOven extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_PyrolyseOven> implements ISurvivalConstructable { @@ -157,56 +158,20 @@ public class GT_MetaTileEntity_PyrolyseOven } @Override - public boolean checkRecipe(ItemStack aStack) { - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - GT_Recipe tRecipe; - - if (mLockedToSingleRecipe && mSingleRecipeCheck != null) { - if (!mSingleRecipeCheck.checkRecipeInputsSingleStack(true)) { - return false; - } - - tRecipe = mSingleRecipeCheck.getRecipe(); - } else { - ItemStack[] tInputs = getCompactedInputs(); - FluidStack[] tFluids = getCompactedFluids(); - - if (tInputs.length == 0) return false; - - GT_Single_Recipe_Check.Builder tSingleRecipeCheckBuilder = null; - if (mLockedToSingleRecipe) { - // We're locked to a single recipe, but haven't built the recipe checker yet. - // Build the checker on next successful recipe. - tSingleRecipeCheckBuilder = GT_Single_Recipe_Check.builder(this) - .setBefore(tInputs, tFluids); - } - - tRecipe = GT_Recipe.GT_Recipe_Map.sPyrolyseRecipes - .findRecipe(getBaseMetaTileEntity(), false, gregtech.api.enums.GT_Values.V[tTier], tFluids, tInputs); - - if (tRecipe == null || !canOutputAll(tRecipe) || !tRecipe.isRecipeInputEqual(true, tFluids, tInputs)) - return false; - - if (mLockedToSingleRecipe) { - mSingleRecipeCheck = tSingleRecipeCheckBuilder.setAfter(tInputs, tFluids) - .setRecipe(tRecipe) - .build(); + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @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; } - } - - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage, false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - if (this.mEUt > 0) this.mEUt = (-this.mEUt); - this.mMaxProgresstime = Math.max(mMaxProgresstime * 2 / (1 + coilHeat.getTier()), 1); - if (tRecipe.mOutputs.length > 0) this.mOutputItems = new ItemStack[] { tRecipe.getOutput(0) }; - if (tRecipe.mFluidOutputs.length > 0) this.mOutputFluids = new FluidStack[] { tRecipe.getFluidOutput(0) }; - updateSlots(); - return true; + }; } @Override 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 429a8a4ddf..54f903299e 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 @@ -18,10 +18,13 @@ import static java.lang.Math.max; import static net.minecraft.util.EnumChatFormatting.GOLD; import static net.minecraft.util.EnumChatFormatting.GRAY; +import javax.annotation.Nonnull; + import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; @@ -33,9 +36,14 @@ import gregtech.api.interfaces.IGlobalWirelessEnergy; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +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; @@ -136,56 +144,53 @@ public class GT_MetaTileEntity_TranscendentPlasmaMixer long mWirelessEUt = 0; @Override - public boolean checkRecipe(ItemStack aStack) { - if (aStack != null && aStack.getItem() instanceof GT_IntegratedCircuit_Item) { - multiplier = aStack.stackSize * max(1, aStack.getItemDamage()); - } - - return processRecipe(getCompactedInputs(), getCompactedFluids()); + public GT_Recipe.GT_Recipe_Map getRecipeMap() { + return GT_Recipe.GT_Recipe_Map.sTranscendentPlasmaMixerRecipes; } - boolean processRecipe(ItemStack[] items, FluidStack[] fluids) { - - GT_Recipe originalRecipe = GT_Recipe.GT_Recipe_Map.sTranscendentPlasmaMixerRecipes - .findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, fluids, items); - - if (originalRecipe == null) { - return false; - } - mWirelessEUt = 10L * (long) originalRecipe.mEUt * (long) multiplier; - // 100L - recipe takes 100 ticks - if (!addEUToGlobalEnergyMap(ownerUUID, mWirelessEUt * -100L)) { - return false; - } - - // Fluid handling. - { - // Output items/fluids. - GT_Recipe modifiedRecipe = originalRecipe.copy(); - - // Multiply up the input plasmas. - for (FluidStack fluidStack : modifiedRecipe.mFluidInputs) { - fluidStack.amount *= multiplier; + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + mWirelessEUt = 10L * (long) recipe.mEUt * (long) multiplier; + if (!addEUToGlobalEnergyMap(ownerUUID, -mWirelessEUt * recipe.mDuration)) { + return CheckRecipeResultRegistry.insufficientPower(mWirelessEUt * recipe.mDuration); + } + return CheckRecipeResultRegistry.SUCCESSFUL; } - // Multiply up the output fluid. - modifiedRecipe.mFluidOutputs[0].amount *= multiplier; - - if (!canOutputAll(modifiedRecipe)) return false; - - // Takes items/fluids from hatches/busses. - if (!modifiedRecipe.isRecipeInputEqual(true, fluids, items)) return false; - - mOutputFluids = modifiedRecipe.mFluidOutputs; - mOutputItems = modifiedRecipe.mOutputs; - } - - mMaxProgresstime = 100; - mEUt = 0; + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe, + @Nonnull GT_ParallelHelper helper) { + return GT_OverclockCalculator.ofNoOverclock(recipe); + } - updateSlots(); + @NotNull + @Override + public CheckRecipeResult process() { + CheckRecipeResult result = super.process(); + // Power will be directly consumed through wireless + setCalculatedEut(0); + return result; + } + }.setMaxParallelSupplier(() -> { + ItemStack controllerStack = getControllerSlot(); + if (controllerStack != null && controllerStack.getItem() instanceof GT_IntegratedCircuit_Item) { + multiplier = controllerStack.stackSize * max(1, controllerStack.getItemDamage()); + } + return multiplier; + }); + } - return true; + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + // The voltage is only used for recipe finding + logic.setAvailableVoltage(Long.MAX_VALUE); + logic.setAvailableAmperage(1); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java index 815515b555..e353d5d980 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java @@ -8,7 +8,6 @@ import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.FluidStack; import com.gtnewhorizon.structurelib.structure.IStructureElement; import com.gtnewhorizon.structurelib.structure.StructureUtility; @@ -17,11 +16,11 @@ import gregtech.api.GregTech_API; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_CubicMultiBlockBase; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Utility; public class GT_MetaTileEntity_VacuumFreezer extends GT_MetaTileEntity_CubicMultiBlockBase<GT_MetaTileEntity_VacuumFreezer> { @@ -102,34 +101,8 @@ public class GT_MetaTileEntity_VacuumFreezer } @Override - public boolean checkRecipe(ItemStack aStack) { - ItemStack[] tInputList = getCompactedInputs(); - FluidStack[] tFluidList = getCompactedFluids(); - - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - GT_Recipe tRecipe = getRecipeMap() - .findRecipe(getBaseMetaTileEntity(), false, gregtech.api.enums.GT_Values.V[tTier], tFluidList, tInputList); - if (tRecipe != null) { - if (!canOutputAll(tRecipe)) return false; - if (tRecipe.isRecipeInputEqual(true, tFluidList, tInputList)) { - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - - calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, 1, tVoltage, false); - // In case recipe is too OP for that machine - if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return false; - if (this.mEUt > 0) { - this.mEUt = (-this.mEUt); - } - this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); - this.mOutputItems = new ItemStack[] { tRecipe.getOutput(0) }; - this.mOutputFluids = new FluidStack[] { tRecipe.getFluidOutput(0) }; - updateSlots(); - return true; - } - } - return false; + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalReactor.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalReactor.java index e9db6c2256..38152869e4 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalReactor.java +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalReactor.java @@ -78,9 +78,12 @@ public class AdvChemicalReactor extends ComplexParallelController<AdvChemicalRea } processFluidWhiteLists.add(processFluidTanks); } - processingLogic = new ComplexParallelProcessingLogic( - GT_Recipe.GT_Recipe_Map_LargeChemicalReactor.sChemicalRecipes, - MAX_PROCESSES); + processingLogic = new ComplexParallelProcessingLogic(getRecipeMap(), MAX_PROCESSES); + } + + @Override + public GT_Recipe.GT_Recipe_Map getRecipeMap() { + return GT_Recipe.GT_Recipe_Map_LargeChemicalReactor.sChemicalRecipes; } @Override diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java index 4a84c1503f..046bb4a114 100644 --- a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java @@ -4,10 +4,14 @@ import static gregtech.api.enums.Mods.Railcraft; import static net.minecraftforge.oredict.OreDictionary.getOreID; import static net.minecraftforge.oredict.OreDictionary.getOreIDs; +import javax.annotation.Nonnull; + import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import gregtech.api.logic.ProcessingLogic; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_OreDictUnificator; @@ -24,21 +28,22 @@ public class CokeOvenProcessingLogic extends ProcessingLogic { private int timeMultiplier = 1; @Override - public boolean process() { + public @Nonnull CheckRecipeResult process() { if (inputItems == null || inputItems[0] == null) { - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } ItemStack input = inputItems[0]; int originalStackSize = input.stackSize; ItemStack output = findRecipe(input); if (currentOutputItems != null && currentOutputItems[0] != null && !currentOutputItems[0].isItemEqual(output)) { - return false; + return CheckRecipeResultRegistry.NO_RECIPE; } input.stackSize -= 1; - setDuration((long) NORMAL_RECIPE_TIME * timeMultiplier); + setDuration(NORMAL_RECIPE_TIME * timeMultiplier); setOutputItems(output); - return originalStackSize > input.stackSize; + return originalStackSize > input.stackSize ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; } protected ItemStack findRecipe(ItemStack input) { diff --git a/src/main/java/gregtech/common/tileentities/storage/GT_MetaTileEntity_DigitalTankBase.java b/src/main/java/gregtech/common/tileentities/storage/GT_MetaTileEntity_DigitalTankBase.java index 123e193f03..dd76ddf45e 100644 --- a/src/main/java/gregtech/common/tileentities/storage/GT_MetaTileEntity_DigitalTankBase.java +++ b/src/main/java/gregtech/common/tileentities/storage/GT_MetaTileEntity_DigitalTankBase.java @@ -476,6 +476,7 @@ public abstract class GT_MetaTileEntity_DigitalTankBase extends GT_MetaTileEntit return allowOverflow() ? Integer.MAX_VALUE : getRealCapacity(); } + @Override public int getRealCapacity() { return commonSizeCompute(mTier); } diff --git a/src/main/java/gregtech/nei/HeatingCoilSpecialValueFormatter.java b/src/main/java/gregtech/nei/HeatingCoilSpecialValueFormatter.java index f6f0a4099f..936aa6b715 100644 --- a/src/main/java/gregtech/nei/HeatingCoilSpecialValueFormatter.java +++ b/src/main/java/gregtech/nei/HeatingCoilSpecialValueFormatter.java @@ -16,15 +16,7 @@ public class HeatingCoilSpecialValueFormatter implements INEISpecialInfoFormatte List<String> result = new ArrayList<>(); result.add(applyPrefixAndSuffix.apply(heat)); - - for (HeatingCoilLevel heatLevel : HeatingCoilLevel.values()) { - if (heatLevel == HeatingCoilLevel.None || heatLevel == HeatingCoilLevel.ULV) continue; - if (heatLevel.getHeat() >= heat) { - result.add(" (" + heatLevel.getName() + ")"); - return result; - } - } - result.add(" (" + HeatingCoilLevel.MAX.getName() + "+)"); + result.add(" (" + HeatingCoilLevel.getDisplayNameFromHeat(heat, false) + ")"); return result; } } |