diff options
Diffstat (limited to 'src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java')
-rw-r--r-- | src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java | 1107 |
1 files changed, 0 insertions, 1107 deletions
diff --git a/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java b/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java deleted file mode 100644 index 8dd6652994..0000000000 --- a/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java +++ /dev/null @@ -1,1107 +0,0 @@ -package net.glease.ggfab.mte; - -import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockUnlocalizedName; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; -import static gregtech.GT_Mod.GT_FML_LOGGER; -import static gregtech.api.enums.GT_HatchElement.Energy; -import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; -import static gregtech.api.enums.GT_HatchElement.InputBus; -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.V; -import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; -import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; -import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; -import static gregtech.api.util.GT_Utility.filterValidMTEs; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_GLOW; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK; -import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.IntStream; - -import net.glease.ggfab.ConfigurationHandler; -import net.glease.ggfab.GGConstants; -import net.glease.ggfab.mui.ClickableTextWidget; -import net.glease.ggfab.util.OverclockHelper; -import net.minecraft.client.resources.I18n; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.PacketBuffer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.StringUtils; -import net.minecraft.world.World; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.Fluid; -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; -import com.gtnewhorizon.structurelib.structure.StructureDefinition; -import com.gtnewhorizons.modularui.api.drawable.Text; -import com.gtnewhorizons.modularui.api.math.Alignment; -import com.gtnewhorizons.modularui.api.widget.ISyncedWidget; -import com.gtnewhorizons.modularui.api.widget.Widget; -import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; -import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; -import com.gtnewhorizons.modularui.common.widget.SlotWidget; -import com.gtnewhorizons.modularui.common.widget.TextWidget; - -import gregtech.api.GregTech_API; -import gregtech.api.enums.GT_Values; -import gregtech.api.enums.ItemList; -import gregtech.api.enums.VoidingMode; -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_ExtendedPowerMultiBlockBase; -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_Input; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; -import gregtech.api.recipe.RecipeMap; -import gregtech.api.recipe.RecipeMaps; -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; -import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_Recipe; -import gregtech.api.util.GT_Utility; -import gregtech.api.util.GT_Waila; -import gregtech.api.util.IGT_HatchAdder; -import gregtech.api.util.shutdown.ShutDownReason; -import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; -import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Input_ME; -import mcp.mobius.waila.api.IWailaConfigHandler; -import mcp.mobius.waila.api.IWailaDataAccessor; - -/* - * Dev note: 1. This multi will be an assline but with greater throughput. it will take one input every 2. - */ -public class MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<MTE_AdvAssLine> - implements ISurvivalConstructable { - - private static final ItemStack NOT_CHECKED = new ItemStack(Blocks.dirt); - private static final String STRUCTURE_PIECE_FIRST = "first"; - private static final String STRUCTURE_PIECE_LATER = "later"; - private static final String STRUCTURE_PIECE_LAST = "last"; - public static final String TAG_KEY_CURRENT_STICK = "mCurrentStick"; - public static final String TAG_KEY_PROGRESS_TIMES = "mProgressTimeArray"; - private static final IStructureDefinition<MTE_AdvAssLine> STRUCTURE_DEFINITION = StructureDefinition - .<MTE_AdvAssLine>builder() - // @formatter:off - .addShape( - STRUCTURE_PIECE_FIRST, - transpose(new String[][] { - { " ", "e", " " }, - { "~", "l", "G" }, - { "g", "m", "g" }, - { "b", "i", "b" }, - })) - .addShape( - STRUCTURE_PIECE_LATER, - transpose(new String[][] { - { " ", "e", " " }, - { "d", "l", "d" }, - { "g", "m", "g" }, - { "b", "I", "b" }, - })) - .addShape( - STRUCTURE_PIECE_LAST, - transpose(new String[][] { - { " ", "e", " " }, - { "d", "l", "d" }, - { "g", "m", "g" }, - { "o", "i", "b" }, - })) - // @formatter:on - .addElement('G', ofBlock(GregTech_API.sBlockCasings3, 10)) // grate machine casing - .addElement('l', ofBlock(GregTech_API.sBlockCasings2, 9)) // assembler machine casing - .addElement('m', ofBlock(GregTech_API.sBlockCasings2, 5)) // assembling line casing - .addElement( - 'g', - ofChain( - ofBlockUnlocalizedName("IC2", "blockAlloyGlass", 0, true), - ofBlockUnlocalizedName("bartworks", "BW_GlasBlocks", 0, true), - // warded glass - ofBlockUnlocalizedName("Thaumcraft", "blockCosmeticOpaque", 2, false))) - .addElement( - 'e', - ofChain( - Energy.or(ExoticEnergy) - .newAny(16, 1, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH), - ofBlock(GregTech_API.sBlockCasings2, 0))) - .addElement( - 'd', - buildHatchAdder(MTE_AdvAssLine.class).atLeast(DataHatchElement.DataAccess) - .dot(2) - .casingIndex(42) - .allowOnly(ForgeDirection.NORTH) - .buildAndChain(GregTech_API.sBlockCasings3, 10)) - .addElement( - 'b', - buildHatchAdder(MTE_AdvAssLine.class).atLeast(InputHatch, InputHatch, InputHatch, InputHatch, Maintenance) - .casingIndex(16) - .dot(3) - .allowOnly(ForgeDirection.DOWN) - .buildAndChain( - ofBlock(GregTech_API.sBlockCasings2, 0), - ofHatchAdder(MTE_AdvAssLine::addOutputToMachineList, 16, 4))) - .addElement( - 'I', - ofChain( - // all blocks nearby use solid steel casing, so let's use the texture of that - InputBus.newAny(16, 5, ForgeDirection.DOWN), - ofHatchAdder(MTE_AdvAssLine::addOutputToMachineList, 16, 4))) - .addElement('i', InputBus.newAny(16, 5, ForgeDirection.DOWN)) - .addElement('o', OutputBus.newAny(16, 4, ForgeDirection.DOWN)) - .build(); - private ItemStack currentStick; - private GT_Recipe.GT_Recipe_AssemblyLine currentRecipe; - private final Slice[] slices = IntStream.range(0, 16) - .mapToObj(Slice::new) - .toArray(Slice[]::new); - private boolean processing; - private long inputVoltage; - // surely no one is using more EUt than this, no? - private long inputEUt; - private long baseEUt; - private boolean stuck; - - private final List<GT_MetaTileEntity_Hatch_DataAccess> mDataAccessHatches = new ArrayList<>(); - private Map<GT_Utility.ItemId, ItemStack> curBatchItemsFromME; - private Map<Fluid, FluidStack> curBatchFluidsFromME; - private int currentInputLength; - private String lastStopReason = ""; - private int currentRecipeParallel = 1; - // Batch mode will increase parallel per slice to try to get as close as possible to this amount of ticks - // per slice, but will never go over this amount. - private static final int BATCH_MODE_DESIRED_TICKS_PER_SLICE = 128; - - public MTE_AdvAssLine(int aID, String aName, String aNameRegional) { - super(aID, aName, aNameRegional); - } - - public MTE_AdvAssLine(String aName) { - super(aName); - } - - @Override - public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { - return new MTE_AdvAssLine(mName); - } - - public boolean addDataAccessToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { - if (aTileEntity == null) return false; - IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); - if (aMetaTileEntity == null) return false; - if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_DataAccess) { - ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); - return mDataAccessHatches.add((GT_MetaTileEntity_Hatch_DataAccess) aMetaTileEntity); - } - return false; - } - - private boolean checkMachine() { - return checkMachine(true) || checkMachine(false); - } - - private boolean checkMachine(boolean leftToRight) { - clearHatches(); - if (!checkPiece(STRUCTURE_PIECE_FIRST, 0, 1, 0)) return false; - for (int i = 1; i < 16; i++) { - if (!checkPiece(STRUCTURE_PIECE_LATER, leftToRight ? -i : i, 1, 0)) return false; - if (!mOutputBusses.isEmpty()) - return (!mEnergyHatches.isEmpty() || !mExoticEnergyHatches.isEmpty()) && mMaintenanceHatches.size() == 1 - && mDataAccessHatches.size() <= 1; - } - return false; - } - - @Override - public void construct(ItemStack stackSize, boolean hintsOnly) { - buildPiece(STRUCTURE_PIECE_FIRST, stackSize, hintsOnly, 0, 1, 0); - int tLength = Math.min(stackSize.stackSize + 3, 16); // render 4 slices at minimal - for (int i = 1; i < tLength; i++) { - buildPiece(STRUCTURE_PIECE_LATER, stackSize, hintsOnly, -i, 1, 0); - } - } - - @Override - public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { - if (mMachine) return -1; - int build = survivialBuildPiece(STRUCTURE_PIECE_FIRST, stackSize, 0, 1, 0, elementBudget, env, false, true); - if (build >= 0) return build; - int tLength = Math.min(stackSize.stackSize + 3, 16); // render 4 slices at minimal - for (int i = 1; i < tLength - 1; i++) { - build = survivialBuildPiece(STRUCTURE_PIECE_LATER, stackSize, -i, 1, 0, elementBudget, env, false, true); - if (build >= 0) return build; - } - return survivialBuildPiece(STRUCTURE_PIECE_LAST, stackSize, 1 - tLength, 1, 0, elementBudget, env, false, true); - } - - @Override - public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing, - int colorIndex, boolean aActive, boolean aRedstone) { - if (side == facing) { - if (stuck) { - return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE_STUCK) - .extFacing() - .build(), - TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW) - .extFacing() - .glow() - .build() }; - } - if (aActive) return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE_ACTIVE) - .extFacing() - .build(), - TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW) - .extFacing() - .glow() - .build() }; - return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE) - .extFacing() - .build(), - TextureFactory.builder() - .addIcon(OVERLAY_FRONT_ADV_ASSLINE_GLOW) - .extFacing() - .glow() - .build() }; - } - return new ITexture[] { casingTexturePages[0][16] }; - } - - @Override - protected GT_Multiblock_Tooltip_Builder createTooltip() { - final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); - tt.addMachineType("Assembling Line") - .addInfo("Controller block for the Advanced Assembling Line") - .addInfo("Built exactly the same as standard Assembling Line") - .addInfo("Place in world to get more info. It will be a lengthy read.") - .addInfo("Assembling Line with item pipelining") - .addInfo("All fluids are however consumed at start") - .addInfo("Use voltage of worst energy hatch for overclocking") - .addInfo("EU/t is (number of slices working) * (overclocked EU/t)") - .addSeparator() - .beginVariableStructureBlock(5, 16, 4, 4, 3, 3, false) - .addStructureInfo("From Bottom to Top, Left to Right") - .addStructureInfo( - "Layer 1 - Solid Steel Machine Casing, Input Bus (last can be Output Bus), Solid Steel Machine Casing") - .addStructureInfo( - "Layer 2 - Borosilicate Glass(any)/Warded Glass/Reinforced Glass, Assembling Line Casing, Reinforced Glass") - .addStructureInfo("Layer 3 - Grate Machine Casing, Assembler Machine Casing, Grate Machine Casing") - .addStructureInfo("Layer 4 - Empty, Solid Steel Machine Casing, Empty") - .addStructureInfo("Up to 16 repeating slices, each one allows for 1 more item in recipes") - .addController("Either Grate on layer 3 of the first slice") - .addEnergyHatch("Any layer 4 casing", 1) - .addMaintenanceHatch("Any layer 1 casing", 3) - .addInputBus("As specified on layer 1", 4, 5) - .addInputHatch("Any layer 1 casing", 3) - .addOutputBus("Replaces Input Bus on final slice or on any solid steel casing on layer 1", 4) - .addOtherStructurePart("Data Access Hatch", "Optional, next to controller", 2) - .toolTipFinisher(GGConstants.GGMARK); - return tt; - } - - private void setCurrentRecipe(ItemStack stick, GT_Recipe.GT_Recipe_AssemblyLine recipe) { - currentRecipe = recipe; - currentStick = stick; - currentInputLength = recipe.mInputs.length; - } - - private void clearCurrentRecipe() { - currentRecipe = null; - currentStick = null; - currentInputLength = -1; - currentRecipeParallel = 1; - stuck = false; - baseEUt = 0; - for (Slice slice : slices) { - slice.reset(); - } - mMaxProgresstime = 0; - getBaseMetaTileEntity().issueClientUpdate(); - } - - @Override - public void saveNBTData(NBTTagCompound aNBT) { - super.saveNBTData(aNBT); - aNBT.setString("lastStop", lastStopReason); - // we need to check for active here. - // if machine was turned off via soft mallet it will not call checkRecipe() on recipe end - // in that case we don't have a current recipe, so this should be ignored - if (getBaseMetaTileEntity().isActive() && GT_Utility.isStackValid(currentStick)) { - aNBT.setTag(TAG_KEY_CURRENT_STICK, currentStick.writeToNBT(new NBTTagCompound())); - aNBT.setInteger("mRecipeHash", currentRecipe.getPersistentHash()); - aNBT.setIntArray( - TAG_KEY_PROGRESS_TIMES, - Arrays.stream(slices) - .limit(currentInputLength) - .mapToInt(s -> s.progress) - .toArray()); - aNBT.setBoolean("stuck", stuck); - aNBT.setLong("inputV", inputVoltage); - aNBT.setLong("inputEU", inputEUt); - aNBT.setLong("baseEU", baseEUt); - aNBT.setInteger("currentParallel", currentRecipeParallel); - } - } - - @Override - public void loadNBTData(NBTTagCompound aNBT) { - super.loadNBTData(aNBT); - lastStopReason = aNBT.getString("lastStop"); - ItemStack loadedStack = null; - GT_Recipe.GT_Recipe_AssemblyLine recipe = null; - if (aNBT.hasKey(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_INT_ARRAY)) { - int[] arr = aNBT.getIntArray(TAG_KEY_PROGRESS_TIMES); - for (int i = 0; i < slices.length; i++) { - if (i < arr.length) { - slices[i].progress = arr[i]; - if (arr[i] == 0) - // this will be synced to client by first MTE packet to client - stuck = true; - } else slices[i].reset(); - } - } - if (aNBT.hasKey(TAG_KEY_CURRENT_STICK, Constants.NBT.TAG_COMPOUND)) { - loadedStack = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag(TAG_KEY_CURRENT_STICK)); - GT_AssemblyLineUtils.LookupResult lookupResult = GT_AssemblyLineUtils - .findAssemblyLineRecipeFromDataStick(loadedStack, false); - switch (lookupResult.getType()) { - case VALID_STACK_AND_VALID_HASH: - recipe = lookupResult.getRecipe(); - stuck = aNBT.getBoolean("stuck"); - inputVoltage = aNBT.getLong("inputV"); - inputEUt = aNBT.getLong("inputEU"); - baseEUt = aNBT.getLong("baseEU"); - currentRecipeParallel = aNBT.getInteger("currentParallel"); - if (inputVoltage <= 0 || inputEUt <= 0 || baseEUt >= 0) { - criticalStopMachine("ggfab.gui.advassline.shutdown.load.energy"); - loadedStack = null; - recipe = null; - } - break; - case VALID_STACK_AND_VALID_RECIPE: - // recipe is there, but it has been changed. to prevent issues, abort the current recipe - // TODO finish the last recipe instead of aborting - default: - // recipe is gone. to prevent issues, abort the current recipe - criticalStopMachine("ggfab.gui.advassline.shutdown.load.recipe"); - loadedStack = null; - break; - } - } - if (loadedStack == null || recipe == null) clearCurrentRecipe(); - else setCurrentRecipe(loadedStack, recipe); - } - - /** - * roughly the same as {@link #criticalStopMachine()}, but does not attempt to send a halting sound if world is not - * loaded. also supports setting a stop reason - */ - private void criticalStopMachine(String reason) { - int oMaxProgresstime = mMaxProgresstime; - stopMachine(); - // don't do these at all if the machine wasn't working before anyway - if (oMaxProgresstime > 0) { - if (getBaseMetaTileEntity().getWorld() != null) sendSound(INTERRUPT_SOUND_INDEX); - getBaseMetaTileEntity().setShutdownStatus(true); - lastStopReason = reason; - } - } - - @Override - public IStructureDefinition<MTE_AdvAssLine> getStructureDefinition() { - return STRUCTURE_DEFINITION; - } - - @Override - public void clearHatches() { - super.clearHatches(); - mExoticEnergyHatches.clear(); - mDataAccessHatches.clear(); - } - - @Override - public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { - if (checkMachine() && (mEnergyHatches.size() > 0 || mExoticEnergyHatches.size() > 0)) { - long oV = inputVoltage, oEut = inputEUt; - inputVoltage = Integer.MAX_VALUE; - inputEUt = 0; - mEnergyHatches.forEach(this::recordEnergySupplier); - mExoticEnergyHatches.forEach(this::recordEnergySupplier); - if (mMaxProgresstime > 0 && (oV != inputVoltage || oEut != inputEUt)) { - criticalStopMachine("ggfab.gui.advassline.shutdown.structure"); - } - return true; - } else { - inputVoltage = V[0]; - return false; - } - } - - private void recordEnergySupplier(GT_MetaTileEntity_Hatch hatch) { - if (!hatch.isValid()) return; - inputEUt += hatch.maxEUInput() * hatch.maxWorkingAmperesIn(); - inputVoltage = Math.min(inputVoltage, hatch.maxEUInput()); - if (inputEUt < 0) inputEUt = Long.MAX_VALUE; - } - - @Override - protected void startRecipeProcessing() { - if (!processing) { - super.startRecipeProcessing(); - curBatchItemsFromME = getStoredInputsFromME(); - curBatchFluidsFromME = getStoredFluidsFromME(); - processing = true; - } - } - - @Override - protected void endRecipeProcessing() { - if (!processing) return; - super.endRecipeProcessing(); - processing = false; - } - - @Override - public void onValueUpdate(byte aValue) { - boolean oStuck = stuck; - stuck = (aValue & 1) == 1; - if (oStuck != stuck) getBaseMetaTileEntity().issueTextureUpdate(); - } - - @Override - public byte getUpdateData() { - return (byte) (stuck ? 1 : 0); - } - - @Override - protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { - super.drawTexts(screenElements, inventorySlot); - /* - * SliceStatusWidget[] arr = - * Arrays.stream(slices).map(SliceStatusWidget::new).toArray(SliceStatusWidget[]::new); - * screenElements.widgets(arr); screenElements.widget(new FakeSyncWidget.IntegerSyncer(() -> currentInputLength, - * l -> { currentInputLength = l; for (SliceStatusWidget w : arr) { w.updateText(); } })); - */ - screenElements.widget( - new TextWidget(Text.localised("ggfab.gui.advassline.shutdown")).setEnabled(this::hasAbnormalStopReason)); - screenElements.widget( - new TextWidget().setTextSupplier(() -> Text.localised(lastStopReason)) - .attachSyncer( - new FakeSyncWidget.StringSyncer(() -> lastStopReason, r -> this.lastStopReason = r), - screenElements) - .setEnabled(this::hasAbnormalStopReason)); - screenElements.widget( - new ClickableTextWidget( - Text.localised("ggfab.gui.advassline.shutdown_clear") - .alignment(Alignment.CenterLeft)).setMarginInLines(0) - .setOnClick((d, w) -> lastStopReason = "") - .setSize(36, 20) - .setEnabled(this::hasAbnormalStopReason)); - } - - private Boolean hasAbnormalStopReason(Widget w) { - return !StringUtils.isNullOrEmpty(lastStopReason); - } - - @Override - public RecipeMap<?> getRecipeMap() { - return RecipeMaps.assemblylineVisualRecipes; - } - - @Override - public boolean onRunningTick(ItemStack aStack) { - if (currentRecipe == null) { - criticalStopMachine("ggfab.gui.advassline.shutdown.recipe_null"); - return false; - } - for (GT_MetaTileEntity_Hatch_DataAccess hatch_dataAccess : mDataAccessHatches) { - hatch_dataAccess.setActive(true); - } - - if (mInputBusses.size() < currentInputLength) { - criticalStopMachine("ggfab.gui.advassline.shutdown.input_busses"); - return false; - } - boolean oStuck = stuck; - stuck = false; - - for (int i = slices.length - 1; i >= 0; i--) { - slices[i].tick(); - } - - if (oStuck != stuck) - // send the status as it has changed - getBaseMetaTileEntity().issueClientUpdate(); - - if (getBaseMetaTileEntity().isAllowedToWork() && slices[0].progress < 0) { - startRecipeProcessing(); - if (hasAllItems(currentRecipe, this.currentRecipeParallel) - && hasAllFluids(currentRecipe, this.currentRecipeParallel) - && slices[0].start()) { - drainAllFluids(currentRecipe, this.currentRecipeParallel); - mProgresstime = 0; - } - } - - boolean foundWorking = false; - int working = 0; - for (Slice slice : slices) { - if (slice.progress >= 0) { - if (!foundWorking) { - foundWorking = true; - mProgresstime = (slice.id + 1) * (mMaxProgresstime / currentInputLength) - slice.progress; - } - } - if (slice.progress > 0) working++; - } - lEUt = working * baseEUt; - - if (lEUt > 0) { - // overflow again :( - lEUt = Long.MIN_VALUE; - for (int i = 0; i < working; i++) { - if (!drainEnergyInput(-baseEUt)) { - criticalStopMachine("ggfab.gui.advassline.shutdown.energy"); - return false; - } - } - } else { - if (!super.onRunningTick(aStack)) return false; - } - - endRecipeProcessing(); - return true; - } - - private ItemStack getInputBusContent(int index) { - if (index < 0 || index >= mInputBusses.size()) return null; - GT_MetaTileEntity_Hatch_InputBus inputBus = mInputBusses.get(index); - if (!inputBus.isValid()) return null; - if (inputBus instanceof GT_MetaTileEntity_Hatch_InputBus_ME meBus) { - ItemStack item = meBus.getShadowItemStack(0); - if (item == null) return null; - GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(item); - if (!curBatchItemsFromME.containsKey(id)) return null; - return curBatchItemsFromME.get(id); - } - return inputBus.getStackInSlot(0); - - } - - private FluidStack getInputHatchContent(int index) { - if (index < 0 || index >= mInputHatches.size()) return null; - GT_MetaTileEntity_Hatch_Input inputHatch = mInputHatches.get(index); - if (!inputHatch.isValid()) return null; - if (inputHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { - FluidStack fluid = meHatch.getShadowFluidStack(0); - if (fluid == null) return null; - if (!curBatchFluidsFromME.containsKey(fluid.getFluid())) return null; - return curBatchFluidsFromME.get(fluid.getFluid()); - } - if (inputHatch instanceof GT_MetaTileEntity_Hatch_MultiInput multiHatch) { - return multiHatch.getFluid(0); - } - return inputHatch.getFillableStack(); - } - - private GT_Recipe.GT_Recipe_AssemblyLine findRecipe(ItemStack tDataStick) { - GT_AssemblyLineUtils.LookupResult tLookupResult = GT_AssemblyLineUtils - .findAssemblyLineRecipeFromDataStick(tDataStick, false); - - if (tLookupResult.getType() == GT_AssemblyLineUtils.LookupResultType.INVALID_STICK) return null; - - GT_Recipe.GT_Recipe_AssemblyLine tRecipe = tLookupResult.getRecipe(); - // Check if the recipe on the data stick is the current recipe for it's given output, if not we update it - // and continue to next. - if (tLookupResult.getType() != GT_AssemblyLineUtils.LookupResultType.VALID_STACK_AND_VALID_HASH) { - tRecipe = GT_AssemblyLineUtils.processDataStick(tDataStick); - if (tRecipe == null) { - return null; - } - } - - // So here we check against the recipe found on the data stick. - // If we run into missing buses/hatches or bad inputs, we go to the next data stick. - // This check only happens if we have a valid up-to-date data stick. - - // Check item Inputs align. For this we do not need to consider batch mode parallels yet, this will be done - // later on during recipe start. - if (!hasAllItems(tRecipe, 1)) return null; - - // Check Fluid Inputs align. Again, do not consider parallels - if (!hasAllFluids(tRecipe, 1)) return null; - - if (GT_Values.D1) { - GT_FML_LOGGER.info("Check overclock"); - } - if (GT_Values.D1) { - GT_FML_LOGGER.info("Find available recipe"); - } - return tRecipe; - } - - private boolean hasAllItems(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) { - int aItemCount = tRecipe.mInputs.length; - if (mInputBusses.size() < aItemCount) return false; - int[] itemConsumptions = GT_Recipe.GT_Recipe_AssemblyLine.getItemConsumptionAmountArray(mInputBusses, tRecipe); - if (itemConsumptions == null || itemConsumptions.length == 0) { - return false; - } - int maxParallel = (int) GT_Recipe.GT_Recipe_AssemblyLine - .maxParallelCalculatedByInputItems(mInputBusses, parallel, itemConsumptions, curBatchItemsFromME); - return maxParallel >= parallel; - } - - private boolean hasAllFluids(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) { - int aFluidCount = tRecipe.mFluidInputs.length; - if (mInputHatches.size() < aFluidCount) return false; - int maxParallel = (int) GT_Recipe.GT_Recipe_AssemblyLine - .maxParallelCalculatedByInputFluids(mInputHatches, parallel, tRecipe.mFluidInputs, curBatchFluidsFromME); - return maxParallel >= parallel; - } - - /** - * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb - */ - private boolean isCorrectDataItem(ItemStack aStack, int state) { - if ((state & 1) != 0 && ItemList.Circuit_Integrated.isStackEqual(aStack, true, true)) return true; - if ((state & 2) != 0 && ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) return true; - return (state & 4) != 0 && ItemList.Tool_DataOrb.isStackEqual(aStack, false, true); - } - - /** - * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb - */ - public ArrayList<ItemStack> getDataItems(int state) { - ArrayList<ItemStack> rList = new ArrayList<>(); - if (GT_Utility.isStackValid(mInventory[1]) && isCorrectDataItem(mInventory[1], state)) { - rList.add(mInventory[1]); - } - for (GT_MetaTileEntity_Hatch_DataAccess tHatch : mDataAccessHatches) { - if (tHatch.isValid()) { - for (int i = 0; i < tHatch.getBaseMetaTileEntity() - .getSizeInventory(); i++) { - if (tHatch.getBaseMetaTileEntity() - .getStackInSlot(i) != null && isCorrectDataItem( - tHatch.getBaseMetaTileEntity() - .getStackInSlot(i), - state)) - rList.add( - tHatch.getBaseMetaTileEntity() - .getStackInSlot(i)); - } - } - } - return rList; - } - - // this is only called when all slices have finished their work - // and the first slice cannot find a input/fluid cannot be found - // so we are safe to assume the old recipe no longer works - @Override - @NotNull - public CheckRecipeResult checkProcessing() { - if (GT_Values.D1) { - GT_FML_LOGGER.info("Start Adv ALine recipe check"); - } - clearCurrentRecipe(); - CheckRecipeResult result = CheckRecipeResultRegistry.NO_DATA_STICKS; - ArrayList<ItemStack> tDataStickList = getDataItems(2); - if (tDataStickList.isEmpty()) { - return result; - } - if (GT_Values.D1) { - GT_FML_LOGGER.info("Stick accepted, " + tDataStickList.size() + " Data Sticks found"); - } - - GT_Recipe.GT_Recipe_AssemblyLine recipe = null; - - for (ItemStack stack : tDataStickList) { - recipe = findRecipe(stack); - if (recipe == null) { - result = CheckRecipeResultRegistry.NO_RECIPE; - continue; - } - if (recipe.mEUt > inputVoltage) { - result = CheckRecipeResultRegistry.insufficientPower(recipe.mEUt); - continue; - } - - setCurrentRecipe(stack, recipe); - // first overclock normally - // we use the new oc calculator instead - // calculateOverclockedNessMulti from super class has a mysterious 5% cable loss thing at the moment - // of writing - GT_OverclockCalculator ocCalc = new GT_OverclockCalculator().setRecipeEUt(currentRecipe.mEUt) - .setDuration(Math.max(recipe.mDuration / recipe.mInputs.length, 1)) - .setEUt(inputVoltage) - .calculate(); - // since we already checked mEUt <= inputVoltage, no need to check if recipe is too OP - lEUt = ocCalc.getConsumption(); - mMaxProgresstime = ocCalc.getDuration(); - // then laser overclock if needed - if (!mExoticEnergyHatches.isEmpty()) { - OverclockHelper.OverclockOutput laserOverclock = OverclockHelper.laserOverclock( - lEUt, - mMaxProgresstime, - inputEUt / recipe.mInputs.length, - ConfigurationHandler.INSTANCE.getLaserOCPenaltyFactor()); - if (laserOverclock != null) { - lEUt = laserOverclock.getEUt(); - mMaxProgresstime = laserOverclock.getDuration(); - } - } - // Save this for batch mode parallel calculations - int timePerSlice = mMaxProgresstime; - // correct the recipe duration - mMaxProgresstime *= recipe.mInputs.length; - - // Finally apply batch mode parallels if possible. - // For this we need to verify the first item slot and all fluids slots have enough resources - // to execute parallels. - // Note that we skip this entirely if the time for each slice is more than - // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks, since in this case the amount of batches will always be 1 - if (super.isBatchModeEnabled() && timePerSlice < BATCH_MODE_DESIRED_TICKS_PER_SLICE) { - // Calculate parallel based on time per slice, and the amount of fluid in the first fluid slot. - // We use fluid, since this way players can limit parallel by controlling how much fluid - // ends up in each AAL. This way, batch mode will not slow down setups where multiple AAL - // are connected to the same set of input items. Note that this will still suffer from the same - // issue if using stocking hatch, but in this case increasing pattern size can help. - - // Note that every assline recipe has a fluid ingredient. - FluidStack firstFluidSlot = getInputHatchContent(0); - if (firstFluidSlot == null) { - result = CheckRecipeResultRegistry.INTERNAL_ERROR; - break; - } - int recipesAvailable = Math.floorDiv(firstFluidSlot.amount, recipe.mFluidInputs[0].amount); - // Divide recipes available by the amount of slices in the recipe. This will prevent the AAL from - // batching instead of parallelizing, which would make it effectively slower. - recipesAvailable = Math.floorDiv(recipesAvailable, recipe.mInputs.length); - // Sanity check to avoid this being zero when there is only one recipe available. - recipesAvailable = Math.max(recipesAvailable, 1); - int desiredBatches = Math.floorDiv(BATCH_MODE_DESIRED_TICKS_PER_SLICE, timePerSlice); - // Limit the amount of parallel to both the amount of recipes available and the maximum number - // of batches we want to run. The latter is done to prevent batch mode from ever going above - // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks per slice (see also where it is defined above). - int parallel = Math.min(recipesAvailable, desiredBatches); - if (hasAllFluids(recipe, parallel) && hasAllItems(recipe, parallel)) { - this.currentRecipeParallel = parallel; - // Update recipe duration with final batch mode multiplier - mMaxProgresstime *= this.currentRecipeParallel; - } - } - result = CheckRecipeResultRegistry.SUCCESSFUL; - break; - } - if (!result.wasSuccessful()) { - clearCurrentRecipe(); - return result; - } - if (recipe == null || !slices[0].start() || currentRecipeParallel <= 0) { - clearCurrentRecipe(); - // something very very wrong... - return CheckRecipeResultRegistry.INTERNAL_ERROR; - } - - if (GT_Values.D1) { - GT_FML_LOGGER.info("All checked start consuming inputs"); - } - drainAllFluids(recipe, this.currentRecipeParallel); - - // Apply parallel - mOutputItems = new ItemStack[] { recipe.mOutput.copy() }; - mOutputItems[0].stackSize *= this.currentRecipeParallel; - - if (this.lEUt > 0) { - this.lEUt = -this.lEUt; - } - baseEUt = lEUt; - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; - - if (GT_Values.D1) { - GT_FML_LOGGER.info("Recipe successful"); - } - return CheckRecipeResultRegistry.SUCCESSFUL; - } - - @Override - public boolean supportsVoidProtection() { - return true; - } - - @Override - public Set<VoidingMode> getAllowedVoidingModes() { - return VoidingMode.ITEM_ONLY_MODES; - } - - @Override - public boolean isCorrectMachinePart(ItemStack aStack) { - return true; - } - - @Override - public int getMaxEfficiency(ItemStack aStack) { - return 10000; - } - - @Override - public int getDamageToComponent(ItemStack aStack) { - return 0; - } - - @Override - public boolean explodesOnComponentBreak(ItemStack aStack) { - return false; - } - - @Override - protected boolean supportsSlotAutomation(int aSlot) { - return aSlot == getControllerSlotIndex(); - } - - @Override - public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, - IWailaConfigHandler config) { - super.getWailaBody(itemStack, currentTip, accessor, config); - NBTTagCompound tag = accessor.getNBTData(); - String machineProgressString = GT_Waila.getMachineProgressString( - tag.getBoolean("isActive"), - tag.getInteger("maxProgress"), - tag.getInteger("progress")); - currentTip.remove(machineProgressString); - - int duration = tag.getInteger("mDuration"); - if (tag.hasKey(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_LIST)) { - NBTTagList tl = tag.getTagList(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_INT); - @SuppressWarnings("unchecked") - List<NBTTagInt> list = tl.tagList; - for (int i = 0, listSize = list.size(); i < listSize; i++) { - NBTTagInt t = list.get(i); - int progress = t.func_150287_d(); - if (progress == 0) { - currentTip.add(I18n.format("ggfab.waila.advassline.slice.stuck", i + 1)); - } else if (progress < 0) { - currentTip.add(I18n.format("ggfab.waila.advassline.slice.idle", i + 1)); - } else if (duration > 40) { - currentTip.add( - I18n.format("ggfab.waila.advassline.slice", i + 1, (duration - progress) / 20, duration / 20)); - } else { - currentTip - .add(I18n.format("ggfab.waila.advassline.slice.small", i + 1, duration - progress, duration)); - } - } - } - } - - @Override - public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, - int z) { - super.getWailaNBTData(player, tile, tag, world, x, y, z); - if (currentRecipe == null || !getBaseMetaTileEntity().isActive()) return; - NBTTagList l = new NBTTagList(); - for (int i = 0; i < currentInputLength; i++) { - l.appendTag(new NBTTagInt(slices[i].progress)); - } - tag.setTag(TAG_KEY_PROGRESS_TIMES, l); - tag.setInteger("mDuration", mMaxProgresstime / currentInputLength); - } - - /** - * Caller is responsible to check and ensure the hatches are there and has all the fluid needed. You will usually - * want to ensure hasAllFluid was called right before calling this, otherwise very bad things can happen. - */ - private void drainAllFluids(GT_Recipe.GT_Recipe_AssemblyLine recipe, int parallel) { - GT_Recipe.GT_Recipe_AssemblyLine - .consumeInputFluids(mInputHatches, parallel, recipe.mFluidInputs, curBatchFluidsFromME); - for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) tHatch.updateSlots(); - } - - @Override - public void stopMachine(@NotNull ShutDownReason reason) { - clearCurrentRecipe(); - super.stopMachine(reason); - } - - @Override - public boolean supportsBatchMode() { - return true; - } - - @Override - public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, - float aX, float aY, float aZ) { - if (aPlayer.isSneaking()) { - batchMode = !batchMode; - if (batchMode) { - GT_Utility.sendChatToPlayer(aPlayer, "Batch mode enabled"); - } else { - GT_Utility.sendChatToPlayer(aPlayer, "Batch mode disabled"); - } - } - return true; - } - - private class SliceStatusWidget extends TextWidget implements ISyncedWidget { - - private final Slice slice; - private int lastProgress = -2; - private Text text; - - private SliceStatusWidget(Slice slice) { - this.slice = slice; - updateText(); - setEnabled(w -> slice.progress == 0 && currentInputLength > slice.id); - } - - @Override - public Text getText() { - return text; - } - - @Override - public void readOnClient(int id, PacketBuffer buf) { - if (id == 0) { - slice.progress = buf.readVarIntFromBuffer(); - updateText(); - checkNeedsRebuild(); - } - } - - public void updateText() { - String type = "unknown"; - if (slice.progress == 0) type = "stuck"; - else if (slice.progress < 0) type = "idle"; - text = Text.localised("ggfab.gui.advassline.slice." + type, slice.id); - } - - @Override - public void readOnServer(int id, PacketBuffer buf) {} - - @Override - public void detectAndSendChanges(boolean init) { - if (slice.progress != lastProgress) { - // suppress small normal progress update - if (slice.progress > 0 && lastProgress > 0 && lastProgress - slice.progress < 10) return; - lastProgress = slice.progress; - syncToClient(0, b -> b.writeVarIntToBuffer(slice.progress)); - } - } - - @Override - public void markForUpdate() {} - - @Override - public void unMarkForUpdate() {} - - @Override - public boolean isMarkedForUpdate() { - return false; - } - } - - private class Slice { - - private final int id; - private int progress = -1; - - public Slice(int id) { - this.id = id; - } - - public void reset() { - progress = -1; - } - - public void tick() { - if (progress < 0) return; - if (progress == 0 || --progress == 0) { - // id==0 will be end of chain if 1 input, so we need a +1 here - if (id + 1 >= currentInputLength) { - // use previously calculated parallel output - ItemStack output = mOutputItems[0]; - if (addOutput(output) || !voidingMode.protectItem) reset(); - else stuck = true; - } else { - if (slices[id + 1].start()) reset(); - else stuck = true; - } - } - } - - public boolean start() { - if (progress >= 0) return false; - startRecipeProcessing(); - ItemStack stack = getInputBusContent(id); - if (stack == null) return false; - int size = GT_Recipe.GT_Recipe_AssemblyLine - .getMatchedIngredientAmount(stack, currentRecipe.mInputs[id], currentRecipe.mOreDictAlt[id]); - if (size < 0 || stack.stackSize < size * currentRecipeParallel) return false; - progress = mMaxProgresstime / currentInputLength; - stack.stackSize -= size * currentRecipeParallel; - mInputBusses.get(id) - .updateSlots(); - return true; - } - - @Override - public String toString() { - return "Slice{" + "id=" + id + ", progress=" + progress + '}'; - } - } - - private enum DataHatchElement implements IHatchElement<MTE_AdvAssLine> { - - DataAccess; - - @Override - public List<? extends Class<? extends IMetaTileEntity>> mteClasses() { - return Collections.singletonList(GT_MetaTileEntity_Hatch_DataAccess.class); - } - - @Override - public IGT_HatchAdder<MTE_AdvAssLine> adder() { - return MTE_AdvAssLine::addDataAccessToMachineList; - } - - @Override - public long count(MTE_AdvAssLine t) { - return t.mDataAccessHatches.size(); - } - } -} |