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