package gregtech.api.metatileentity.implementations; import static gregtech.api.enums.GTValues.V; import static gregtech.api.enums.GTValues.debugCleanroom; import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; import static gregtech.api.metatileentity.BaseTileEntity.FLUID_TRANSFER_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.ITEM_TRANSFER_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.NEI_TRANSFER_STEAM_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.NEI_TRANSFER_VOLTAGE_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.POWER_SOURCE_KEY; import static gregtech.api.metatileentity.BaseTileEntity.SPECIAL_SLOT_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.STALLED_STUTTERING_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.STALLED_VENT_TOOLTIP; import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; import static gregtech.api.metatileentity.BaseTileEntity.UNUSED_SLOT_TOOLTIP; import static gregtech.api.util.GTRecipeConstants.EXPLODE; import static gregtech.api.util.GTRecipeConstants.ON_FIRE; import static gregtech.api.util.GTUtility.moveMultipleItemStacks; import static net.minecraftforge.common.util.ForgeDirection.DOWN; import static net.minecraftforge.common.util.ForgeDirection.UNKNOWN; import static net.minecraftforge.common.util.ForgeDirection.UP; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidHandler; import org.apache.commons.lang3.tuple.Pair; import com.gtnewhorizons.modularui.api.drawable.IDrawable; import com.gtnewhorizons.modularui.api.math.Pos2d; import com.gtnewhorizons.modularui.api.math.Size; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import com.gtnewhorizons.modularui.api.widget.Widget; import com.gtnewhorizons.modularui.common.fluid.FluidStackTank; import com.gtnewhorizons.modularui.common.widget.CycleButtonWidget; import com.gtnewhorizons.modularui.common.widget.DrawableWidget; import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; import com.gtnewhorizons.modularui.common.widget.ProgressBar; import com.gtnewhorizons.modularui.common.widget.SlotWidget; import gregtech.GTMod; import gregtech.api.GregTechAPI; import gregtech.api.enums.SoundResource; import gregtech.api.gui.modularui.GTUIInfos; import gregtech.api.gui.modularui.GTUITextures; import gregtech.api.gui.modularui.SteamTexture; import gregtech.api.interfaces.ICleanroom; import gregtech.api.interfaces.IConfigurationCircuitSupport; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.modularui.IAddGregtechLogo; import gregtech.api.interfaces.modularui.IAddUIWidgets; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider; import gregtech.api.interfaces.tileentity.RecipeMapWorkable; import gregtech.api.objects.GTItemStack; import gregtech.api.objects.overclockdescriber.EUOverclockDescriber; import gregtech.api.objects.overclockdescriber.OverclockDescriber; import gregtech.api.recipe.BasicUIProperties; import gregtech.api.recipe.RecipeMap; import gregtech.api.render.TextureFactory; import gregtech.api.util.CoverBehaviorBase; import gregtech.api.util.GTClientPreference; import gregtech.api.util.GTLog; import gregtech.api.util.GTOreDictUnificator; import gregtech.api.util.GTRecipe; import gregtech.api.util.GTUtility; import gregtech.api.util.GTWaila; import gregtech.api.util.GT_TooltipDataCache; import gregtech.api.util.OverclockCalculator; import gregtech.common.gui.modularui.UIHelper; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; /** * NEVER INCLUDE THIS FILE IN YOUR MOD!!! *

* This is the main construct for my Basic Machines such as the Automatic Extractor Extend this class to make a simple * Machine */ public abstract class MTEBasicMachine extends MTEBasicTank implements RecipeMapWorkable, IConfigurationCircuitSupport, IOverclockDescriptionProvider, IAddGregtechLogo, IAddUIWidgets { /** * return values for checkRecipe() */ protected static final int DID_NOT_FIND_RECIPE = 0, FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS = 1, FOUND_AND_SUCCESSFULLY_USED_RECIPE = 2; public static final int OTHER_SLOT_COUNT = 5; public final ItemStack[] mOutputItems; public final int mInputSlotCount, mAmperage; public boolean mAllowInputFromOutputSide = false, mFluidTransfer = false, mItemTransfer = false, mHasBeenUpdated = false, mStuttering = false, mCharge = false, mDecharge = false; public boolean mDisableFilter = true; public boolean mDisableMultiStack = true; public int mProgresstime = 0, mMaxProgresstime = 0, mEUt = 0, mOutputBlocked = 0; public ForgeDirection mMainFacing = ForgeDirection.WEST; public FluidStack mOutputFluid; protected final OverclockDescriber overclockDescriber; /** * Contains the Recipe which has been previously used, or null if there was no previous Recipe, which could have * been buffered */ protected GTRecipe mLastRecipe = null; private FluidStack mFluidOut; protected final FluidStackTank fluidOutputTank = new FluidStackTank( () -> mFluidOut, fluidStack -> mFluidOut = fluidStack, this::getCapacity); /** * Registers machine with single-line description. * * @param aOverlays 0 = SideFacingActive 1 = SideFacingInactive 2 = FrontFacingActive 3 = FrontFacingInactive 4 = * TopFacingActive 5 = TopFacingInactive 6 = BottomFacingActive 7 = BottomFacingInactive ----- Not * all Array Elements have to be initialised, you can also just use 8 Parameters for the Default * Pipe Texture Overlays ----- 8 = BottomFacingPipeActive 9 = BottomFacingPipeInactive 10 = * TopFacingPipeActive 11 = TopFacingPipeInactive 12 = SideFacingPipeActive 13 = * SideFacingPipeInactive */ public MTEBasicMachine(int aID, String aName, String aNameRegional, int aTier, int aAmperage, String aDescription, int aInputSlotCount, int aOutputSlotCount, ITexture... aOverlays) { super( aID, aName, aNameRegional, aTier, OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, aDescription, aOverlays); mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; overclockDescriber = createOverclockDescriber(); } /** * Registers machine with multi-line descriptions. */ public MTEBasicMachine(int aID, String aName, String aNameRegional, int aTier, int aAmperage, String[] aDescription, int aInputSlotCount, int aOutputSlotCount, ITexture... aOverlays) { super( aID, aName, aNameRegional, aTier, OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, aDescription, aOverlays); mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; overclockDescriber = createOverclockDescriber(); } /** * For {@link #newMetaEntity}. */ public MTEBasicMachine(String aName, int aTier, int aAmperage, String[] aDescription, ITexture[][][] aTextures, int aInputSlotCount, int aOutputSlotCount) { super(aName, aTier, OTHER_SLOT_COUNT + aInputSlotCount + aOutputSlotCount + 1, aDescription, aTextures); mInputSlotCount = Math.max(0, aInputSlotCount); mOutputItems = new ItemStack[Math.max(0, aOutputSlotCount)]; mAmperage = aAmperage; overclockDescriber = createOverclockDescriber(); } /** * To be called by the constructor to initialize this instance's overclock behavior */ protected OverclockDescriber createOverclockDescriber() { return new EUOverclockDescriber(mTier, mAmperage); } protected boolean isValidMainFacing(ForgeDirection side) { return (side.flag & (UP.flag | DOWN.flag | UNKNOWN.flag)) == 0; // Horizontal } public boolean setMainFacing(ForgeDirection side) { if (!isValidMainFacing(side)) return false; mMainFacing = side; if (getBaseMetaTileEntity().getFrontFacing() == mMainFacing) { getBaseMetaTileEntity().setFrontFacing(side.getOpposite()); } onFacingChange(); onMachineBlockUpdate(); return true; } @Override public void onFacingChange() { super.onFacingChange(); // Set up the correct facing (front towards player, output opposite) client-side before the server packet // arrives if (mMainFacing == UNKNOWN) { IGregTechTileEntity te = getBaseMetaTileEntity(); if (te != null && te.getWorld().isRemote) { mMainFacing = te.getFrontFacing(); te.setFrontFacing(te.getBackFacing()); } } } @Override public ITexture[][][] getTextureSet(ITexture[] aTextures) { ITexture[][][] rTextures = new ITexture[14][17][]; aTextures = Arrays.copyOf(aTextures, 14); for (int i = 0; i < aTextures.length; i++) if (aTextures[i] != null) for (byte c = -1; c < 16; c++) { if (rTextures[i][c + 1] == null) rTextures[i][c + 1] = new ITexture[] { MACHINE_CASINGS[mTier][c + 1], aTextures[i] }; } for (byte c = -1; c < 16; c++) { if (rTextures[0][c + 1] == null) rTextures[0][c + 1] = getSideFacingActive(c); if (rTextures[1][c + 1] == null) rTextures[1][c + 1] = getSideFacingInactive(c); if (rTextures[2][c + 1] == null) rTextures[2][c + 1] = getFrontFacingActive(c); if (rTextures[3][c + 1] == null) rTextures[3][c + 1] = getFrontFacingInactive(c); if (rTextures[4][c + 1] == null) rTextures[4][c + 1] = getTopFacingActive(c); if (rTextures[5][c + 1] == null) rTextures[5][c + 1] = getTopFacingInactive(c); if (rTextures[6][c + 1] == null) rTextures[6][c + 1] = getBottomFacingActive(c); if (rTextures[7][c + 1] == null) rTextures[7][c + 1] = getBottomFacingInactive(c); if (rTextures[8][c + 1] == null) rTextures[8][c + 1] = getBottomFacingPipeActive(c); if (rTextures[9][c + 1] == null) rTextures[9][c + 1] = getBottomFacingPipeInactive(c); if (rTextures[10][c + 1] == null) rTextures[10][c + 1] = getTopFacingPipeActive(c); if (rTextures[11][c + 1] == null) rTextures[11][c + 1] = getTopFacingPipeInactive(c); if (rTextures[12][c + 1] == null) rTextures[12][c + 1] = getSideFacingPipeActive(c); if (rTextures[13][c + 1] == null) rTextures[13][c + 1] = getSideFacingPipeInactive(c); } return rTextures; } @Override public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { final int textureIndex; if ((mMainFacing.flag & (UP.flag | DOWN.flag)) != 0) { // UP or DOWN if (sideDirection == facingDirection) { textureIndex = active ? 2 : 3; } else { textureIndex = switch (sideDirection) { case DOWN -> active ? 6 : 7; case UP -> active ? 4 : 5; default -> active ? 0 : 1; }; } } else { if (sideDirection == mMainFacing) { textureIndex = active ? 2 : 3; } else { if (showPipeFacing() && sideDirection == facingDirection) { textureIndex = switch (sideDirection) { case DOWN -> active ? 8 : 9; case UP -> active ? 10 : 11; default -> active ? 12 : 13; }; } else { textureIndex = switch (sideDirection) { case DOWN -> active ? 6 : 7; case UP -> active ? 4 : 5; default -> active ? 0 : 1; }; } } } return mTextures[textureIndex][colorIndex + 1]; } @Override public boolean isSimpleMachine() { return false; } @Override public boolean isOverclockerUpgradable() { return false; } @Override public boolean isTransformerUpgradable() { return false; } @Override public boolean isElectric() { return true; } @Override public boolean isValidSlot(int aIndex) { return aIndex > 0 && super.isValidSlot(aIndex) && aIndex != getCircuitSlot() && aIndex != OTHER_SLOT_COUNT + mInputSlotCount + mOutputItems.length; } @Override public boolean isFacingValid(ForgeDirection facing) { // Either mMainFacing or mMainFacing is horizontal return ((facing.flag | mMainFacing.flag) & ~(UP.flag | DOWN.flag | UNKNOWN.flag)) != 0; } @Override public boolean isEnetInput() { return true; } @Override public boolean isInputFacing(ForgeDirection side) { return side != mMainFacing; } @Override public boolean isOutputFacing(ForgeDirection side) { return false; } @Override public boolean isTeleporterCompatible() { return false; } @Override public boolean isLiquidInput(ForgeDirection side) { return side != mMainFacing && (mAllowInputFromOutputSide || side != getBaseMetaTileEntity().getFrontFacing()); } @Override public boolean isLiquidOutput(ForgeDirection side) { return side != mMainFacing; } @Override public long getMinimumStoredEU() { return V[mTier] * 16L; } @Override public long maxEUStore() { return V[mTier] * 64L; } @Override public long maxEUInput() { return V[mTier]; } @Override public long maxSteamStore() { return maxEUStore(); } @Override public long maxAmperesIn() { return ((long) mEUt * 2L) / V[mTier] + 1L; } @Override public int getInputSlot() { return OTHER_SLOT_COUNT; } @Override public int getOutputSlot() { return OTHER_SLOT_COUNT + mInputSlotCount; } public int getSpecialSlotIndex() { return 3; } @Override public int getStackDisplaySlot() { return 2; } @Override public int rechargerSlotStartIndex() { return 1; } @Override public int dechargerSlotStartIndex() { return 1; } @Override public int rechargerSlotCount() { return mCharge ? 1 : 0; } @Override public int dechargerSlotCount() { return mDecharge ? 1 : 0; } @Override public boolean isAccessAllowed(EntityPlayer aPlayer) { return true; } @Override public int getProgresstime() { return mProgresstime; } @Override public int maxProgresstime() { return mMaxProgresstime; } @Override public int increaseProgress(int aProgress) { mProgresstime += aProgress; return mMaxProgresstime - mProgresstime; } @Override public boolean isFluidInputAllowed(FluidStack aFluid) { return getFillableStack() != null || (getRecipeMap() != null && getRecipeMap().containsInput(aFluid)); } @Override public boolean isFluidChangingAllowed() { return true; } @Override public boolean doesFillContainers() { return false; } @Override public boolean doesEmptyContainers() { return false; } @Override public boolean canTankBeFilled() { return true; } @Override public boolean canTankBeEmptied() { return true; } @Override public boolean displaysItemStack() { return true; } @Override public boolean displaysStackSize() { return true; } @Override public FluidStack getDrainableStack() { return mFluidOut; } @Override public FluidStack setDrainableStack(FluidStack aFluid) { markDirty(); mFluidOut = aFluid; return mFluidOut; } @Override public boolean isDrainableStackSeparate() { return true; } @Override public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { if (aBaseMetaTileEntity.isClientSide()) return true; if (!GTMod.gregtechproxy.mForceFreeFace) { GTUIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); return true; } for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { if (aBaseMetaTileEntity.getAirAtSide(side)) { GTUIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); return true; } } GTUtility.sendChatToPlayer(aPlayer, "No free Side!"); return true; } @Override public void initDefaultModes(NBTTagCompound aNBT) { mMainFacing = ForgeDirection.UNKNOWN; if (!getBaseMetaTileEntity().getWorld().isRemote) { final GTClientPreference tPreference = GTMod.gregtechproxy .getClientPreference(getBaseMetaTileEntity().getOwnerUuid()); if (tPreference != null) { mDisableFilter = !tPreference.isSingleBlockInitialFilterEnabled(); mDisableMultiStack = !tPreference.isSingleBlockInitialMultiStackEnabled(); } } } @Override public void saveNBTData(NBTTagCompound aNBT) { super.saveNBTData(aNBT); aNBT.setBoolean("mFluidTransfer", mFluidTransfer); aNBT.setBoolean("mItemTransfer", mItemTransfer); aNBT.setBoolean("mHasBeenUpdated", mHasBeenUpdated); aNBT.setBoolean("mAllowInputFromOutputSide", mAllowInputFromOutputSide); aNBT.setBoolean("mDisableFilter", mDisableFilter); aNBT.setBoolean("mDisableMultiStack", mDisableMultiStack); aNBT.setInteger("mEUt", mEUt); aNBT.setInteger("mMainFacing", mMainFacing.ordinal()); aNBT.setInteger("mProgresstime", mProgresstime); aNBT.setInteger("mMaxProgresstime", mMaxProgresstime); if (mOutputFluid != null) aNBT.setTag("mOutputFluid", mOutputFluid.writeToNBT(new NBTTagCompound())); if (mFluidOut != null) aNBT.setTag("mFluidOut", mFluidOut.writeToNBT(new NBTTagCompound())); for (int i = 0; i < mOutputItems.length; i++) if (mOutputItems[i] != null) GTUtility.saveItem(aNBT, "mOutputItem" + i, mOutputItems[i]); } @Override public void loadNBTData(NBTTagCompound aNBT) { super.loadNBTData(aNBT); mFluidTransfer = aNBT.getBoolean("mFluidTransfer"); mItemTransfer = aNBT.getBoolean("mItemTransfer"); mHasBeenUpdated = aNBT.getBoolean("mHasBeenUpdated"); mAllowInputFromOutputSide = aNBT.getBoolean("mAllowInputFromOutputSide"); mDisableFilter = aNBT.getBoolean("mDisableFilter"); mDisableMultiStack = aNBT.getBoolean("mDisableMultiStack"); mEUt = aNBT.getInteger("mEUt"); mMainFacing = ForgeDirection.getOrientation(aNBT.getInteger("mMainFacing")); mProgresstime = aNBT.getInteger("mProgresstime"); mMaxProgresstime = aNBT.getInteger("mMaxProgresstime"); mOutputFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mOutputFluid")); mFluidOut = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluidOut")); for (int i = 0; i < mOutputItems.length; i++) mOutputItems[i] = GTUtility.loadItem(aNBT, "mOutputItem" + i); } @Override public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { super.onPostTick(aBaseMetaTileEntity, aTick); if (aBaseMetaTileEntity.isServerSide()) { mCharge = aBaseMetaTileEntity.getStoredEU() / 2 > aBaseMetaTileEntity.getEUCapacity() / 3; mDecharge = aBaseMetaTileEntity.getStoredEU() < aBaseMetaTileEntity.getEUCapacity() / 3; doDisplayThings(); boolean tSucceeded = false; if (mMaxProgresstime > 0 && (mProgresstime >= 0 || aBaseMetaTileEntity.isAllowedToWork())) { markDirty(); aBaseMetaTileEntity.setActive(true); if (mProgresstime < 0 || drainEnergyForProcess(mEUt)) { if (++mProgresstime >= mMaxProgresstime) { for (int i = 0; i < mOutputItems.length; i++) for (int j = 0; j < mOutputItems.length; j++) if (aBaseMetaTileEntity .addStackToSlot(getOutputSlot() + ((j + i) % mOutputItems.length), mOutputItems[i])) break; if (mOutputFluid != null) if (getDrainableStack() == null) setDrainableStack(mOutputFluid.copy()); else if (mOutputFluid.isFluidEqual(getDrainableStack())) getDrainableStack().amount += mOutputFluid.amount; Arrays.fill(mOutputItems, null); mOutputFluid = null; mEUt = 0; mProgresstime = 0; mMaxProgresstime = 0; mStuttering = false; tSucceeded = true; endProcess(); } if (mProgresstime > 5) mStuttering = false; } else { if (!mStuttering) { stutterProcess(); if (canHaveInsufficientEnergy()) mProgresstime = -100; mStuttering = true; } } } else { aBaseMetaTileEntity.setActive(false); } boolean tRemovedOutputFluid = false; if (doesAutoOutputFluids() && getDrainableStack() != null && aBaseMetaTileEntity.getFrontFacing() != mMainFacing && (tSucceeded || aTick % 20 == 0)) { IFluidHandler tTank = aBaseMetaTileEntity.getITankContainerAtSide(aBaseMetaTileEntity.getFrontFacing()); if (tTank != null) { FluidStack tDrained = drain(1000, false); if (tDrained != null) { final int tFilledAmount = tTank.fill(aBaseMetaTileEntity.getBackFacing(), tDrained, false); if (tFilledAmount > 0) tTank.fill(aBaseMetaTileEntity.getBackFacing(), drain(tFilledAmount, true), true); } } if (getDrainableStack() == null) tRemovedOutputFluid = true; } if (doesAutoOutput() && !isOutputEmpty() && aBaseMetaTileEntity.getFrontFacing() != mMainFacing && (tSucceeded || mOutputBlocked % 300 == 1 || aBaseMetaTileEntity.hasInventoryBeenModified() || aTick % 600 == 0)) { TileEntity tTileEntity2 = aBaseMetaTileEntity.getTileEntityAtSide(aBaseMetaTileEntity.getFrontFacing()); long tStoredEnergy = aBaseMetaTileEntity.getUniversalEnergyStored(); int tMaxStacks = (int) (tStoredEnergy / 64L); if (tMaxStacks > mOutputItems.length) tMaxStacks = mOutputItems.length; moveMultipleItemStacks( aBaseMetaTileEntity, tTileEntity2, aBaseMetaTileEntity.getFrontFacing(), aBaseMetaTileEntity.getBackFacing(), null, false, (byte) 64, (byte) 1, (byte) 64, (byte) 1, tMaxStacks); } if (mOutputBlocked != 0) if (isOutputEmpty()) mOutputBlocked = 0; else mOutputBlocked++; if (allowToCheckRecipe()) { if (mMaxProgresstime <= 0 && aBaseMetaTileEntity.isAllowedToWork() && (tRemovedOutputFluid || tSucceeded || aBaseMetaTileEntity.hasInventoryBeenModified() || aTick % 600 == 0 || aBaseMetaTileEntity.hasWorkJustBeenEnabled()) && hasEnoughEnergyToCheckRecipe()) { if (checkRecipe() == FOUND_AND_SUCCESSFULLY_USED_RECIPE) { if (getSpecialSlot() != null && getSpecialSlot().stackSize <= 0) mInventory[getSpecialSlotIndex()] = null; for (int i = getInputSlot(), j = i + mInputSlotCount; i < j; i++) if (mInventory[i] != null && mInventory[i].stackSize <= 0) mInventory[i] = null; for (int i = 0; i < mOutputItems.length; i++) { mOutputItems[i] = GTUtility.copyOrNull(mOutputItems[i]); if (mOutputItems[i] != null && mOutputItems[i].stackSize > 64) mOutputItems[i].stackSize = 64; mOutputItems[i] = GTOreDictUnificator.get(true, mOutputItems[i]); } if (mFluid != null && mFluid.amount <= 0) mFluid = null; mMaxProgresstime = Math.max(1, mMaxProgresstime); if (GTUtility.isDebugItem(mInventory[dechargerSlotStartIndex()])) { mEUt = mMaxProgresstime = 1; } startProcess(); } else { mMaxProgresstime = 0; Arrays.fill(mOutputItems, null); mOutputFluid = null; } } } else { if (!mStuttering) { stutterProcess(); mStuttering = true; } } } // Only using mNeedsSteamVenting right now and assigning it to 64 to space in the range for more single block // machine problems. // Value | Class | Field // 1 | GT_MetaTileEntity_BasicMachine | mStuttering // 64 | GT_MetaTileEntity_BasicMachine_Bronze | mNeedsSteamVenting aBaseMetaTileEntity.setErrorDisplayID((aBaseMetaTileEntity.getErrorDisplayID() & ~127)); // | (mStuttering ? 1 : // 0)); } protected void doDisplayThings() { if (!isValidMainFacing(mMainFacing) && isValidMainFacing(getBaseMetaTileEntity().getFrontFacing())) { mMainFacing = getBaseMetaTileEntity().getFrontFacing(); } if (isValidMainFacing(mMainFacing) && !mHasBeenUpdated) { mHasBeenUpdated = true; getBaseMetaTileEntity().setFrontFacing(getBaseMetaTileEntity().getBackFacing()); } } protected boolean hasEnoughEnergyToCheckRecipe() { return getBaseMetaTileEntity().isUniversalEnergyStored(getMinimumStoredEU() / 2); } protected boolean drainEnergyForProcess(long aEUt) { return getBaseMetaTileEntity().decreaseStoredEnergyUnits(aEUt, false); } /** * Calculates overclock based on {@link #overclockDescriber}. */ protected void calculateCustomOverclock(GTRecipe recipe) { OverclockCalculator calculator = overclockDescriber.createCalculator( new OverclockCalculator().setRecipeEUt(recipe.mEUt) .setDuration(recipe.mDuration) .setOneTickDiscount(true), recipe); calculator.calculate(); mEUt = (int) calculator.getConsumption(); mMaxProgresstime = calculator.getDuration(); } /** * Helper method for calculating simple overclock. */ protected void calculateOverclockedNess(int eut, int duration) { OverclockCalculator calculator = new OverclockCalculator().setRecipeEUt(eut) .setEUt(V[mTier] * mAmperage) .setDuration(duration) .setOneTickDiscount(true) .calculate(); mEUt = (int) calculator.getConsumption(); mMaxProgresstime = calculator.getDuration(); } protected ItemStack getSpecialSlot() { return mInventory[getSpecialSlotIndex()]; } protected ItemStack getOutputAt(int aIndex) { return mInventory[getOutputSlot() + aIndex]; } protected ItemStack[] getAllOutputs() { ItemStack[] rOutputs = new ItemStack[mOutputItems.length]; for (int i = 0; i < mOutputItems.length; i++) rOutputs[i] = getOutputAt(i); return rOutputs; } protected boolean canOutput(GTRecipe aRecipe) { return aRecipe != null && (aRecipe.mNeedsEmptyOutput ? isOutputEmpty() && getDrainableStack() == null : canOutput(aRecipe.getFluidOutput(0)) && canOutput(aRecipe.mOutputs)); } protected boolean canOutput(ItemStack... aOutputs) { if (aOutputs == null) return true; ItemStack[] tOutputSlots = getAllOutputs(); for (int i = 0; i < tOutputSlots.length && i < aOutputs.length; i++) if (tOutputSlots[i] != null && aOutputs[i] != null && (!GTUtility.areStacksEqual(tOutputSlots[i], aOutputs[i], false) || tOutputSlots[i].stackSize + aOutputs[i].stackSize > tOutputSlots[i].getMaxStackSize())) { mOutputBlocked++; return false; } return true; } protected boolean canOutput(FluidStack aOutput) { if (aOutput == null) return true; FluidStack drainableStack = getDrainableStack(); if (drainableStack != null && !drainableStack.isFluidEqual(aOutput)) return false; return (drainableStack != null ? drainableStack.amount : 0) + aOutput.amount <= getCapacity(); } protected ItemStack getInputAt(int aIndex) { return mInventory[getInputSlot() + aIndex]; } protected ItemStack[] getAllInputs() { int tRealInputSlotCount = this.mInputSlotCount + (allowSelectCircuit() ? 1 : 0); ItemStack[] rInputs = new ItemStack[tRealInputSlotCount]; for (int i = 0; i < mInputSlotCount; i++) rInputs[i] = getInputAt(i); if (allowSelectCircuit()) rInputs[mInputSlotCount] = getStackInSlot(getCircuitSlot()); return rInputs; } protected boolean isOutputEmpty() { boolean rIsEmpty = true; for (ItemStack tOutputSlotContent : getAllOutputs()) if (tOutputSlotContent != null) { rIsEmpty = false; break; } return rIsEmpty; } @Override public void onValueUpdate(byte aValue) { mMainFacing = ForgeDirection.getOrientation(aValue); } @Override public byte getUpdateData() { return (byte) mMainFacing.ordinal(); } @Override public void doSound(byte aIndex, double aX, double aY, double aZ) { super.doSound(aIndex, aX, aY, aZ); if (aIndex == 8) GTUtility.doSoundAtClient(SoundResource.IC2_MACHINES_INTERRUPT_ONE, 100, 1.0F, aX, aY, aZ); } public boolean doesAutoOutput() { return mItemTransfer; } public boolean doesAutoOutputFluids() { return mFluidTransfer; } public boolean allowToCheckRecipe() { return true; } public boolean showPipeFacing() { return true; } /** * Called whenever the Machine successfully started a Process, useful for Sound Effects */ public void startProcess() { // } /** * Called whenever the Machine successfully finished a Process, useful for Sound Effects */ public void endProcess() { // } /** * Called whenever the Machine aborted a Process, useful for Sound Effects */ public void abortProcess() { // } /** * Called whenever the Machine aborted a Process but still works on it, useful for Sound Effects */ public void stutterProcess() { if (useStandardStutterSound()) sendSound((byte) 8); } /** * If this Machine can have the Insufficient Energy Line Problem */ public boolean canHaveInsufficientEnergy() { return true; } public boolean useStandardStutterSound() { return true; } @Override public String[] getInfoData() { return new String[] { "Progress:", EnumChatFormatting.GREEN + GTUtility.formatNumbers((mProgresstime / 20)) + EnumChatFormatting.RESET + " s / " + EnumChatFormatting.YELLOW + GTUtility.formatNumbers(mMaxProgresstime / 20) + EnumChatFormatting.RESET + " s", "Stored Energy:", EnumChatFormatting.GREEN + GTUtility.formatNumbers(getBaseMetaTileEntity().getStoredEU()) + EnumChatFormatting.RESET + " EU / " + EnumChatFormatting.YELLOW + GTUtility.formatNumbers(getBaseMetaTileEntity().getEUCapacity()) + EnumChatFormatting.RESET + " EU", "Probably uses: " + EnumChatFormatting.RED + GTUtility.formatNumbers(mEUt) + EnumChatFormatting.RESET + " EU/t at " + EnumChatFormatting.RED + GTUtility.formatNumbers(mEUt == 0 ? 0 : mAmperage) + EnumChatFormatting.RESET + " A" }; } @Override public boolean isGivingInformation() { return true; } @Override public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { if (side == getBaseMetaTileEntity().getFrontFacing() || side == mMainFacing) { if (aPlayer.isSneaking()) { mDisableFilter = !mDisableFilter; GTUtility.sendChatToPlayer( aPlayer, StatCollector.translateToLocal("GT5U.hatch.disableFilter." + mDisableFilter)); } else { mAllowInputFromOutputSide = !mAllowInputFromOutputSide; GTUtility.sendChatToPlayer( aPlayer, mAllowInputFromOutputSide ? GTUtility.trans("095", "Input from Output Side allowed") : GTUtility.trans("096", "Input from Output Side forbidden")); } } } @Override public boolean onSolderingToolRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, float aX, float aY, float aZ) { if (!entityPlayer.isSneaking()) return false; final boolean click = super.onSolderingToolRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ); if (click) return true; if (wrenchingSide != mMainFacing) return false; mDisableMultiStack = !mDisableMultiStack; GTUtility.sendChatToPlayer( entityPlayer, StatCollector.translateToLocal("GT5U.hatch.disableMultiStack." + mDisableMultiStack)); return true; } @Override public boolean allowCoverOnSide(ForgeDirection side, GTItemStack aCoverID) { if (side != mMainFacing) return true; CoverBehaviorBase tBehavior = GregTechAPI.getCoverBehaviorNew(aCoverID.toStack()); return tBehavior.isGUIClickable( side, GTUtility.stackToInt(aCoverID.toStack()), tBehavior.createDataObject(), getBaseMetaTileEntity()); } @Override public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, ItemStack aStack) { return side != mMainFacing && aIndex >= getOutputSlot() && aIndex < getOutputSlot() + mOutputItems.length; } @Override public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, ItemStack aStack) { if (side == mMainFacing || aIndex < getInputSlot() || aIndex >= getInputSlot() + mInputSlotCount || (!mAllowInputFromOutputSide && side == aBaseMetaTileEntity.getFrontFacing())) return false; for (int i = getInputSlot(), j = i + mInputSlotCount; i < j; i++) if (GTUtility.areStacksEqual(GTOreDictUnificator.get(aStack), mInventory[i]) && mDisableMultiStack) return i == aIndex; return mDisableFilter || allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack); } /** * Test if given stack can be inserted into specified slot. If mDisableMultiStack is false, before execution of this * method it is ensured there is no such kind of item inside any input slots already. Otherwise, you don't need to * check for it anyway. */ protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, ItemStack aStack) { return !mDisableMultiStack || mInventory[aIndex] == null; } @Override public boolean allowSelectCircuit() { return false; } protected final ItemStack[] appendSelectedCircuit(ItemStack... inputs) { if (allowSelectCircuit()) { ItemStack circuit = getStackInSlot(getCircuitSlot()); if (circuit != null) { ItemStack[] result = Arrays.copyOf(inputs, inputs.length + 1); result[inputs.length] = circuit; return result; } } return inputs; } @Override public int getCircuitSlot() { return 4; } @Override public int getCircuitGUISlot() { return 3; } @Override public List getConfigurationCircuits() { return GregTechAPI.getConfigurationCircuitList(mTier); } @Override public RecipeMap getRecipeMap() { return null; } /** * Override this to check the Recipes yourself, super calls to this could be useful if you just want to add a * special case *

* I thought about Enum too, but Enum doesn't add support for people adding other return Systems. *

* Funny how Eclipse marks the word Enum as not correctly spelled. * * @return see constants above */ public int checkRecipe() { return checkRecipe(false); } public static boolean isValidForLowGravity(GTRecipe tRecipe, int dimId) { return // TODO check or get a better solution DimensionManager.getProvider(dimId) .getClass() .getName() .contains("Orbit") || DimensionManager.getProvider(dimId) .getClass() .getName() .endsWith("Space") || DimensionManager.getProvider(dimId) .getClass() .getName() .endsWith("Asteroids") || DimensionManager.getProvider(dimId) .getClass() .getName() .endsWith("SS") || DimensionManager.getProvider(dimId) .getClass() .getName() .contains("SpaceStation"); } /** * * @param skipOC disables OverclockedNess calculation and check - if you do you must implement your own method... * @return DID_NOT_FIND_RECIPE = 0, FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS = 1, * FOUND_AND_SUCCESSFULLY_USED_RECIPE = 2; */ public int checkRecipe(boolean skipOC) { RecipeMap tMap = getRecipeMap(); if (tMap == null) return DID_NOT_FIND_RECIPE; GTRecipe tRecipe = tMap.findRecipeQuery() .items(getAllInputs()) .fluids(getFillableStack()) .specialSlot(getSpecialSlot()) .voltage(V[mTier]) .cachedRecipe(mLastRecipe) .find(); if (tRecipe == null) { return DID_NOT_FIND_RECIPE; } if (tRecipe.getMetadataOrDefault(EXPLODE, false) && getBaseMetaTileEntity() != null) { getBaseMetaTileEntity().doExplosion(V[mTier] * 4); return DID_NOT_FIND_RECIPE; } if (tRecipe.getMetadataOrDefault(ON_FIRE, false) && getBaseMetaTileEntity() != null) { getBaseMetaTileEntity().setOnFire(); return DID_NOT_FIND_RECIPE; } if (GTMod.gregtechproxy.mLowGravProcessing && (tRecipe.mSpecialValue == -100 || tRecipe.mSpecialValue == -300) && !isValidForLowGravity(tRecipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; if (tRecipe.mCanBeBuffered) mLastRecipe = tRecipe; if (!canOutput(tRecipe)) { mOutputBlocked++; return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; } ICleanroom cleanroom = getCleanroom(); if (tRecipe.mSpecialValue == -200 || tRecipe.mSpecialValue == -300) { if (cleanroom == null || !cleanroom.isValidCleanroom() || cleanroom.getCleanness() == 0) { return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; } } if (!tRecipe.isRecipeInputEqual(true, new FluidStack[] { getFillableStack() }, getAllInputs())) return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; for (int i = 0; i < mOutputItems.length; i++) if (getBaseMetaTileEntity().getRandomNumber(10000) < tRecipe.getOutputChance(i)) mOutputItems[i] = tRecipe.getOutput(i); if (tRecipe.mSpecialValue == -200 || tRecipe.mSpecialValue == -300) { assert cleanroom != null; for (int i = 0; i < mOutputItems.length; i++) if (mOutputItems[i] != null && getBaseMetaTileEntity().getRandomNumber(10000) > cleanroom.getCleanness()) { if (debugCleanroom) { GTLog.out.println( "BasicMachine: Voiding output due to cleanness failure. Cleanness = " + cleanroom.getCleanness()); } mOutputItems[i] = null; } } mOutputFluid = tRecipe.getFluidOutput(0); if (!skipOC) { calculateCustomOverclock(tRecipe); // In case recipe is too OP for that machine if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; } return FOUND_AND_SUCCESSFULLY_USED_RECIPE; } public ITexture[] getSideFacingActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getSideFacingInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getFrontFacingActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getFrontFacingInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getTopFacingActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getTopFacingInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getBottomFacingActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getBottomFacingInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1] }; } public ITexture[] getBottomFacingPipeActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } public ITexture[] getBottomFacingPipeInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } public ITexture[] getTopFacingPipeActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } public ITexture[] getTopFacingPipeInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } public ITexture[] getSideFacingPipeActive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } public ITexture[] getSideFacingPipeInactive(byte aColor) { return new ITexture[] { MACHINE_CASINGS[mTier][aColor + 1], TextureFactory.of(OVERLAY_PIPE_OUT) }; } @Override public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor, IWailaConfigHandler config) { final NBTTagCompound tag = accessor.getNBTData(); if (tag.getBoolean("stutteringSingleBlock")) { currenttip.add("Status: insufficient energy"); } else { boolean isActive = tag.getBoolean("isActiveSingleBlock"); if (isActive) { int mEUt = tag.getInteger("eut"); if (!isSteampowered()) { if (mEUt > 0) { currenttip.add( StatCollector.translateToLocalFormatted( "GT5U.waila.energy.use_with_amperage", GTUtility.formatNumbers(mEUt), GTUtility.getAmperageForTier(mEUt, (byte) getInputTier()), GTUtility.getColoredTierNameFromTier((byte) getInputTier()))); } else if (mEUt < 0) { currenttip.add( StatCollector.translateToLocalFormatted( "GT5U.waila.energy.produce_with_amperage", GTUtility.formatNumbers(-mEUt), GTUtility.getAmperageForTier(-mEUt, (byte) getOutputTier()), GTUtility.getColoredTierNameFromTier((byte) getOutputTier()))); } } else { if (mEUt > 0) { currenttip.add( StatCollector.translateToLocalFormatted( "GT5U.waila.energy.use", GTUtility.formatNumbers(mEUt), GTUtility.getColoredTierNameFromVoltage(mEUt))); } else if (mEUt < 0) { currenttip.add( StatCollector.translateToLocalFormatted( "GT5U.waila.energy.produce", GTUtility.formatNumbers(-mEUt), GTUtility.getColoredTierNameFromVoltage(-mEUt))); } } } currenttip.add( GTWaila.getMachineProgressString( isActive, tag.getInteger("maxProgressSingleBlock"), tag.getInteger("progressSingleBlock"))); } currenttip.add( String.format( "Machine Facing: %s", ForgeDirection.getOrientation(tag.getInteger("mainFacingSingleBlock")) .name())); currenttip.add( String.format( "Output Facing: %s", ForgeDirection.getOrientation(tag.getInteger("outputFacingSingleBlock")) .name())); } @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); tag.setInteger("progressSingleBlock", mProgresstime); tag.setInteger("maxProgressSingleBlock", mMaxProgresstime); tag.setInteger("mainFacingSingleBlock", mMainFacing.ordinal()); tag.setBoolean("stutteringSingleBlock", mStuttering); final IGregTechTileEntity tileEntity = getBaseMetaTileEntity(); if (tileEntity != null) { tag.setBoolean("isActiveSingleBlock", tileEntity.isActive()); tag.setInteger( "outputFacingSingleBlock", tileEntity.getFrontFacing() .ordinal()); if (tileEntity.isActive()) tag.setInteger("eut", mEUt); } } @Nonnull @Override public OverclockDescriber getOverclockDescriber() { return overclockDescriber; } // GUI stuff @Override public int getCircuitSlotX() { return 153; } @Override public int getCircuitSlotY() { return 63; } @Override public void addGregTechLogo(ModularWindow.Builder builder) { if (getRecipeMap() != null) { getRecipeMap().getFrontend() .addGregTechLogo(builder, new Pos2d(0, 0)); } else { builder.widget( new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) .setSize(17, 17) .setPos(152, 63)); } } @Override public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { if (!isSteampowered()) { builder.widget(createFluidAutoOutputButton()); builder.widget(createItemAutoOutputButton()); } BasicUIProperties uiProperties = getUIProperties(); addIOSlots(builder, uiProperties); builder.widget(createChargerSlot(79, 62)); addProgressBar(builder, uiProperties); builder.widget( createErrorStatusArea( builder, isSteampowered() ? GTUITextures.PICTURE_STALLED_STEAM : GTUITextures.PICTURE_STALLED_ELECTRICITY)); } /** * Override to specify UI properties if this machine doesn't work with recipemap. */ protected BasicUIProperties getUIProperties() { if (getRecipeMap() != null) { BasicUIProperties originalProperties = getRecipeMap().getFrontend() .getUIProperties(); return originalProperties.toBuilder() .maxItemInputs(mInputSlotCount) .maxItemOutputs(mOutputItems.length) .maxFluidInputs(Math.min(originalProperties.maxFluidInputs, 1)) .maxFluidOutputs(Math.min(originalProperties.maxFluidOutputs, 1)) .build(); } return BasicUIProperties.builder() .maxItemInputs(mInputSlotCount) .maxItemOutputs(mOutputItems.length) .maxFluidInputs(getCapacity() != 0 ? 1 : 0) .maxFluidOutputs(0) .build(); } /** * Adds item I/O, special item, and fluid I/O slots. */ protected void addIOSlots(ModularWindow.Builder builder, BasicUIProperties uiProperties) { UIHelper.forEachSlots( (i, backgrounds, pos) -> builder.widget(createItemInputSlot(i, backgrounds, pos)), (i, backgrounds, pos) -> builder.widget(createItemOutputSlot(i, backgrounds, pos)), (i, backgrounds, pos) -> builder.widget(createSpecialSlot(backgrounds, pos, uiProperties)), (i, backgrounds, pos) -> builder.widget(createFluidInputSlot(backgrounds, pos)), (i, backgrounds, pos) -> builder.widget(createFluidOutputSlot(backgrounds, pos)), getGUITextureSet().getItemSlot(), getGUITextureSet().getFluidSlot(), uiProperties, uiProperties.maxItemInputs, uiProperties.maxItemOutputs, uiProperties.maxFluidInputs, uiProperties.maxFluidOutputs, getSteamVariant(), Pos2d.ZERO); } protected void addProgressBar(ModularWindow.Builder builder, BasicUIProperties uiProperties) { boolean isSteamPowered = isSteampowered(); RecipeMap recipeMap = getRecipeMap(); if (!isSteamPowered && uiProperties.progressBarTexture == null) { if (recipeMap != null) { // Require progress bar texture for machines working with recipemap, otherwise permit throw new RuntimeException("Missing progressbar texture for " + recipeMap.unlocalizedName); } else { return; } } if (isSteamPowered && uiProperties.progressBarTextureSteam == null) { if (recipeMap != null) { throw new RuntimeException("Missing steam progressbar texture for " + recipeMap.unlocalizedName); } else { return; } } builder.widget( setNEITransferRect( new ProgressBar() .setProgress(() -> maxProgresstime() != 0 ? (float) getProgresstime() / maxProgresstime() : 0) .setTexture( isSteamPowered ? uiProperties.progressBarTextureSteam.get(getSteamVariant()) : uiProperties.progressBarTexture.get(), uiProperties.progressBarImageSize) .setDirection(uiProperties.progressBarDirection) .setPos(uiProperties.progressBarPos) .setSize(uiProperties.progressBarSize), uiProperties.neiTransferRectId)); addProgressBarSpecialTextures(builder, uiProperties); } /** * Override this as needed instead of calling. */ protected SlotWidget createItemInputSlot(int index, IDrawable[] backgrounds, Pos2d pos) { return (SlotWidget) new SlotWidget(inventoryHandler, getInputSlot() + index).setAccess(true, true) .setBackground(backgrounds) .setPos(pos); } /** * Override this as needed instead of calling. */ protected SlotWidget createItemOutputSlot(int index, IDrawable[] backgrounds, Pos2d pos) { return (SlotWidget) new SlotWidget(inventoryHandler, getOutputSlot() + index).setAccess(true, false) .setBackground(backgrounds) .setPos(pos); } /** * Override this as needed instead of calling. */ protected SlotWidget createSpecialSlot(IDrawable[] backgrounds, Pos2d pos, BasicUIProperties uiProperties) { return (SlotWidget) new SlotWidget(inventoryHandler, getSpecialSlotIndex()).setAccess(true, true) .disableShiftInsert() .setGTTooltip( () -> mTooltipCache.getData(uiProperties.useSpecialSlot ? SPECIAL_SLOT_TOOLTIP : UNUSED_SLOT_TOOLTIP)) .setTooltipShowUpDelay(TOOLTIP_DELAY) .setBackground(backgrounds) .setPos(pos); } protected FluidSlotWidget createFluidInputSlot(IDrawable[] backgrounds, Pos2d pos) { return (FluidSlotWidget) new FluidSlotWidget(fluidTank).setBackground(backgrounds) .setPos(pos); } protected FluidSlotWidget createFluidOutputSlot(IDrawable[] backgrounds, Pos2d pos) { return (FluidSlotWidget) new FluidSlotWidget(fluidOutputTank).setInteraction(true, false) .setBackground(backgrounds) .setPos(pos); } @Override protected SlotWidget createChargerSlot(int x, int y) { if (isSteampowered()) { return (SlotWidget) createChargerSlot(x, y, UNUSED_SLOT_TOOLTIP, new String[0]) .setBackground(getGUITextureSet().getItemSlot()); } else { return super.createChargerSlot(x, y); } } protected CycleButtonWidget createItemAutoOutputButton() { return (CycleButtonWidget) new CycleButtonWidget().setToggle(() -> mItemTransfer, val -> mItemTransfer = val) .setStaticTexture(GTUITextures.OVERLAY_BUTTON_AUTOOUTPUT_ITEM) .setVariableBackground(GTUITextures.BUTTON_STANDARD_TOGGLE) .setGTTooltip(() -> mTooltipCache.getData(ITEM_TRANSFER_TOOLTIP)) .setTooltipShowUpDelay(TOOLTIP_DELAY) .setPos(25, 62) .setSize(18, 18); } protected CycleButtonWidget createFluidAutoOutputButton() { return (CycleButtonWidget) new CycleButtonWidget().setToggle(() -> mFluidTransfer, val -> mFluidTransfer = val) .setStaticTexture(GTUITextures.OVERLAY_BUTTON_AUTOOUTPUT_FLUID) .setVariableBackground(GTUITextures.BUTTON_STANDARD_TOGGLE) .setGTTooltip(() -> mTooltipCache.getData(FLUID_TRANSFER_TOOLTIP)) .setTooltipShowUpDelay(TOOLTIP_DELAY) .setPos(7, 62) .setSize(18, 18); } protected Widget setNEITransferRect(Widget widget, String transferRectID) { if (GTUtility.isStringInvalid(transferRectID)) { return widget; } final String transferRectTooltip; if (isSteampowered()) { transferRectTooltip = StatCollector .translateToLocalFormatted(NEI_TRANSFER_STEAM_TOOLTIP, overclockDescriber.getTierString()); } else { transferRectTooltip = StatCollector .translateToLocalFormatted(NEI_TRANSFER_VOLTAGE_TOOLTIP, overclockDescriber.getTierString()); } widget.setNEITransferRect(transferRectID, new Object[] { overclockDescriber }, transferRectTooltip); return widget; } protected void addProgressBarSpecialTextures(ModularWindow.Builder builder, BasicUIProperties uiProperties) { if (isSteampowered()) { for (Pair> specialTexture : uiProperties.specialTexturesSteam) { builder.widget( new DrawableWidget().setDrawable( specialTexture.getLeft() .get(getSteamVariant())) .setSize( specialTexture.getRight() .getLeft()) .setPos( specialTexture.getRight() .getRight())); } } else { for (Pair> specialTexture : uiProperties.specialTextures) { builder.widget( new DrawableWidget().setDrawable(specialTexture.getLeft()) .setSize( specialTexture.getRight() .getLeft()) .setPos( specialTexture.getRight() .getRight())); } } } protected DrawableWidget createErrorStatusArea(ModularWindow.Builder builder, IDrawable picture) { return (DrawableWidget) new DrawableWidget().setDrawable(picture) .setTooltipShowUpDelay(TOOLTIP_DELAY) .setEnabled( widget -> !widget.getTooltip() .isEmpty()) .dynamicTooltip(this::getErrorDescriptions) .dynamicTooltipShift(this::getErrorDescriptionsShift) .setPos(79, 44) .setSize(18, 18) .attachSyncer( new FakeSyncWidget.BooleanSyncer(() -> mStuttering, val -> mStuttering = val), builder, (widget, val) -> widget.notifyTooltipChange()) .attachSyncer( new FakeSyncWidget.IntegerSyncer( () -> getBaseMetaTileEntity().getErrorDisplayID(), val -> getBaseMetaTileEntity().setErrorDisplayID(val)), builder, (widget, val) -> widget.notifyTooltipChange()); } protected List getErrorDescriptions() { final GT_TooltipDataCache.TooltipData tooltip = getErrorTooltip(); return tooltip != null ? tooltip.text : Collections.emptyList(); } protected List getErrorDescriptionsShift() { final GT_TooltipDataCache.TooltipData tooltip = getErrorTooltip(); return tooltip != null ? tooltip.shiftText : Collections.emptyList(); } protected GT_TooltipDataCache.TooltipData getErrorTooltip() { if (isSteampowered()) { if ((getBaseMetaTileEntity().getErrorDisplayID() & 64) != 0) { return mTooltipCache.getData(STALLED_VENT_TOOLTIP); } } if (mStuttering) { return mTooltipCache.getData( STALLED_STUTTERING_TOOLTIP, StatCollector.translateToLocal(POWER_SOURCE_KEY + (isSteampowered() ? "steam" : "power"))); } return null; } protected static int getCapacityForTier(int tier) { return switch (tier) { case 0 -> 8000; case 1 -> 16000; case 2 -> 32000; case 3 -> 64000; case 4 -> 128000; default -> 256000; }; } }