diff options
Diffstat (limited to 'src/main/java/gregtech/api/metatileentity/implementations')
37 files changed, 14408 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java new file mode 100644 index 0000000000..1477f989f8 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java @@ -0,0 +1,679 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Mods.GalacticraftCore; +import static net.minecraftforge.common.util.ForgeDirection.DOWN; +import static net.minecraftforge.common.util.ForgeDirection.EAST; +import static net.minecraftforge.common.util.ForgeDirection.NORTH; +import static net.minecraftforge.common.util.ForgeDirection.SOUTH; +import static net.minecraftforge.common.util.ForgeDirection.UP; +import static net.minecraftforge.common.util.ForgeDirection.WEST; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import cofh.api.energy.IEnergyReceiver; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Materials; +import gregtech.api.enums.TextureSet; +import gregtech.api.enums.Textures; +import gregtech.api.graphs.Node; +import gregtech.api.graphs.NodeList; +import gregtech.api.graphs.PowerNode; +import gregtech.api.graphs.PowerNodes; +import gregtech.api.graphs.consumers.ConsumerNode; +import gregtech.api.graphs.paths.PowerNodePath; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IConnectable; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.metatileentity.IMetaTileEntityCable; +import gregtech.api.interfaces.tileentity.ICoverable; +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.interfaces.PowerLogicHost; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.objects.GT_Cover_None; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_CoverBehavior; +import gregtech.api.util.GT_CoverBehaviorBase; +import gregtech.api.util.GT_GC_Compat; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.ISerializableObject; +import gregtech.common.GT_Client; +import gregtech.common.covers.CoverInfo; +import gregtech.common.covers.GT_Cover_SolarPanel; +import ic2.api.energy.EnergyNet; +import ic2.api.energy.tile.IEnergyEmitter; +import ic2.api.energy.tile.IEnergySink; +import ic2.api.energy.tile.IEnergySource; +import ic2.api.energy.tile.IEnergyTile; +import ic2.api.reactor.IReactorChamber; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTileEntityCable { + + public final float mThickNess; + public final Materials mMaterial; + public final long mCableLossPerMeter, mAmperage, mVoltage; + public final boolean mInsulated, mCanShock; + + public int mTransferredAmperage = 0; + public long mTransferredVoltage = 0; + + @Deprecated + public int mTransferredAmperageLast20 = 0, mTransferredAmperageLast20OK = 0, mTransferredAmperageOK = 0; + @Deprecated + public long mTransferredVoltageLast20 = 0, mTransferredVoltageLast20OK = 0, mTransferredVoltageOK = 0; + + public long mRestRF; + public int mOverheat; + public static short mMaxOverheat = (short) (GT_Mod.gregtechproxy.mWireHeatingTicks * 100); + + private long lastWorldTick; + + public GT_MetaPipeEntity_Cable(int aID, String aName, String aNameRegional, float aThickNess, Materials aMaterial, + long aCableLossPerMeter, long aAmperage, long aVoltage, boolean aInsulated, boolean aCanShock) { + super(aID, aName, aNameRegional, 0); + mThickNess = aThickNess; + mMaterial = aMaterial; + mAmperage = aAmperage; + mVoltage = aVoltage; + mInsulated = aInsulated; + mCanShock = aCanShock; + mCableLossPerMeter = aCableLossPerMeter; + } + + public GT_MetaPipeEntity_Cable(String aName, float aThickNess, Materials aMaterial, long aCableLossPerMeter, + long aAmperage, long aVoltage, boolean aInsulated, boolean aCanShock) { + super(aName, 0); + mThickNess = aThickNess; + mMaterial = aMaterial; + mAmperage = aAmperage; + mVoltage = aVoltage; + mInsulated = aInsulated; + mCanShock = aCanShock; + mCableLossPerMeter = aCableLossPerMeter; + } + + @Override + public byte getTileEntityBaseType() { + return (byte) (mInsulated ? 9 : 8); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaPipeEntity_Cable( + mName, + mThickNess, + mMaterial, + mCableLossPerMeter, + mAmperage, + mVoltage, + mInsulated, + mCanShock); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + int facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (!mInsulated) return new ITexture[] { TextureFactory + .of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], Dyes.getModulation(colorIndex, mMaterial.mRGBa)) }; + if (active) { + float tThickNess = getThickNess(); + if (tThickNess < 0.124F) return new ITexture[] { TextureFactory + .of(Textures.BlockIcons.INSULATION_FULL, Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + if (tThickNess < 0.374F) // 0.375 x1 + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_TINY, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + if (tThickNess < 0.499F) // 0.500 x2 + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_SMALL, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + if (tThickNess < 0.624F) // 0.625 x4 + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_MEDIUM, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + if (tThickNess < 0.749F) // 0.750 x8 + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_MEDIUM_PLUS, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + if (tThickNess < 0.874F) // 0.825 x12 + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_LARGE, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + return new ITexture[] { + TextureFactory.of(mMaterial.mIconSet.mTextures[TextureSet.INDEX_wire], mMaterial.mRGBa), + TextureFactory.of( + Textures.BlockIcons.INSULATION_HUGE, + Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + } + return new ITexture[] { TextureFactory + .of(Textures.BlockIcons.INSULATION_FULL, Dyes.getModulation(colorIndex, Dyes.CABLE_INSULATION.mRGBa)) }; + } + + @Override + public void onEntityCollidedWithBlock(World aWorld, int aX, int aY, int aZ, Entity aEntity) { + + if (!mCanShock) return; + + final BaseMetaPipeEntity baseEntity = (BaseMetaPipeEntity) getBaseMetaTileEntity(); + + if (!(aEntity instanceof EntityLivingBase livingEntity)) return; + if (!(baseEntity.getNodePath() instanceof PowerNodePath powerPath)) return; + + if (isCoverOnSide(baseEntity, livingEntity)) return; + if ((baseEntity.mConnections & IConnectable.HAS_HARDENEDFOAM) == 1) return; + + final long amperage = powerPath.getAmperage(); + final long voltage = powerPath.getVoltage(); + + if (amperage == 0L) return; + + GT_Utility.applyElectricityDamage(livingEntity, voltage, amperage); + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public final boolean renderInside(ForgeDirection side) { + return false; + } + + @Override + public int getProgresstime() { + return (int) mTransferredAmperage * 64; + } + + @Override + public int maxProgresstime() { + return (int) mAmperage * 64; + } + + @Override + public long injectEnergyUnits(ForgeDirection side, long voltage, long amperage) { + if (!isConnectedAtSide(side) && side != ForgeDirection.UNKNOWN) return 0; + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .letsEnergyIn()) return 0; + return transferElectricity(side, voltage, amperage, (HashSet<TileEntity>) null); + } + + @Override + @Deprecated + public long transferElectricity(ForgeDirection side, long aVoltage, long aAmperage, + ArrayList<TileEntity> aAlreadyPassedTileEntityList) { + return transferElectricity(side, aVoltage, aAmperage, new HashSet<>(aAlreadyPassedTileEntityList)); + } + + @Override + public long transferElectricity(ForgeDirection side, long voltage, long amperage, + HashSet<TileEntity> alreadyPassedSet) { + if (!getBaseMetaTileEntity().isServerSide() || !isConnectedAtSide(side) && side != ForgeDirection.UNKNOWN) + return 0; + final BaseMetaPipeEntity tBase = (BaseMetaPipeEntity) getBaseMetaTileEntity(); + if (!(tBase.getNode() instanceof PowerNode tNode)) return 0; + int tPlace = 0; + final Node[] tToPower = new Node[tNode.mConsumers.size()]; + if (tNode.mHadVoltage) { + for (ConsumerNode consumer : tNode.mConsumers) { + if (consumer.needsEnergy()) tToPower[tPlace++] = consumer; + } + } else { + tNode.mHadVoltage = true; + for (ConsumerNode consumer : tNode.mConsumers) { + tToPower[tPlace++] = consumer; + } + } + return PowerNodes.powerNode(tNode, null, new NodeList(tToPower), (int) voltage, (int) amperage); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (aBaseMetaTileEntity.isServerSide()) { + lastWorldTick = aBaseMetaTileEntity.getWorld() + .getTotalWorldTime() - 1; + // sets initial value -1 since it is + // in the same tick as first on post + // tick + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aTick % 20 == 0 && aBaseMetaTileEntity.isServerSide() + && (!GT_Mod.gregtechproxy.gt6Cable || mCheckConnections)) { + checkConnections(); + } + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + if (GT_Mod.gregtechproxy.gt6Cable + && GT_ModHandler.damageOrDechargeItem(aPlayer.inventory.getCurrentItem(), 1, 500, aPlayer)) { + if (isConnectedAtSide(wrenchingSide)) { + disconnect(wrenchingSide); + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("215", "Disconnected")); + } else if (!GT_Mod.gregtechproxy.costlyCableConnection) { + if (connect(wrenchingSide) > 0) + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("214", "Connected")); + } + return true; + } + return false; + } + + @Override + public boolean onSolderingToolRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + if (GT_Mod.gregtechproxy.gt6Cable + && GT_ModHandler.damageOrDechargeItem(aPlayer.inventory.getCurrentItem(), 1, 500, aPlayer)) { + if (isConnectedAtSide(wrenchingSide)) { + disconnect(wrenchingSide); + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("215", "Disconnected")); + } else if (!GT_Mod.gregtechproxy.costlyCableConnection || GT_ModHandler.consumeSolderingMaterial(aPlayer)) { + if (connect(wrenchingSide) > 0) + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("214", "Connected")); + } + return true; + } + return false; + } + + @Override + public boolean letsIn(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsEnergyIn(side, aCoverID, aCoverVariable, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsEnergyOut(side, aCoverID, aCoverVariable, aTileEntity); + } + + @Override + public boolean letsIn(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsEnergyIn(side, aCoverID, aCoverVariable, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsEnergyOut(side, aCoverID, aCoverVariable, aTileEntity); + } + + @Override + public boolean letsIn(CoverInfo coverInfo) { + return coverInfo.letsEnergyIn(); + } + + @Override + public boolean letsOut(CoverInfo coverInfo) { + return coverInfo.letsEnergyOut(); + } + + @Override + public boolean canConnect(ForgeDirection side, TileEntity tileEntity) { + final IGregTechTileEntity baseMetaTile = getBaseMetaTileEntity(); + final GT_CoverBehaviorBase<?> coverBehavior = baseMetaTile.getCoverBehaviorAtSideNew(side); + final ForgeDirection oppositeSide = side.getOpposite(); + + // GT Machine handling + if ((tileEntity instanceof PowerLogicHost powerLogic && powerLogic.getPowerLogic(oppositeSide) != null) + || ((tileEntity instanceof IEnergyConnected energyConnected) + && (energyConnected.inputEnergyFrom(oppositeSide, false) + || energyConnected.outputsEnergyTo(oppositeSide, false)))) + return true; + + // Solar Panel Compat + if (coverBehavior instanceof GT_Cover_SolarPanel) return true; + + // ((tIsGregTechTileEntity && tIsTileEntityCable) && (tAlwaysLookConnected || tLetEnergyIn || tLetEnergyOut) ) + // --> Not needed + if (GalacticraftCore.isModLoaded() && GT_GC_Compat.canConnect(tileEntity, oppositeSide)) return true; + + // AE2-p2p Compat + if (tileEntity instanceof appeng.tile.powersink.IC2 ic2sink + && ic2sink.acceptsEnergyFrom((TileEntity) baseMetaTile, oppositeSide)) return true; + + // IC2 Compat + { + final TileEntity ic2Energy; + + if (tileEntity instanceof IReactorChamber) + ic2Energy = (TileEntity) ((IReactorChamber) tileEntity).getReactor(); + else ic2Energy = (tileEntity == null || tileEntity instanceof IEnergyTile || EnergyNet.instance == null) + ? tileEntity + : EnergyNet.instance + .getTileEntity(tileEntity.getWorldObj(), tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); + + // IC2 Sink Compat + if ((ic2Energy instanceof IEnergySink) + && ((IEnergySink) ic2Energy).acceptsEnergyFrom((TileEntity) baseMetaTile, oppositeSide)) return true; + + // IC2 Source Compat + if (GT_Mod.gregtechproxy.ic2EnergySourceCompat && (ic2Energy instanceof IEnergySource)) { + if (((IEnergySource) ic2Energy).emitsEnergyTo((TileEntity) baseMetaTile, oppositeSide)) { + return true; + } + } + } + // RF Output Compat + if (GregTech_API.mOutputRF && tileEntity instanceof IEnergyReceiver + && ((IEnergyReceiver) tileEntity).canConnectEnergy(oppositeSide)) return true; + + // RF Input Compat + return GregTech_API.mInputRF && (tileEntity instanceof IEnergyEmitter + && ((IEnergyEmitter) tileEntity).emitsEnergyTo((TileEntity) baseMetaTile, oppositeSide)); + } + + @Override + public boolean getGT6StyleConnection() { + // Yes if GT6 Cables are enabled + return GT_Mod.gregtechproxy.gt6Cable; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public String[] getDescription() { + return new String[] { + StatCollector.translateToLocal("GT5U.item.cable.max_voltage") + ": %%%" + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mVoltage) + + " (" + + GT_Utility.getColoredTierNameFromVoltage(mVoltage) + + EnumChatFormatting.GREEN + + ")" + + EnumChatFormatting.GRAY, + StatCollector.translateToLocal("GT5U.item.cable.max_amperage") + ": %%%" + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mAmperage) + + EnumChatFormatting.GRAY, + StatCollector.translateToLocal("GT5U.item.cable.loss") + ": %%%" + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(mCableLossPerMeter) + + EnumChatFormatting.GRAY + + "%%% " + + StatCollector.translateToLocal("GT5U.item.cable.eu_volt") }; + } + + @Override + public float getThickNess() { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x1) != 0) return 0.0625F; + return mThickNess; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + if (GT_Mod.gregtechproxy.gt6Cable) aNBT.setByte("mConnections", mConnections); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + if (GT_Mod.gregtechproxy.gt6Cable) { + mConnections = aNBT.getByte("mConnections"); + } + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + final BaseMetaPipeEntity base = (BaseMetaPipeEntity) getBaseMetaTileEntity(); + final PowerNodePath path = (PowerNodePath) base.getNodePath(); + + if (path == null) + return new String[] { EnumChatFormatting.RED + "Failed to get Power Node info" + EnumChatFormatting.RESET }; + + final long currAmp = path.getAmperage(); + final long currVoltage = path.getVoltage(); + + final double avgAmp = path.getAvgAmperage(); + final double avgVoltage = path.getAvgVoltage(); + + final long maxVoltageOut = (mVoltage - mCableLossPerMeter) * mAmperage; + + return new String[] { + "Heat: " + EnumChatFormatting.RED + + GT_Utility.formatNumbers(mOverheat) + + EnumChatFormatting.RESET + + " / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxOverheat) + + EnumChatFormatting.RESET, + "Amperage: " + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(currAmp) + + EnumChatFormatting.RESET + + " / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mAmperage) + + EnumChatFormatting.RESET + + " A", + "Voltage Out: " + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(currVoltage) + + EnumChatFormatting.RESET + + " / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxVoltageOut) + + EnumChatFormatting.RESET + + " EU/t", + "Avg Amperage (20t): " + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(avgAmp) + + EnumChatFormatting.RESET + + " A", + "Avg Output (20t): " + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(avgVoltage) + + EnumChatFormatting.RESET + + " EU/t" }; + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) + return AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + 1, aY + 1, aZ + 1); + else return getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + } + + private AxisAlignedBB getActualCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + float tSpace = (1f - mThickNess) / 2; + float spaceDown = tSpace; + float spaceUp = 1f - tSpace; + float spaceNorth = tSpace; + float spaceSouth = 1f - tSpace; + float spaceWest = tSpace; + float spaceEast = 1f - tSpace; + + if (getBaseMetaTileEntity().getCoverIDAtSide(DOWN) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(UP) != 0) { + spaceNorth = spaceWest = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(NORTH) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceUp = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(SOUTH) != 0) { + spaceDown = spaceWest = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(WEST) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceUp = spaceSouth = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(EAST) != 0) { + spaceDown = spaceNorth = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + + byte tConn = ((BaseMetaPipeEntity) getBaseMetaTileEntity()).mConnections; + if ((tConn & DOWN.flag) != 0) spaceDown = 0f; + if ((tConn & UP.flag) != 0) spaceUp = 1f; + if ((tConn & NORTH.flag) != 0) spaceNorth = 0f; + if ((tConn & SOUTH.flag) != 0) spaceSouth = 1f; + if ((tConn & WEST.flag) != 0) spaceWest = 0f; + if ((tConn & EAST.flag) != 0) spaceEast = 1f; + + return AxisAlignedBB.getBoundingBox( + aX + spaceWest, + aY + spaceDown, + aZ + spaceNorth, + aX + spaceEast, + aY + spaceUp, + aZ + spaceSouth); + } + + @Override + public void addCollisionBoxesToList(World aWorld, int aX, int aY, int aZ, AxisAlignedBB inputAABB, + List<AxisAlignedBB> outputAABB, Entity collider) { + super.addCollisionBoxesToList(aWorld, aX, aY, aZ, inputAABB, outputAABB, collider); + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) { + final AxisAlignedBB aabb = getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + if (inputAABB.intersectsWith(aabb)) outputAABB.add(aabb); + } + } + + @Override + public boolean shouldJoinIc2Enet() { + if (!GT_Mod.gregtechproxy.ic2EnergySourceCompat) return false; + + if (mConnections != 0) { + final IGregTechTileEntity baseMeta = getBaseMetaTileEntity(); + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (isConnectedAtSide(side)) { + final TileEntity tTileEntity = baseMeta.getTileEntityAtSide(side); + final TileEntity tEmitter = (tTileEntity == null || tTileEntity instanceof IEnergyTile + || EnergyNet.instance == null) + ? tTileEntity + : EnergyNet.instance.getTileEntity( + tTileEntity.getWorldObj(), + tTileEntity.xCoord, + tTileEntity.yCoord, + tTileEntity.zCoord); + + if (tEmitter instanceof IEnergyEmitter) return true; + } + } + } + return false; + } + + @Override + public void reloadLocks() { + final BaseMetaPipeEntity pipe = (BaseMetaPipeEntity) getBaseMetaTileEntity(); + if (pipe.getNode() != null) { + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (isConnectedAtSide(side)) { + final CoverInfo coverInfo = pipe.getCoverInfoAtSide(side); + if (coverInfo.getCoverBehavior() instanceof GT_Cover_None) continue; + if (!letsIn(coverInfo) || !letsOut(coverInfo)) { + pipe.addToLock(pipe, side); + } else { + pipe.removeFromLock(pipe, side); + } + } + } + } else { + boolean dontAllow = false; + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (isConnectedAtSide(side)) { + final CoverInfo coverInfo = pipe.getCoverInfoAtSide(side); + if (coverInfo.getCoverBehavior() instanceof GT_Cover_None) continue; + + if (!letsIn(coverInfo) || !letsOut(coverInfo)) { + dontAllow = true; + } + } + } + if (dontAllow) { + pipe.addToLock(pipe, DOWN); + } else { + pipe.removeFromLock(pipe, DOWN); + } + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + + currenttip.add( + StatCollector.translateToLocal("GT5U.item.cable.max_voltage") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mVoltage) + + " (" + + GT_Utility.getColoredTierNameFromVoltage(mVoltage) + + EnumChatFormatting.GREEN + + ")"); + currenttip.add( + StatCollector.translateToLocal("GT5U.item.cable.max_amperage") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mAmperage)); + currenttip.add( + StatCollector.translateToLocal("GT5U.item.cable.loss") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(mCableLossPerMeter) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.item.cable.eu_volt")); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Fluid.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Fluid.java new file mode 100644 index 0000000000..f604f1583f --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Fluid.java @@ -0,0 +1,991 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.ALL_VALID_SIDES; +import static gregtech.api.enums.GT_Values.D1; +import static gregtech.api.enums.Mods.TinkerConstruct; +import static gregtech.api.enums.Mods.Translocator; +import static gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Fluid.Border.BOTTOM; +import static gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Fluid.Border.LEFT; +import static gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Fluid.Border.RIGHT; +import static gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Fluid.Border.TOP; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; +import static net.minecraftforge.common.util.ForgeDirection.DOWN; +import static net.minecraftforge.common.util.ForgeDirection.EAST; +import static net.minecraftforge.common.util.ForgeDirection.NORTH; +import static net.minecraftforge.common.util.ForgeDirection.SOUTH; +import static net.minecraftforge.common.util.ForgeDirection.UP; +import static net.minecraftforge.common.util.ForgeDirection.WEST; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +import org.apache.commons.lang3.tuple.MutableTriple; + +import cpw.mods.fml.common.Optional; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ConfigCategories; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Materials; +import gregtech.api.enums.Mods; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.enums.ToolModes; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.ICoverable; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_CoverBehavior; +import gregtech.api.util.GT_CoverBehaviorBase; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.ISerializableObject; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; +import gregtech.common.GT_Client; +import gregtech.common.covers.CoverInfo; +import gregtech.common.covers.GT_Cover_Drain; +import gregtech.common.covers.GT_Cover_FluidRegulator; + +public class GT_MetaPipeEntity_Fluid extends MetaPipeEntity { + + protected static final EnumMap<ForgeDirection, EnumMap<Border, ForgeDirection>> FACE_BORDER_MAP = new EnumMap<>( + ForgeDirection.class); + + static { + FACE_BORDER_MAP.put(DOWN, borderMap(NORTH, SOUTH, EAST, WEST)); + FACE_BORDER_MAP.put(UP, borderMap(NORTH, SOUTH, WEST, EAST)); + FACE_BORDER_MAP.put(NORTH, borderMap(UP, DOWN, EAST, WEST)); + FACE_BORDER_MAP.put(SOUTH, borderMap(UP, DOWN, WEST, EAST)); + FACE_BORDER_MAP.put(WEST, borderMap(UP, DOWN, NORTH, SOUTH)); + FACE_BORDER_MAP.put(EAST, borderMap(UP, DOWN, SOUTH, NORTH)); + } + + protected static final Map<Integer, IIconContainer> RESTR_TEXTURE_MAP = new HashMap<>(); + + static { + RESTR_TEXTURE_MAP.put(TOP.mask, Textures.BlockIcons.PIPE_RESTRICTOR_UP); + RESTR_TEXTURE_MAP.put(BOTTOM.mask, Textures.BlockIcons.PIPE_RESTRICTOR_DOWN); + RESTR_TEXTURE_MAP.put(TOP.mask | BOTTOM.mask, Textures.BlockIcons.PIPE_RESTRICTOR_UD); + RESTR_TEXTURE_MAP.put(LEFT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_LEFT); + RESTR_TEXTURE_MAP.put(TOP.mask | LEFT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_UL); + RESTR_TEXTURE_MAP.put(BOTTOM.mask | LEFT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_DL); + RESTR_TEXTURE_MAP.put(TOP.mask | BOTTOM.mask | LEFT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_NR); + RESTR_TEXTURE_MAP.put(RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_RIGHT); + RESTR_TEXTURE_MAP.put(TOP.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_UR); + RESTR_TEXTURE_MAP.put(BOTTOM.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_DR); + RESTR_TEXTURE_MAP.put(TOP.mask | BOTTOM.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_NL); + RESTR_TEXTURE_MAP.put(LEFT.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_LR); + RESTR_TEXTURE_MAP.put(TOP.mask | LEFT.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_ND); + RESTR_TEXTURE_MAP.put(BOTTOM.mask | LEFT.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR_NU); + RESTR_TEXTURE_MAP.put(TOP.mask | BOTTOM.mask | LEFT.mask | RIGHT.mask, Textures.BlockIcons.PIPE_RESTRICTOR); + } + + public final float mThickNess; + public final Materials mMaterial; + public final int mCapacity, mHeatResistance, mPipeAmount; + public final boolean mGasProof; + public final FluidStack[] mFluids; + public byte mLastReceivedFrom = 0, oLastReceivedFrom = 0; + /** + * Bitmask for whether disable fluid input form each side. + */ + public byte mDisableInput = 0; + + public GT_MetaPipeEntity_Fluid(int aID, String aName, String aNameRegional, float aThickNess, Materials aMaterial, + int aCapacity, int aHeatResistance, boolean aGasProof) { + this(aID, aName, aNameRegional, aThickNess, aMaterial, aCapacity, aHeatResistance, aGasProof, 1); + } + + public GT_MetaPipeEntity_Fluid(int aID, String aName, String aNameRegional, float aThickNess, Materials aMaterial, + int aCapacity, int aHeatResistance, boolean aGasProof, int aFluidTypes) { + super(aID, aName, aNameRegional, 0, false); + mThickNess = aThickNess; + mMaterial = aMaterial; + mCapacity = aCapacity; + mGasProof = aGasProof; + mHeatResistance = aHeatResistance; + mPipeAmount = aFluidTypes; + mFluids = new FluidStack[mPipeAmount]; + addInfo(aID); + } + + @Deprecated + public GT_MetaPipeEntity_Fluid(String aName, float aThickNess, Materials aMaterial, int aCapacity, + int aHeatResistance, boolean aGasProof) { + this(aName, aThickNess, aMaterial, aCapacity, aHeatResistance, aGasProof, 1); + } + + public GT_MetaPipeEntity_Fluid(String aName, float aThickNess, Materials aMaterial, int aCapacity, + int aHeatResistance, boolean aGasProof, int aFluidTypes) { + super(aName, 0); + mThickNess = aThickNess; + mMaterial = aMaterial; + mCapacity = aCapacity; + mGasProof = aGasProof; + mHeatResistance = aHeatResistance; + mPipeAmount = aFluidTypes; + mFluids = new FluidStack[mPipeAmount]; + } + + @Override + public byte getTileEntityBaseType() { + return (byte) (mMaterial == null ? 4 : (byte) (4) + Math.max(0, Math.min(3, mMaterial.mToolQuality))); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaPipeEntity_Fluid( + mName, + mThickNess, + mMaterial, + mCapacity, + mHeatResistance, + mGasProof, + mPipeAmount); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, int aConnections, + int colorIndex, boolean aConnected, boolean redstoneLevel) { + if (side == ForgeDirection.UNKNOWN) return Textures.BlockIcons.ERROR_RENDERING; + final float tThickNess = getThickNess(); + if (mDisableInput == 0) + return new ITexture[] { aConnected ? getBaseTexture(tThickNess, mPipeAmount, mMaterial, colorIndex) + : TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(colorIndex, mMaterial.mRGBa)) }; + int borderMask = 0; + for (Border border : Border.values()) { + if (isInputDisabledAtSide(getSideAtBorder(side, border))) borderMask |= border.mask; + } + + return new ITexture[] { aConnected ? getBaseTexture(tThickNess, mPipeAmount, mMaterial, colorIndex) + : TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(colorIndex, mMaterial.mRGBa)), + getRestrictorTexture(borderMask) }; + } + + protected static ITexture getBaseTexture(float aThickNess, int aPipeAmount, Materials aMaterial, int colorIndex) { + if (aPipeAmount >= 9) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeNonuple.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aPipeAmount >= 4) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeQuadruple.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aThickNess < 0.124F) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aThickNess < 0.374F) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeTiny.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aThickNess < 0.499F) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeSmall.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aThickNess < 0.749F) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeMedium.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + if (aThickNess < 0.874F) return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeLarge.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + return TextureFactory.of( + aMaterial.mIconSet.mTextures[OrePrefixes.pipeHuge.mTextureIndex], + Dyes.getModulation(colorIndex, aMaterial.mRGBa)); + } + + @Deprecated + protected static ITexture getRestrictorTexture(byte borderMask) { + return getRestrictorTexture((int) borderMask); + } + + protected static ITexture getRestrictorTexture(int borderMask) { + final IIconContainer restrictorIcon = RESTR_TEXTURE_MAP.get(borderMask); + return restrictorIcon != null ? TextureFactory.of(restrictorIcon) : null; + } + + @Override + public void onValueUpdate(byte aValue) { + mDisableInput = aValue; + } + + @Override + public byte getUpdateData() { + return mDisableInput; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public final boolean renderInside(ForgeDirection side) { + return false; + } + + @Override + public int getProgresstime() { + return getFluidAmount(); + } + + @Override + public int maxProgresstime() { + return getCapacity(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + for (int i = 0; i < mPipeAmount; i++) if (mFluids[i] != null) + aNBT.setTag("mFluid" + (i == 0 ? "" : i), mFluids[i].writeToNBT(new NBTTagCompound())); + aNBT.setByte("mLastReceivedFrom", mLastReceivedFrom); + if (GT_Mod.gregtechproxy.gt6Pipe) { + aNBT.setByte("mConnections", mConnections); + aNBT.setByte("mDisableInput", mDisableInput); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + for (int i = 0; i < mPipeAmount; i++) + mFluids[i] = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid" + (i == 0 ? "" : i))); + mLastReceivedFrom = aNBT.getByte("mLastReceivedFrom"); + if (GT_Mod.gregtechproxy.gt6Pipe) { + mConnections = aNBT.getByte("mConnections"); + mDisableInput = aNBT.getByte("mDisableInput"); + } + } + + @Override + public void onEntityCollidedWithBlock(World aWorld, int aX, int aY, int aZ, Entity aEntity) { + if ((((BaseMetaPipeEntity) getBaseMetaTileEntity()).mConnections & -128) == 0 + && aEntity instanceof EntityLivingBase) { + for (FluidStack tFluid : mFluids) { + if (tFluid != null) { + final int tTemperature = tFluid.getFluid() + .getTemperature(tFluid); + if (tTemperature > 320 + && !isCoverOnSide((BaseMetaPipeEntity) getBaseMetaTileEntity(), (EntityLivingBase) aEntity)) { + GT_Utility.applyHeatDamage((EntityLivingBase) aEntity, (tTemperature - 300) / 50.0F); + break; + } else if (tTemperature < 260 + && !isCoverOnSide((BaseMetaPipeEntity) getBaseMetaTileEntity(), (EntityLivingBase) aEntity)) { + GT_Utility.applyFrostDamage((EntityLivingBase) aEntity, (270 - tTemperature) / 25.0F); + break; + } + } + } + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && aTick % 5 == 0) { + mLastReceivedFrom &= 63; + if (mLastReceivedFrom == 63) { + mLastReceivedFrom = 0; + } + + if (!GT_Mod.gregtechproxy.gt6Pipe || mCheckConnections) checkConnections(); + + final boolean shouldDistribute = (oLastReceivedFrom == mLastReceivedFrom); + for (int i = 0, j = aBaseMetaTileEntity.getRandomNumber(mPipeAmount); i < mPipeAmount; i++) { + final int index = (i + j) % mPipeAmount; + if (mFluids[index] != null && mFluids[index].amount <= 0) mFluids[index] = null; + if (mFluids[index] == null) continue; + + if (checkEnvironment(index, aBaseMetaTileEntity)) return; + + if (shouldDistribute) { + distributeFluid(index, aBaseMetaTileEntity); + mLastReceivedFrom = 0; + } + } + + oLastReceivedFrom = mLastReceivedFrom; + } + } + + private boolean checkEnvironment(int index, IGregTechTileEntity aBaseMetaTileEntity) { + // Check for hot liquids that melt the pipe or gasses that escape and burn/freeze people + final FluidStack tFluid = mFluids[index]; + + if (tFluid != null && tFluid.amount > 0) { + final int tTemperature = tFluid.getFluid() + .getTemperature(tFluid); + if (tTemperature > mHeatResistance) { + if (aBaseMetaTileEntity.getRandomNumber(100) == 0) { + // Poof + GT_Log.exp.println( + "Set Pipe to Fire due to to low heat resistance at " + aBaseMetaTileEntity.getXCoord() + + " | " + + aBaseMetaTileEntity.getYCoord() + + " | " + + aBaseMetaTileEntity.getZCoord() + + " DIMID: " + + aBaseMetaTileEntity.getWorld().provider.dimensionId); + aBaseMetaTileEntity.setToFire(); + return true; + } + // Mmhmm, Fire + aBaseMetaTileEntity.setOnFire(); + GT_Log.exp.println( + "Set Blocks around Pipe to Fire due to to low heat resistance at " + aBaseMetaTileEntity.getXCoord() + + " | " + + aBaseMetaTileEntity.getYCoord() + + " | " + + aBaseMetaTileEntity.getZCoord() + + " DIMID: " + + aBaseMetaTileEntity.getWorld().provider.dimensionId); + } + if (!mGasProof && tFluid.getFluid() + .isGaseous(tFluid)) { + tFluid.amount -= 5; + sendSound((byte) 9); + if (tTemperature > 320) { + try { + for (EntityLivingBase tLiving : getBaseMetaTileEntity().getWorld() + .getEntitiesWithinAABB( + EntityLivingBase.class, + AxisAlignedBB.getBoundingBox( + getBaseMetaTileEntity().getXCoord() - 2, + getBaseMetaTileEntity().getYCoord() - 2, + getBaseMetaTileEntity().getZCoord() - 2, + getBaseMetaTileEntity().getXCoord() + 3, + getBaseMetaTileEntity().getYCoord() + 3, + getBaseMetaTileEntity().getZCoord() + 3))) { + GT_Utility.applyHeatDamage(tLiving, (tTemperature - 300) / 25.0F); + } + } catch (Throwable e) { + if (D1) e.printStackTrace(GT_Log.err); + } + } else if (tTemperature < 260) { + try { + for (EntityLivingBase tLiving : getBaseMetaTileEntity().getWorld() + .getEntitiesWithinAABB( + EntityLivingBase.class, + AxisAlignedBB.getBoundingBox( + getBaseMetaTileEntity().getXCoord() - 2, + getBaseMetaTileEntity().getYCoord() - 2, + getBaseMetaTileEntity().getZCoord() - 2, + getBaseMetaTileEntity().getXCoord() + 3, + getBaseMetaTileEntity().getYCoord() + 3, + getBaseMetaTileEntity().getZCoord() + 3))) { + GT_Utility.applyFrostDamage(tLiving, (270 - tTemperature) / 12.5F); + } + } catch (Throwable e) { + if (D1) e.printStackTrace(GT_Log.err); + } + } + } + if (tFluid.amount <= 0) mFluids[index] = null; + } + return false; + } + + private void distributeFluid(int index, IGregTechTileEntity aBaseMetaTileEntity) { + final FluidStack tFluid = mFluids[index]; + if (tFluid == null) return; + + // Tank, From, Amount to receive + final List<MutableTriple<IFluidHandler, ForgeDirection, Integer>> tTanks = new ArrayList<>(); + final int amount = tFluid.amount; + final byte tOffset = (byte) getBaseMetaTileEntity().getRandomNumber(6); + for (final byte i : ALL_VALID_SIDES) { + // Get a list of tanks accepting fluids, and what side they're on + final ForgeDirection side = ForgeDirection.getOrientation((i + tOffset) % 6); + final ForgeDirection oppositeSide = side.getOpposite(); + final IFluidHandler tTank = aBaseMetaTileEntity.getITankContainerAtSide(side); + final IGregTechTileEntity gTank = tTank instanceof IGregTechTileEntity ? (IGregTechTileEntity) tTank : null; + + if (isConnectedAtSide(side) && tTank != null + && (mLastReceivedFrom & side.flag) == 0 + && getBaseMetaTileEntity().getCoverInfoAtSide(side) + .letsFluidOut(tFluid.getFluid()) + && (gTank == null || gTank.getCoverInfoAtSide(oppositeSide) + .letsFluidIn(tFluid.getFluid()))) { + if (tTank.fill(oppositeSide, tFluid, false) > 0) { + tTanks.add(new MutableTriple<>(tTank, oppositeSide, 0)); + } + tFluid.amount = amount; // Because some mods do actually modify input fluid stack + } + } + + // How much of this fluid is available for distribution? + final double tAmount = Math.max(1, Math.min(mCapacity * 10, tFluid.amount)); + + final FluidStack maxFluid = tFluid.copy(); + maxFluid.amount = Integer.MAX_VALUE; + + double availableCapacity = 0; + // Calculate available capacity for distribution from all tanks + for (final MutableTriple<IFluidHandler, ForgeDirection, Integer> tEntry : tTanks) { + tEntry.right = tEntry.left.fill(tEntry.middle, maxFluid, false); + availableCapacity += tEntry.right; + } + + // Now distribute + for (final MutableTriple<IFluidHandler, ForgeDirection, Integer> tEntry : tTanks) { + // Distribue fluids based on percentage available space at destination + if (availableCapacity > tAmount) + tEntry.right = (int) Math.floor(tEntry.right * tAmount / availableCapacity); + + // If the percent is not enough to give at least 1L, try to give 1L + if (tEntry.right == 0) tEntry.right = (int) Math.min(1, tAmount); + + if (tEntry.right <= 0) continue; + + final int tFilledAmount = tEntry.left + .fill(tEntry.middle, drainFromIndex(tEntry.right, false, index), false); + + if (tFilledAmount > 0) tEntry.left.fill(tEntry.middle, drainFromIndex(tFilledAmount, true, index), true); + + if (mFluids[index] == null || mFluids[index].amount <= 0) return; + } + } + + public void connectPipeOnSide(ForgeDirection side, EntityPlayer entityPlayer) { + if (!isConnectedAtSide(side)) { + if (connect(side) > 0) GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("214", "Connected")); + } else { + disconnect(side); + GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("215", "Disconnected")); + } + } + + public void blockPipeOnSide(ForgeDirection side, EntityPlayer entityPlayer, byte mask) { + if (isInputDisabledAtSide(side)) { + mDisableInput &= ~mask; + GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("212", "Input enabled")); + if (!isConnectedAtSide(side)) connect(side); + } else { + mDisableInput |= mask; + GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("213", "Input disabled")); + } + } + + @Override + public boolean onWrenchRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, + float aX, float aY, float aZ, ItemStack aTool) { + + if (GT_Mod.gregtechproxy.gt6Pipe) { + final int mode = GT_MetaGenerated_Tool.getToolMode(aTool); + IGregTechTileEntity currentPipeBase = getBaseMetaTileEntity(); + GT_MetaPipeEntity_Fluid currentPipe = (GT_MetaPipeEntity_Fluid) currentPipeBase.getMetaTileEntity(); + final ForgeDirection tSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ); + final byte tMask = (byte) (tSide.flag); + + if (mode == ToolModes.REGULAR.get()) { + if (entityPlayer.isSneaking()) { + currentPipe.blockPipeOnSide(tSide, entityPlayer, tMask); + } else currentPipe.connectPipeOnSide(tSide, entityPlayer); + return true; + } + + if (mode == ToolModes.WRENCH_LINE.get()) { + + boolean initialState = entityPlayer.isSneaking() ? currentPipe.isInputDisabledAtSide(tSide) + : currentPipe.isConnectedAtSide(tSide); + + boolean wasActionPerformed = false; + + int limit = GregTech_API.sSpecialFile.get(ConfigCategories.general, "PipeWrenchingChainRange", 64); + for (int connected = 0; connected < limit; connected++) { + + TileEntity nextPipeBaseTile = currentPipeBase.getTileEntityAtSide(tSide); + + // if next tile doesn't exist or if next tile is not GT tile + if (!(nextPipeBaseTile instanceof IGregTechTileEntity nextPipeBase)) { + return wasActionPerformed; + } + + // if next tile is wrong color + if (!currentPipe.connectableColor(nextPipeBaseTile)) { + return wasActionPerformed; + } + + GT_MetaPipeEntity_Fluid nextPipe = nextPipeBase + .getMetaTileEntity() instanceof GT_MetaPipeEntity_Fluid + ? (GT_MetaPipeEntity_Fluid) nextPipeBase.getMetaTileEntity() + : null; + + // if next tile entity is not a pipe + if (nextPipe == null) { + return wasActionPerformed; + } + + // if pipes are same size + if (mPipeAmount != nextPipe.mPipeAmount) { + return wasActionPerformed; + } + + // making sure next pipe has same fluid + for (int i = 0; i < mPipeAmount; i++) { + if (mFluids[i] != null && nextPipe.mFluids[i] != null) { + if (!mFluids[i].isFluidEqual(nextPipe.mFluids[i])) { + return wasActionPerformed; + } + } else if (mFluids[i] != nextPipe.mFluids[i]) { + return wasActionPerformed; + } + } + + boolean currentState = entityPlayer.isSneaking() ? currentPipe.isInputDisabledAtSide(tSide) + : currentPipe.isConnectedAtSide(tSide); + + /* + * Making sure next pipe will have same action applied to it + * e.g. Connecting pipe won`t trigger disconnect if next pipe is already connected + */ + if (currentState != initialState) { + return wasActionPerformed; + } + + if (entityPlayer.isSneaking()) { + currentPipe.blockPipeOnSide(tSide, entityPlayer, tMask); + } else currentPipe.connectPipeOnSide(tSide, entityPlayer); + + wasActionPerformed = true; + + currentPipeBase = (IGregTechTileEntity) nextPipeBase; + currentPipe = nextPipe; + + } + return wasActionPerformed; + } + } + return false; + } + + @Override + public boolean letsIn(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsFluidIn(side, aCoverID, aCoverVariable, null, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsFluidOut(side, aCoverID, aCoverVariable, null, aTileEntity); + } + + @Override + public boolean letsIn(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsFluidIn(side, aCoverID, aCoverVariable, null, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsFluidOut(side, aCoverID, aCoverVariable, null, aTileEntity); + } + + @Override + public boolean letsIn(CoverInfo coverInfo) { + return coverInfo.letsFluidIn(null); + } + + @Override + public boolean letsOut(CoverInfo coverInfo) { + return coverInfo.letsFluidOut(null); + } + + @Override + public boolean canConnect(ForgeDirection side, TileEntity tileEntity) { + if (tileEntity == null) return false; + + final ForgeDirection tSide = side.getOpposite(); + final IGregTechTileEntity baseMetaTile = getBaseMetaTileEntity(); + if (baseMetaTile == null) return false; + + final GT_CoverBehaviorBase<?> coverBehavior = baseMetaTile.getCoverBehaviorAtSideNew(side); + final IGregTechTileEntity gTileEntity = (tileEntity instanceof IGregTechTileEntity) + ? (IGregTechTileEntity) tileEntity + : null; + + if (coverBehavior instanceof GT_Cover_Drain + || (TinkerConstruct.isModLoaded() && isTConstructFaucet(tileEntity))) return true; + + final IFluidHandler fTileEntity = (tileEntity instanceof IFluidHandler) ? (IFluidHandler) tileEntity : null; + + if (fTileEntity != null) { + final FluidTankInfo[] tInfo = fTileEntity.getTankInfo(tSide); + if (tInfo != null) { + return tInfo.length > 0 || (Translocator.isModLoaded() && isTranslocator(tileEntity)) + || gTileEntity != null + && gTileEntity.getCoverBehaviorAtSideNew(tSide) instanceof GT_Cover_FluidRegulator; + } + } + return false; + } + + @Optional.Method(modid = Mods.Names.TINKER_CONSTRUCT) + private boolean isTConstructFaucet(TileEntity tTileEntity) { + // Tinker Construct Faucets return a null tank info, so check the class + return tTileEntity instanceof tconstruct.smeltery.logic.FaucetLogic; + } + + @Optional.Method(modid = Mods.Names.TRANSLOCATOR) + private boolean isTranslocator(TileEntity tTileEntity) { + // Translocators return a TankInfo, but it's of 0 length - so check the class if we see this pattern + return tTileEntity instanceof codechicken.translocator.TileLiquidTranslocator; + } + + @Override + public boolean getGT6StyleConnection() { + // Yes if GT6 pipes are enabled + return GT_Mod.gregtechproxy.gt6Pipe; + } + + @Override + public void doSound(byte aIndex, double aX, double aY, double aZ) { + super.doSound(aIndex, aX, aY, aZ); + if (aIndex == 9) { + GT_Utility.doSoundAtClient(SoundResource.RANDOM_FIZZ, 5, 1.0F, aX, aY, aZ); + + new ParticleEventBuilder().setIdentifier(ParticleFX.CLOUD) + .setWorld(getBaseMetaTileEntity().getWorld()) + .<ParticleEventBuilder>times( + 6, + (x, i) -> x + .setMotion( + ForgeDirection.getOrientation(i).offsetX / 5.0, + ForgeDirection.getOrientation(i).offsetY / 5.0, + ForgeDirection.getOrientation(i).offsetZ / 5.0) + .setPosition( + aX - 0.5 + XSTR_INSTANCE.nextFloat(), + aY - 0.5 + XSTR_INSTANCE.nextFloat(), + aZ - 0.5 + XSTR_INSTANCE.nextFloat()) + .run()); + } + } + + @Override + public final int getCapacity() { + return mCapacity * 20 * mPipeAmount; + } + + @Override + public FluidTankInfo getInfo() { + for (FluidStack tFluid : mFluids) { + if (tFluid != null) return new FluidTankInfo(tFluid, mCapacity * 20); + } + return new FluidTankInfo(null, mCapacity * 20); + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection side) { + if (getCapacity() <= 0 && !getBaseMetaTileEntity().hasSteamEngineUpgrade()) return new FluidTankInfo[] {}; + ArrayList<FluidTankInfo> tList = new ArrayList<>(); + for (FluidStack tFluid : mFluids) tList.add(new FluidTankInfo(tFluid, mCapacity * 20)); + return tList.toArray(new FluidTankInfo[mPipeAmount]); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public final FluidStack getFluid() { + for (FluidStack tFluid : mFluids) { + if (tFluid != null) return tFluid; + } + return null; + } + + @Override + public final int getFluidAmount() { + int rAmount = 0; + for (FluidStack tFluid : mFluids) { + if (tFluid != null) rAmount += tFluid.amount; + } + return rAmount; + } + + @Override + public final int fill_default(ForgeDirection side, FluidStack aFluid, boolean doFill) { + if (aFluid == null || aFluid.getFluid() + .getID() <= 0) return 0; + + int index = -1; + for (int i = 0; i < mPipeAmount; i++) { + if (mFluids[i] != null && mFluids[i].isFluidEqual(aFluid)) { + index = i; + break; + } else if ((mFluids[i] == null || mFluids[i].getFluid() + .getID() <= 0) && index < 0) { + index = i; + } + } + + return fill_default_intoIndex(side, aFluid, doFill, index); + } + + private int fill_default_intoIndex(ForgeDirection side, FluidStack aFluid, boolean doFill, int index) { + if (index < 0 || index >= mPipeAmount) return 0; + if (aFluid == null || aFluid.getFluid() + .getID() <= 0) return 0; + + final int ordinalSide = side.ordinal(); + + if (mFluids[index] == null || mFluids[index].getFluid() + .getID() <= 0) { + if (aFluid.amount * mPipeAmount <= getCapacity()) { + if (doFill) { + mFluids[index] = aFluid.copy(); + mLastReceivedFrom |= (1 << ordinalSide); + } + return aFluid.amount; + } + if (doFill) { + mFluids[index] = aFluid.copy(); + mLastReceivedFrom |= (1 << ordinalSide); + mFluids[index].amount = getCapacity() / mPipeAmount; + } + return getCapacity() / mPipeAmount; + } + + if (!mFluids[index].isFluidEqual(aFluid)) return 0; + + final int space = getCapacity() / mPipeAmount - mFluids[index].amount; + if (aFluid.amount <= space) { + if (doFill) { + mFluids[index].amount += aFluid.amount; + mLastReceivedFrom |= (1 << ordinalSide); + } + return aFluid.amount; + } + if (doFill) { + mFluids[index].amount = getCapacity() / mPipeAmount; + mLastReceivedFrom |= (1 << ordinalSide); + } + return space; + } + + @Override + public final FluidStack drain(int maxDrain, boolean doDrain) { + FluidStack drained; + for (int i = 0; i < mPipeAmount; i++) { + if ((drained = drainFromIndex(maxDrain, doDrain, i)) != null) return drained; + } + return null; + } + + private FluidStack drainFromIndex(int maxDrain, boolean doDrain, int index) { + if (index < 0 || index >= mPipeAmount) return null; + if (mFluids[index] == null) return null; + if (mFluids[index].amount <= 0) { + mFluids[index] = null; + return null; + } + + int used = maxDrain; + if (mFluids[index].amount < used) used = mFluids[index].amount; + + if (doDrain) { + mFluids[index].amount -= used; + } + + final FluidStack drained = mFluids[index].copy(); + drained.amount = used; + + if (mFluids[index].amount <= 0) { + mFluids[index] = null; + } + + return drained; + } + + @Override + public int getTankPressure() { + return getFluidAmount() - (getCapacity() / 2); + } + + @Override + public String[] getDescription() { + List<String> descriptions = new ArrayList<>(); + descriptions.add( + EnumChatFormatting.BLUE + "Fluid Capacity: %%%" + + GT_Utility.formatNumbers(mCapacity * 20L) + + "%%% L/sec" + + EnumChatFormatting.GRAY); + descriptions.add( + EnumChatFormatting.RED + "Heat Limit: %%%" + + GT_Utility.formatNumbers(mHeatResistance) + + "%%% K" + + EnumChatFormatting.GRAY); + if (!mGasProof) { + descriptions.add(EnumChatFormatting.DARK_GREEN + "Cannot handle gas" + EnumChatFormatting.GRAY); + } + if (mPipeAmount != 1) { + descriptions.add(EnumChatFormatting.AQUA + "Pipe Amount: %%%" + mPipeAmount + EnumChatFormatting.GRAY); + } + return descriptions.toArray(new String[0]); + } + + @Override + public float getThickNess() { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x1) != 0) return 0.0625F; + return mThickNess; + } + + @Override + public boolean isLiquidInput(ForgeDirection side) { + return !isInputDisabledAtSide(side); + } + + @Override + public boolean isLiquidOutput(ForgeDirection side) { + return true; + } + + public boolean isInputDisabledAtSide(ForgeDirection side) { + return (mDisableInput & side.flag) != 0; + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) + return AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + 1, aY + 1, aZ + 1); + else return getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + } + + private AxisAlignedBB getActualCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + final float tSpace = (1f - mThickNess) / 2; + float tSide0 = tSpace; + float tSide1 = 1f - tSpace; + float tSide2 = tSpace; + float tSide3 = 1f - tSpace; + float tSide4 = tSpace; + float tSide5 = 1f - tSpace; + + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.DOWN) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.UP) != 0) { + tSide2 = tSide4 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.NORTH) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide1 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.SOUTH) != 0) { + tSide0 = tSide4 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.WEST) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide1 = tSide3 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.EAST) != 0) { + tSide0 = tSide2 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + + final byte tConn = ((BaseMetaPipeEntity) getBaseMetaTileEntity()).mConnections; + if ((tConn & ForgeDirection.DOWN.flag) != 0) tSide0 = 0f; + if ((tConn & ForgeDirection.UP.flag) != 0) tSide1 = 1f; + if ((tConn & ForgeDirection.NORTH.flag) != 0) tSide2 = 0f; + if ((tConn & ForgeDirection.SOUTH.flag) != 0) tSide3 = 1f; + if ((tConn & ForgeDirection.WEST.flag) != 0) tSide4 = 0f; + if ((tConn & ForgeDirection.EAST.flag) != 0) tSide5 = 1f; + + return AxisAlignedBB + .getBoundingBox(aX + tSide4, aY + tSide0, aZ + tSide2, aX + tSide5, aY + tSide1, aZ + tSide3); + } + + @Override + public void addCollisionBoxesToList(World aWorld, int aX, int aY, int aZ, AxisAlignedBB inputAABB, + List<AxisAlignedBB> outputAABB, Entity collider) { + super.addCollisionBoxesToList(aWorld, aX, aY, aZ, inputAABB, outputAABB, collider); + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) { + final AxisAlignedBB aabb = getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + if (inputAABB.intersectsWith(aabb)) outputAABB.add(aabb); + } + } + + @Override + public FluidStack drain(ForgeDirection side, FluidStack aFluid, boolean doDrain) { + if (aFluid == null) return null; + for (int i = 0; i < mFluids.length; ++i) { + final FluidStack f = mFluids[i]; + if (f == null || !f.isFluidEqual(aFluid)) continue; + return drainFromIndex(aFluid.amount, doDrain, i); + } + return null; + } + + private static EnumMap<Border, ForgeDirection> borderMap(ForgeDirection topSide, ForgeDirection bottomSide, + ForgeDirection leftSide, ForgeDirection rightSide) { + final EnumMap<Border, ForgeDirection> sideMap = new EnumMap<>(Border.class); + sideMap.put(TOP, topSide); + sideMap.put(BOTTOM, bottomSide); + sideMap.put(LEFT, leftSide); + sideMap.put(RIGHT, rightSide); + return sideMap; + } + + protected static ForgeDirection getSideAtBorder(ForgeDirection side, Border border) { + return FACE_BORDER_MAP.get(side) + .get(border); + } + + protected enum Border { + + TOP(), + BOTTOM(), + LEFT(), + RIGHT(); + + public final int mask; + + Border() { + mask = 1 << this.ordinal(); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java new file mode 100644 index 0000000000..399c536b9f --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Frame.java @@ -0,0 +1,150 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.recipe.RecipeMaps.assemblerRecipes; +import static gregtech.api.util.GT_RecipeBuilder.SECONDS; +import static gregtech.api.util.GT_RecipeBuilder.TICKS; +import static gregtech.api.util.GT_Utility.calculateRecipeEU; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SubTag; +import gregtech.api.enums.TierEU; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_ModHandler.RecipeBits; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +public class GT_MetaPipeEntity_Frame extends MetaPipeEntity { + + private static final String localizedDescFormat = GT_LanguageManager + .addStringLocalization("gt.blockmachines.gt_frame.desc.format", "Just something you can put covers on."); + public final Materials mMaterial; + + public GT_MetaPipeEntity_Frame(int aID, String aName, String aNameRegional, Materials aMaterial) { + super(aID, aName, aNameRegional, 0); + mMaterial = aMaterial; + + GT_OreDictUnificator.registerOre(OrePrefixes.frameGt, aMaterial, getStackForm(1)); + if (aMaterial.getProcessingMaterialTierEU() < TierEU.IV) { + GT_ModHandler.addCraftingRecipe( + getStackForm(2), + RecipeBits.NOT_REMOVABLE | GT_ModHandler.RecipeBits.BUFFERED, + new Object[] { "SSS", "SwS", "SSS", 'S', OrePrefixes.stick.get(mMaterial) }); + } + + if (!aMaterial.contains(SubTag.NO_RECIPES) + && GT_OreDictUnificator.get(OrePrefixes.stick, aMaterial, 1) != null) { + // Auto generate frame box recipe in an assembler. + GT_Values.RA.stdBuilder() + .itemInputs( + GT_OreDictUnificator.get(OrePrefixes.stick, aMaterial, 4), + GT_Utility.getIntegratedCircuit(4)) + .itemOutputs(getStackForm(1)) + .duration(3 * SECONDS + 4 * TICKS) + .eut(calculateRecipeEU(aMaterial, 7)) + .addTo(assemblerRecipes); + } + } + + public GT_MetaPipeEntity_Frame(String aName, Materials aMaterial) { + super(aName, 0); + mMaterial = aMaterial; + } + + @Override + public byte getTileEntityBaseType() { + return (byte) (mMaterial == null ? 4 : (byte) (4) + Math.max(0, Math.min(3, mMaterial.mToolQuality))); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaPipeEntity_Frame(mName, mMaterial); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, int connections, + int colorIndex, boolean active, boolean redstoneLevel) { + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.frameGt.mTextureIndex], + Dyes.getModulation(colorIndex, mMaterial.mRGBa)) }; + } + + @Override + public String[] getDescription() { + return localizedDescFormat.split("\\R"); + } + + @Override + public final boolean isSimpleMachine() { + return true; + } + + @Override + public final boolean isFacingValid(ForgeDirection facing) { + return false; + } + + @Override + public final boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public final boolean renderInside(ForgeDirection side) { + return true; + } + + @Override + public final float getThickNess() { + return 1.0F; + } + + @Override + public final void saveNBTData(NBTTagCompound aNBT) { + /* Do nothing */ + } + + @Override + public final void loadNBTData(NBTTagCompound aNBT) { + /* Do nothing */ + } + + @Override + public final boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public final boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public int connect(ForgeDirection side) { + return 0; + } + + @Override + public void disconnect(ForgeDirection side) { + /* Do nothing */ + } + + @Override + public boolean isMachineBlockUpdateRecursive() { + return true; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Item.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Item.java new file mode 100644 index 0000000000..660230660e --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Item.java @@ -0,0 +1,530 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.ALL_VALID_SIDES; +import static gregtech.api.enums.Textures.BlockIcons.PIPE_RESTRICTOR; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.GT_Mod; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.metatileentity.IMetaTileEntityItemPipe; +import gregtech.api.interfaces.tileentity.ICoverable; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_CoverBehavior; +import gregtech.api.util.GT_CoverBehaviorBase; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.ISerializableObject; +import gregtech.common.GT_Client; +import gregtech.common.covers.CoverInfo; + +public class GT_MetaPipeEntity_Item extends MetaPipeEntity implements IMetaTileEntityItemPipe { + + public final float mThickNess; + public final Materials mMaterial; + public final int mStepSize; + public final int mTickTime; + public int mTransferredItems = 0; + public long mCurrentTransferStartTick = 0; + public ForgeDirection mLastReceivedFrom = ForgeDirection.UNKNOWN, oLastReceivedFrom = ForgeDirection.UNKNOWN; + public boolean mIsRestrictive = false; + private int[] cacheSides; + + public GT_MetaPipeEntity_Item(int aID, String aName, String aNameRegional, float aThickNess, Materials aMaterial, + int aInvSlotCount, int aStepSize, boolean aIsRestrictive, int aTickTime) { + super(aID, aName, aNameRegional, aInvSlotCount, false); + mIsRestrictive = aIsRestrictive; + mThickNess = aThickNess; + mMaterial = aMaterial; + mStepSize = aStepSize; + mTickTime = aTickTime; + addInfo(aID); + } + + public GT_MetaPipeEntity_Item(int aID, String aName, String aNameRegional, float aThickNess, Materials aMaterial, + int aInvSlotCount, int aStepSize, boolean aIsRestrictive) { + this(aID, aName, aNameRegional, aThickNess, aMaterial, aInvSlotCount, aStepSize, aIsRestrictive, 20); + } + + public GT_MetaPipeEntity_Item(String aName, float aThickNess, Materials aMaterial, int aInvSlotCount, int aStepSize, + boolean aIsRestrictive, int aTickTime) { + super(aName, aInvSlotCount); + mIsRestrictive = aIsRestrictive; + mThickNess = aThickNess; + mMaterial = aMaterial; + mStepSize = aStepSize; + mTickTime = aTickTime; + } + + @Override + public byte getTileEntityBaseType() { + return (byte) (mMaterial == null ? 4 : (byte) (4) + Math.max(0, Math.min(3, mMaterial.mToolQuality))); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaPipeEntity_Item( + mName, + mThickNess, + mMaterial, + mInventory.length, + mStepSize, + mIsRestrictive, + mTickTime); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, int aConnections, + int aColorIndex, boolean aConnected, boolean redstoneLevel) { + if (mIsRestrictive) { + if (aConnected) { + float tThickNess = getThickNess(); + if (tThickNess < 0.124F) return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + if (tThickNess < 0.374F) // 0.375 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeTiny.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + if (tThickNess < 0.499F) // 0.500 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeSmall.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + if (tThickNess < 0.749F) // 0.750 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeMedium.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + if (tThickNess < 0.874F) // 0.825 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeLarge.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeHuge.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + } + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)), TextureFactory.of(PIPE_RESTRICTOR) }; + } + if (aConnected) { + float tThickNess = getThickNess(); + if (tThickNess < 0.124F) return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + if (tThickNess < 0.374F) // 0.375 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeTiny.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + if (tThickNess < 0.499F) // 0.500 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeSmall.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + if (tThickNess < 0.749F) // 0.750 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeMedium.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + if (tThickNess < 0.874F) // 0.825 + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeLarge.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipeHuge.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + } + return new ITexture[] { TextureFactory.of( + mMaterial.mIconSet.mTextures[OrePrefixes.pipe.mTextureIndex], + Dyes.getModulation(aColorIndex, mMaterial.mRGBa)) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return false; + } + + @Override + public boolean isValidSlot(int ignoredSlotIndex) { + return true; + } + + @Override + public final boolean renderInside(ForgeDirection side) { + return false; + } + + @Override + public int getProgresstime() { + return getPipeContent() * 64; + } + + @Override + public int maxProgresstime() { + return getMaxPipeCapacity() * 64; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setByte("mLastReceivedFrom", (byte) mLastReceivedFrom.ordinal()); + if (GT_Mod.gregtechproxy.gt6Pipe) aNBT.setByte("mConnections", mConnections); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + mLastReceivedFrom = ForgeDirection.getOrientation(aNBT.getByte("mLastReceivedFrom")); + if (GT_Mod.gregtechproxy.gt6Pipe) { + mConnections = aNBT.getByte("mConnections"); + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && (aTick - mCurrentTransferStartTick) % 10 == 0) { + if ((aTick - mCurrentTransferStartTick) % mTickTime == 0) { + mTransferredItems = 0; + mCurrentTransferStartTick = 0; + } + + if (!GT_Mod.gregtechproxy.gt6Pipe || mCheckConnections) checkConnections(); + + if (oLastReceivedFrom == mLastReceivedFrom) { + doTickProfilingInThisTick = false; + + final ArrayList<IMetaTileEntityItemPipe> tPipeList = new ArrayList<>(); + + for (boolean temp = true; temp && !isInventoryEmpty() && pipeCapacityCheck();) { + temp = false; + tPipeList.clear(); + for (IMetaTileEntityItemPipe tTileEntity : GT_Utility + .sortMapByValuesAcending( + IMetaTileEntityItemPipe.Util.scanPipes(this, new HashMap<>(), 0, false, false)) + .keySet()) { + if (temp) break; + tPipeList.add(tTileEntity); + while (!temp && !isInventoryEmpty() && tTileEntity.sendItemStack(aBaseMetaTileEntity)) + for (IMetaTileEntityItemPipe tPipe : tPipeList) + if (!tPipe.incrementTransferCounter(1)) temp = true; + } + } + } + + if (isInventoryEmpty()) mLastReceivedFrom = ForgeDirection.UNKNOWN; + oLastReceivedFrom = mLastReceivedFrom; + } + } + + @Override + public boolean onWrenchRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, + float aX, float aY, float aZ) { + if (GT_Mod.gregtechproxy.gt6Pipe) { + final ForgeDirection tSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ); + if (isConnectedAtSide(tSide)) { + disconnect(tSide); + GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("215", "Disconnected")); + } else { + if (connect(tSide) > 0) GT_Utility.sendChatToPlayer(entityPlayer, GT_Utility.trans("214", "Connected")); + } + return true; + } + return false; + } + + @Override + public boolean letsIn(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsItemsIn(side, aCoverID, aCoverVariable, -1, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehavior coverBehavior, ForgeDirection side, int aCoverID, int aCoverVariable, + ICoverable aTileEntity) { + return coverBehavior.letsItemsOut(side, aCoverID, aCoverVariable, -1, aTileEntity); + } + + @Override + public boolean letsIn(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsItemsIn(side, aCoverID, aCoverVariable, -1, aTileEntity); + } + + @Override + public boolean letsOut(GT_CoverBehaviorBase<?> coverBehavior, ForgeDirection side, int aCoverID, + ISerializableObject aCoverVariable, ICoverable aTileEntity) { + return coverBehavior.letsItemsOut(side, aCoverID, aCoverVariable, -1, aTileEntity); + } + + @Override + public boolean letsIn(CoverInfo coverInfo) { + return coverInfo.letsItemsOut(-1); + } + + @Override + public boolean letsOut(CoverInfo coverInfo) { + return coverInfo.letsItemsOut(-1); + } + + @Override + public boolean canConnect(ForgeDirection side, TileEntity tileEntity) { + if (tileEntity == null) return false; + + final ForgeDirection oppositeSide = side.getOpposite(); + boolean connectable = GT_Utility.isConnectableNonInventoryPipe(tileEntity, oppositeSide); + + final IGregTechTileEntity gTileEntity = (tileEntity instanceof IGregTechTileEntity) + ? (IGregTechTileEntity) tileEntity + : null; + if (gTileEntity != null) { + if (gTileEntity.getMetaTileEntity() == null) return false; + if (gTileEntity.getMetaTileEntity() + .connectsToItemPipe(oppositeSide)) return true; + connectable = true; + } + + if (tileEntity instanceof IInventory) { + if (((IInventory) tileEntity).getSizeInventory() <= 0) return false; + connectable = true; + } + if (tileEntity instanceof ISidedInventory) { + final int[] tSlots = ((ISidedInventory) tileEntity).getAccessibleSlotsFromSide(oppositeSide.ordinal()); + if (tSlots == null || tSlots.length == 0) return false; + connectable = true; + } + + return connectable; + } + + @Override + public boolean getGT6StyleConnection() { + // Yes if GT6 pipes are enabled + return GT_Mod.gregtechproxy.gt6Pipe; + } + + @Override + public boolean incrementTransferCounter(int aIncrement) { + if (mTransferredItems == 0) mCurrentTransferStartTick = getBaseMetaTileEntity().getTimer(); + mTransferredItems += aIncrement; + return pipeCapacityCheck(); + } + + @Override + public boolean sendItemStack(Object aSender) { + if (pipeCapacityCheck()) { + final byte tOffset = (byte) getBaseMetaTileEntity().getRandomNumber(6); + for (final byte i : ALL_VALID_SIDES) { + final ForgeDirection tSide = ForgeDirection.getOrientation((i + tOffset) % 6); + if (isConnectedAtSide(tSide) + && (isInventoryEmpty() || (tSide != mLastReceivedFrom || aSender != getBaseMetaTileEntity()))) { + if (insertItemStackIntoTileEntity(aSender, tSide)) return true; + } + } + } + return false; + } + + @Override + public boolean insertItemStackIntoTileEntity(Object aSender, ForgeDirection side) { + if (getBaseMetaTileEntity().getCoverInfoAtSide(side) + .letsItemsOut(-1)) { + final TileEntity tInventory = getBaseMetaTileEntity().getTileEntityAtSide(side); + if (tInventory != null && !(tInventory instanceof BaseMetaPipeEntity)) { + if ((!(tInventory instanceof TileEntityHopper) && !(tInventory instanceof TileEntityDispenser)) + || getBaseMetaTileEntity().getMetaIDAtSide(side) != side.getOpposite() + .ordinal()) { + return GT_Utility.moveMultipleItemStacks( + aSender, + tInventory, + ForgeDirection.UNKNOWN, + side.getOpposite(), + null, + false, + (byte) 64, + (byte) 1, + (byte) 64, + (byte) 1, + 1) > 0; + } + } + } + return false; + } + + @Override + public boolean pipeCapacityCheck() { + return mTransferredItems <= 0 || getPipeContent() < getMaxPipeCapacity(); + } + + private int getPipeContent() { + return mTransferredItems; + } + + private int getMaxPipeCapacity() { + return Math.max(1, getPipeCapacity()); + } + + /** + * Amount of ItemStacks this Pipe can conduct per Second. + */ + public int getPipeCapacity() { + return mInventory.length; + } + + @Override + public int getStepSize() { + return mStepSize; + } + + @Override + public boolean canInsertItem(int aIndex, ItemStack aStack, int ordinalSide) { + return isConnectedAtSide(ForgeDirection.getOrientation(ordinalSide)) + && super.canInsertItem(aIndex, aStack, ordinalSide); + } + + @Override + public boolean canExtractItem(int aIndex, ItemStack aStack, int ordinalSide) { + return isConnectedAtSide(ForgeDirection.getOrientation(ordinalSide)); + } + + @Override + public int[] getAccessibleSlotsFromSide(int ordinalSide) { + final IGregTechTileEntity tTileEntity = getBaseMetaTileEntity(); + final CoverInfo coverInfo = tTileEntity.getCoverInfoAtSide(ForgeDirection.getOrientation(ordinalSide)); + final boolean tAllow = coverInfo.letsItemsIn(-2) || coverInfo.letsItemsOut(-2); + if (tAllow) { + if (cacheSides == null) cacheSides = super.getAccessibleSlotsFromSide(ordinalSide); + return cacheSides; + } else { + return GT_Values.emptyIntArray; + } + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return isConnectedAtSide(side); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (!isConnectedAtSide(side)) return false; + if (isInventoryEmpty()) mLastReceivedFrom = side; + return mLastReceivedFrom == side && mInventory[aIndex] == null; + } + + @Override + public String[] getDescription() { + if (mTickTime == 20) return new String[] { "Item Capacity: %%%" + getMaxPipeCapacity() + "%%% Stacks/sec", + "Routing Value: %%%" + GT_Utility.formatNumbers(mStepSize) }; + else if (mTickTime % 20 == 0) return new String[] { + "Item Capacity: %%%" + getMaxPipeCapacity() + "%%% Stacks/%%%" + (mTickTime / 20) + "%%% sec", + "Routing Value: %%%" + GT_Utility.formatNumbers(mStepSize) }; + else return new String[] { + "Item Capacity: %%%" + getMaxPipeCapacity() + "%%% Stacks/%%%" + mTickTime + "%%% ticks", + "Routing Value: %%%" + GT_Utility.formatNumbers(mStepSize) }; + } + + private boolean isInventoryEmpty() { + for (ItemStack tStack : mInventory) if (tStack != null) return false; + return true; + } + + @Override + public float getThickNess() { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x1) != 0) return 0.0625F; + return mThickNess; + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) + return AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + 1, aY + 1, aZ + 1); + else return getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + } + + private AxisAlignedBB getActualCollisionBoundingBoxFromPool(World ignoredAWorld, int aX, int aY, int aZ) { + final float tSpace = (1f - mThickNess) / 2; + float spaceDown = tSpace; + float spaceUp = 1f - tSpace; + float spaceNorth = tSpace; + float spaceSouth = 1f - tSpace; + float spaceWest = tSpace; + float spaceEast = 1f - tSpace; + + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.DOWN) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.UP) != 0) { + spaceNorth = spaceWest = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.NORTH) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceUp = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.SOUTH) != 0) { + spaceDown = spaceWest = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.WEST) != 0) { + spaceDown = spaceNorth = spaceWest = 0; + spaceUp = spaceSouth = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.EAST) != 0) { + spaceDown = spaceNorth = 0; + spaceUp = spaceSouth = spaceEast = 1; + } + + final byte tConn = ((BaseMetaPipeEntity) getBaseMetaTileEntity()).mConnections; + if ((tConn & ForgeDirection.DOWN.flag) != 0) spaceDown = 0f; + if ((tConn & ForgeDirection.UP.flag) != 0) spaceUp = 1f; + if ((tConn & ForgeDirection.NORTH.flag) != 0) spaceNorth = 0f; + if ((tConn & ForgeDirection.SOUTH.flag) != 0) spaceSouth = 1f; + if ((tConn & ForgeDirection.WEST.flag) != 0) spaceWest = 0f; + if ((tConn & ForgeDirection.EAST.flag) != 0) spaceEast = 1f; + + return AxisAlignedBB.getBoundingBox( + aX + spaceWest, + aY + spaceDown, + aZ + spaceNorth, + aX + spaceEast, + aY + spaceUp, + aZ + spaceSouth); + } + + @Override + public void addCollisionBoxesToList(World aWorld, int aX, int aY, int aZ, AxisAlignedBB inputAABB, + List<AxisAlignedBB> outputAABB, Entity collider) { + super.addCollisionBoxesToList(aWorld, aX, aY, aZ, inputAABB, outputAABB, collider); + if (GT_Mod.instance.isClientSide() && (GT_Client.hideValue & 0x2) != 0) { + final AxisAlignedBB aabb = getActualCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + if (inputAABB.intersectsWith(aabb)) outputAABB.add(aabb); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicBatteryBuffer.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicBatteryBuffer.java new file mode 100644 index 0000000000..ece64e2c1d --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicBatteryBuffer.java @@ -0,0 +1,441 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; + +import java.util.List; + +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.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; + +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_MetaBase_Item; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import ic2.api.item.IElectricItem; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * This is the main construct for my Basic Machines such as the Automatic Extractor Extend this class to make a simple + * Machine + */ +public class GT_MetaTileEntity_BasicBatteryBuffer extends GT_MetaTileEntity_TieredMachineBlock + implements IAddUIWidgets { + + public boolean mCharge = false, mDecharge = false; + public int mBatteryCount = 0, mChargeableCount = 0; + private long count = 0; + private long mStored = 0; + private long mMax = 0; + + public GT_MetaTileEntity_BasicBatteryBuffer(int aID, String aName, String aNameRegional, int aTier, + String aDescription, int aSlotCount) { + super(aID, aName, aNameRegional, aTier, aSlotCount, aDescription); + } + + public GT_MetaTileEntity_BasicBatteryBuffer(String aName, int aTier, String aDescription, ITexture[][][] aTextures, + int aSlotCount) { + super(aName, aTier, aSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicBatteryBuffer(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures, int aSlotCount) { + super(aName, aTier, aSlotCount, aDescription, aTextures); + } + + @Override + public String[] getDescription() { + String[] desc = new String[mDescriptionArray.length + 1]; + System.arraycopy(mDescriptionArray, 0, desc, 0, mDescriptionArray.length); + desc[mDescriptionArray.length] = mInventory.length + " Slots"; + return desc; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[2][17][]; + for (byte i = -1; i < 16; i++) { + rTextures[0][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1] }; + rTextures[1][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + mInventory.length == 16 ? Textures.BlockIcons.OVERLAYS_ENERGY_OUT_POWER[mTier] + : mInventory.length > 4 ? Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] + : Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + } + return rTextures; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return mTextures[side == aFacing ? 1 : 0][colorIndex + 1]; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicBatteryBuffer(mName, mTier, mDescriptionArray, mTextures, mInventory.length); + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isElectric() { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return side != getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return V[mTier] * 16L * mInventory.length; + } + + @Override + public long maxEUStore() { + return V[mTier] * 64L * mInventory.length; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxEUOutput() { + return V[mTier]; + } + + @Override + public long maxAmperesIn() { + return mChargeableCount * 2L; + } + + @Override + public long maxAmperesOut() { + return mBatteryCount; + } + + @Override + public int rechargerSlotStartIndex() { + return 0; + } + + @Override + public int dechargerSlotStartIndex() { + return 0; + } + + @Override + public int rechargerSlotCount() { + return mCharge ? mInventory.length : 0; + } + + @Override + public int dechargerSlotCount() { + return mDecharge ? mInventory.length : 0; + } + + @Override + public int getProgresstime() { + return (int) getBaseMetaTileEntity().getUniversalEnergyStored(); + } + + @Override + public int maxProgresstime() { + return (int) getBaseMetaTileEntity().getUniversalEnergyCapacity(); + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + // + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + // + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + mCharge = aBaseMetaTileEntity.getStoredEU() / 2 > aBaseMetaTileEntity.getEUCapacity() / 3; + mDecharge = aBaseMetaTileEntity.getStoredEU() < aBaseMetaTileEntity.getEUCapacity() / 3; + mBatteryCount = 0; + mChargeableCount = 0; + for (ItemStack tStack : mInventory) if (GT_ModHandler.isElectricItem(tStack, mTier)) { + if (GT_ModHandler.isChargerItem(tStack)) mBatteryCount++; + mChargeableCount++; + } + } + count++; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (GT_ModHandler.isElectricItem(aStack) && aStack.getUnlocalizedName() + .startsWith("gt.metaitem.01.")) { + String name = aStack.getUnlocalizedName(); + if (name.equals("gt.metaitem.01.32510") || name.equals("gt.metaitem.01.32511") + || name.equals("gt.metaitem.01.32520") + || name.equals("gt.metaitem.01.32521") + || name.equals("gt.metaitem.01.32530") + || name.equals("gt.metaitem.01.32531")) { + return ic2.api.item.ElectricItem.manager.getCharge(aStack) == 0; + } + } + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (!GT_Utility.isStackValid(aStack)) { + return false; + } + return mInventory[aIndex] == null && GT_ModHandler.isElectricItem(aStack, this.mTier); + } + + @Override + public int getInventoryStackLimit() { + return 1; + } + + public long[] getStoredEnergy() { + boolean scaleOverflow = false; + boolean storedOverflow = false; + long tScale = getBaseMetaTileEntity().getEUCapacity(); + long tStored = getBaseMetaTileEntity().getStoredEU(); + long tStep = 0; + if (mInventory != null) { + for (ItemStack aStack : mInventory) { + if (GT_ModHandler.isElectricItem(aStack)) { + + if (aStack.getItem() instanceof GT_MetaBase_Item) { + Long[] stats = ((GT_MetaBase_Item) aStack.getItem()).getElectricStats(aStack); + if (stats != null) { + if (stats[0] > Long.MAX_VALUE / 2) { + scaleOverflow = true; + } + tScale = tScale + stats[0]; + tStep = ((GT_MetaBase_Item) aStack.getItem()).getRealCharge(aStack); + if (tStep > Long.MAX_VALUE / 2) { + storedOverflow = true; + } + tStored = tStored + tStep; + } + } else if (aStack.getItem() instanceof IElectricItem) { + tStored = tStored + (long) ic2.api.item.ElectricItem.manager.getCharge(aStack); + tScale = tScale + (long) ((IElectricItem) aStack.getItem()).getMaxCharge(aStack); + } + } + } + } + if (scaleOverflow) { + tScale = Long.MAX_VALUE; + } + if (storedOverflow) { + tStored = Long.MAX_VALUE; + } + return new long[] { tStored, tScale }; + } + + @Override + public String[] getInfoData() { + updateStorageInfo(); + + return new String[] { EnumChatFormatting.BLUE + getLocalName() + EnumChatFormatting.RESET, "Stored Items:", + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(mStored) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMax) + + EnumChatFormatting.RESET + + " EU", + "Average input:", GT_Utility.formatNumbers(getBaseMetaTileEntity().getAverageElectricInput()) + " EU/t", + "Average output:", GT_Utility.formatNumbers(getBaseMetaTileEntity().getAverageElectricOutput()) + " EU/t" }; + } + + private void updateStorageInfo() { + if (mMax == 0 || (count > 20)) { + long[] tmp = getStoredEnergy(); + mStored = tmp[0]; + mMax = tmp[1]; + count = 0; + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.stored", + GT_Utility.formatNumbers(tag.getLong("mStored")), + GT_Utility.formatNumbers(tag.getLong("mMax")))); + long avgIn = tag.getLong("AvgIn"); + long avgOut = tag.getLong("AvgOut"); + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.avg_in_with_amperage", + GT_Utility.formatNumbers(avgIn), + GT_Utility.getAmperageForTier(avgIn, (byte) getInputTier()), + GT_Utility.getColoredTierNameFromTier((byte) getInputTier()))); + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.avg_out_with_amperage", + GT_Utility.formatNumbers(avgOut), + GT_Utility.getAmperageForTier(avgOut, (byte) getOutputTier()), + GT_Utility.getColoredTierNameFromTier((byte) getOutputTier()))); + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + updateStorageInfo(); + super.getWailaNBTData(player, tile, tag, world, x, y, z); + tag.setLong("mStored", mStored); + tag.setLong("mMax", mMax); + tag.setLong("AvgIn", getBaseMetaTileEntity().getAverageElectricInput()); + tag.setLong("AvgOut", getBaseMetaTileEntity().getAverageElectricOutput()); + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + switch (mInventory.length) { + case 4 -> builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 2) + .startFromSlot(0) + .endAtSlot(3) + .slotCreator(index -> new BaseSlot(inventoryHandler, index) { + + @Override + public int getSlotStackLimit() { + return 1; + } + }) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(70, 25)); + case 9 -> builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 3) + .startFromSlot(0) + .endAtSlot(8) + .slotCreator(index -> new BaseSlot(inventoryHandler, index) { + + @Override + public int getSlotStackLimit() { + return 1; + } + }) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(61, 16)); + case 16 -> builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 4) + .startFromSlot(0) + .endAtSlot(15) + .slotCreator(index -> new BaseSlot(inventoryHandler, index) { + + @Override + public int getSlotStackLimit() { + return 1; + } + }) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(52, 7)); + default -> builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 1) + .startFromSlot(0) + .endAtSlot(0) + .slotCreator(index -> new BaseSlot(inventoryHandler, index) { + + @Override + public int getSlotStackLimit() { + return 1; + } + }) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(79, 34)); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java new file mode 100644 index 0000000000..897f9dad6f --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicGenerator.java @@ -0,0 +1,344 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; +import net.minecraftforge.fluids.IFluidHandler; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.RecipeMapWorkable; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.maps.FuelBackend; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.common.GT_Pollution; + +public abstract class GT_MetaTileEntity_BasicGenerator extends GT_MetaTileEntity_BasicTank + implements RecipeMapWorkable { + + public GT_MetaTileEntity_BasicGenerator(int aID, String aName, String aNameRegional, int aTier, String aDescription, + ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicGenerator(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicGenerator(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicGenerator(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[10][17][]; + for (byte i = -1; i < 16; i++) { + rTextures[0][i + 1] = getFront(i); + rTextures[1][i + 1] = getBack(i); + rTextures[2][i + 1] = getBottom(i); + rTextures[3][i + 1] = getTop(i); + rTextures[4][i + 1] = getSides(i); + rTextures[5][i + 1] = getFrontActive(i); + rTextures[6][i + 1] = getBackActive(i); + rTextures[7][i + 1] = getBottomActive(i); + rTextures[8][i + 1] = getTopActive(i); + rTextures[9][i + 1] = getSidesActive(i); + } + return rTextures; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + return mTextures[(active ? 5 : 0) + (side == facingDirection ? 0 + : side == facingDirection.getOpposite() ? 1 + : side == ForgeDirection.DOWN ? 2 : side == ForgeDirection.UP ? 3 : 4)][colorIndex + 1]; + } + + @Override + public String[] getDescription() { + String[] desc = new String[mDescriptionArray.length + 1]; + System.arraycopy(mDescriptionArray, 0, desc, 0, mDescriptionArray.length); + desc[mDescriptionArray.length] = "Fuel Efficiency: " + getEfficiency() + "%"; + return desc; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + public ITexture[] getFront(byte aColor) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][aColor + 1] }; + } + + public ITexture[] getBack(byte aColor) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][aColor + 1] }; + } + + public ITexture[] getBottom(byte aColor) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][aColor + 1] }; + } + + public ITexture[] getTop(byte aColor) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][aColor + 1] }; + } + + public ITexture[] getSides(byte aColor) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][aColor + 1] }; + } + + public ITexture[] getFrontActive(byte aColor) { + return getFront(aColor); + } + + public ITexture[] getBackActive(byte aColor) { + return getBack(aColor); + } + + public ITexture[] getBottomActive(byte aColor) { + return getBottom(aColor); + } + + public ITexture[] getTopActive(byte aColor) { + return getTop(aColor); + } + + public ITexture[] getSidesActive(byte aColor) { + return getSides(aColor); + } + + @Override + public boolean isFacingValid(ForgeDirection side) { + return true; + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex < 2; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public long maxEUOutput() { + return getBaseMetaTileEntity().isAllowedToWork() ? V[mTier] : 0L; + } + + @Override + public long maxEUStore() { + return Math.max(getEUVar(), V[mTier] * 80L + getMinimumStoredEU()); + } + + @Override + public boolean doesFillContainers() { + return getBaseMetaTileEntity().isAllowedToWork(); + // return false; + } + + @Override + public boolean doesEmptyContainers() { + return getBaseMetaTileEntity().isAllowedToWork(); + } + + @Override + public boolean canTankBeFilled() { + return getBaseMetaTileEntity().isAllowedToWork(); + } + + @Override + public boolean canTankBeEmptied() { + return getBaseMetaTileEntity().isAllowedToWork(); + } + + @Override + public boolean displaysItemStack() { + return true; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return getFuelValue(aFluid) > 0; + } + + @Override + public boolean isLiquidOutput(ForgeDirection side) { + // return super.isLiquidOutput(aSide); + return false; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isAllowedToWork() && aTick % 10 == 0) { + if (mFluid != null) { + long tFuelValue = getFuelValue(mFluid), tConsumed = consumedFluidPerOperation(mFluid); + if (tFuelValue > 0 && tConsumed > 0 && mFluid.amount >= tConsumed) { + long tFluidAmountToUse = Math.min( + mFluid.amount / tConsumed, + (maxEUStore() - aBaseMetaTileEntity.getUniversalEnergyStored()) / tFuelValue); + if (tFluidAmountToUse > 0 + && aBaseMetaTileEntity.increaseStoredEnergyUnits(tFluidAmountToUse * tFuelValue, true)) { + // divided by two because this is called every 10 ticks, not 20 + GT_Pollution.addPollution(getBaseMetaTileEntity(), getPollution() / 2); + mFluid.amount -= tFluidAmountToUse * tConsumed; + } + } + } + + if (mInventory[getInputSlot()] != null + && aBaseMetaTileEntity.getUniversalEnergyStored() < (maxEUOutput() * 20 + getMinimumStoredEU()) + && ((GT_Utility.getFluidForFilledItem(mInventory[getInputSlot()], true) != null) + || solidFuelOverride(mInventory[getInputSlot()]))) { + long tFuelValue = getFuelValue(mInventory[getInputSlot()]); + if (tFuelValue <= 0) tFuelValue = getFuelValue(mInventory[getInputSlot()], true); + // System.out.println(" tFuelValue : " + tFuelValue ); + if (tFuelValue > 0) { + ItemStack tEmptyContainer = getEmptyContainer(mInventory[getInputSlot()]); + if (aBaseMetaTileEntity.addStackToSlot(getOutputSlot(), tEmptyContainer)) { + aBaseMetaTileEntity.increaseStoredEnergyUnits(tFuelValue, true); + aBaseMetaTileEntity.decrStackSize(getInputSlot(), 1); + // divided by two because this is called every 10 ticks, not 20 + GT_Pollution.addPollution(getBaseMetaTileEntity(), getPollution() / 2); + } + } + } + } + + if (aBaseMetaTileEntity.isServerSide()) aBaseMetaTileEntity.setActive( + aBaseMetaTileEntity.isAllowedToWork() + && aBaseMetaTileEntity.getUniversalEnergyStored() >= maxEUOutput() + getMinimumStoredEU()); + } + + /** + * @param stack the fuel stack + * @return if the stack is a solid fuel + */ + public boolean solidFuelOverride(ItemStack stack) { + // this could be used for a coal generator for example aswell... + ItemData association = GT_OreDictUnificator.getAssociation(stack); + // if it is a gregtech Item, make sure its not a VOLUMETRIC_FLASK or any type of cell, else do vanilla checks + if (association != null) { + return !OrePrefixes.CELL_TYPES.contains(association.mPrefix) + && !GT_Utility.areStacksEqual(ItemList.VOLUMETRIC_FLASK.get(1L), stack, true); + } else { + return stack != null && // when the stack is null its not a solid + stack.getItem() != null && // when the item in the stack is null its not a solid + !(stack.getItem() instanceof IFluidContainerItem) && // when the item is a fluid container its not a + // solid... + !(stack.getItem() instanceof IFluidHandler) && // when the item is a fluid handler its not a + // solid... + !stack.getItem() + .getUnlocalizedName() + .contains("bucket"); // since we cant really check for + // buckets... + } + } + + public abstract int getPollution(); + + @Override + public abstract RecipeMap<?> getRecipeMap(); + + public abstract int getEfficiency(); + + public int consumedFluidPerOperation(FluidStack aLiquid) { + return 1; + } + + public int getFuelValue(FluidStack aLiquid) { + long value = getFuelValue(aLiquid, true); + return (value > Integer.MAX_VALUE) ? 0 : (int) value; + } + + public long getFuelValue(FluidStack aLiquid, boolean aLong) { + RecipeMap<?> tRecipes = getRecipeMap(); + if (aLiquid == null || !(tRecipes.getBackend() instanceof FuelBackend tFuels)) return 0; + GT_Recipe tFuel = tFuels.findFuel(aLiquid); + if (tFuel == null) return 0; + + return (long) tFuel.mSpecialValue * getEfficiency() * consumedFluidPerOperation(aLiquid) / 100; + } + + public int getFuelValue(ItemStack aStack) { + long value = getFuelValue(aStack, true); + return (value > Integer.MAX_VALUE) ? 0 : (int) value; + } + + public long getFuelValue(ItemStack aStack, boolean aLong) { + if (GT_Utility.isStackInvalid(aStack) || getRecipeMap() == null) return 0; + GT_Recipe tFuel = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); + if (tFuel == null) return 0; + + long liters = 10L; // 1000mb/100 + return (long) tFuel.mSpecialValue * liters * getEfficiency(); + } + + public ItemStack getEmptyContainer(ItemStack aStack) { + if (GT_Utility.isStackInvalid(aStack) || getRecipeMap() == null) return null; + GT_Recipe tFuel = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, Long.MAX_VALUE, null, aStack); + if (tFuel != null) return GT_Utility.copyOrNull(tFuel.getOutput(0)); + return GT_Utility.getContainerItem(aStack, true); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStack(aBaseMetaTileEntity, aIndex, side, aStack) && (getFuelValue(aStack, true) > 0 + || getFuelValue(GT_Utility.getFluidForFilledItem(aStack, true), true) > 0); + } + + @Override + public int getCapacity() { + return 16000; + } + + @Override + public int getTankPressure() { + return -100; + } + + @Override + public boolean useModularUI() { + return true; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull.java new file mode 100644 index 0000000000..e5766eee39 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull.java @@ -0,0 +1,175 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GT_MetaTileEntity_BasicHull extends GT_MetaTileEntity_BasicTank { + + public GT_MetaTileEntity_BasicHull(int aID, String aName, String aNameRegional, int aTier, String aDescription, + ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, 1, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicHull(mName, mTier, mInventory.length, mDescriptionArray, mTextures); + } + + @Override + public boolean isElectric() { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return !isOutputFacing(side); + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public long getMinimumStoredEU() { + return 512; + } + + @Override + public long maxEUStore() { + return 512 + V[mTier] * 50; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxEUOutput() { + return V[mTier]; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return true; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return true; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aConnected, boolean redstoneLevel) { + return mTextures[Math.min(2, side.ordinal()) + (side == aFacing ? 3 : 0)][colorIndex + 1]; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[6][17][]; + for (byte i = -1; i < 16; i++) { + rTextures[0][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1] }; + rTextures[1][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1] }; + rTextures[2][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1] }; + rTextures[3][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + rTextures[4][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + rTextures[5][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + } + return rTextures; + } + + @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 false; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + @Override + public int getCapacity() { + return (mTier + 1) * 1000; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull_NonElectric.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull_NonElectric.java new file mode 100644 index 0000000000..b6584b50ab --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicHull_NonElectric.java @@ -0,0 +1,78 @@ +package gregtech.api.metatileentity.implementations; + +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public abstract class GT_MetaTileEntity_BasicHull_NonElectric extends GT_MetaTileEntity_BasicHull { + + public GT_MetaTileEntity_BasicHull_NonElectric(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_BasicHull_NonElectric(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull_NonElectric(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + return mTextures[Math.min(2, sideDirection.ordinal())][colorIndex + 1]; + } + + @Override + public boolean isElectric() { + return false; + } + + @Override + public boolean isEnetInput() { + return false; + } + + @Override + public boolean isEnetOutput() { + return false; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return false; + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 0; + } + + @Override + public long maxEUStore() { + return 0; + } + + @Override + public long maxEUInput() { + return 0; + } + + @Override + public long maxEUOutput() { + return 0; + } + + @Override + public abstract ITexture[][][] getTextureSet(ITexture[] aTextures); +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java new file mode 100644 index 0000000000..4709c82776 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java @@ -0,0 +1,1568 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.GT_Values.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.GT_RecipeConstants.EXPLODE; +import static gregtech.api.util.GT_RecipeConstants.ON_FIRE; +import static gregtech.api.util.GT_Utility.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.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.SoundResource; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +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.GT_ItemStack; +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.GT_ClientPreference; +import gregtech.api.util.GT_CoverBehaviorBase; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_TooltipDataCache; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Waila; +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!!! + * <p/> + * 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 GT_MetaTileEntity_BasicMachine extends GT_MetaTileEntity_BasicTank 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 GT_Recipe 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 GT_MetaTileEntity_BasicMachine(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 GT_MetaTileEntity_BasicMachine(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 GT_MetaTileEntity_BasicMachine(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 (!GT_Mod.gregtechproxy.mForceFreeFace) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (aBaseMetaTileEntity.getAirAtSide(side)) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + } + GT_Utility.sendChatToPlayer(aPlayer, "No free Side!"); + return true; + } + + @Override + public void initDefaultModes(NBTTagCompound aNBT) { + mMainFacing = ForgeDirection.UNKNOWN; + if (!getBaseMetaTileEntity().getWorld().isRemote) { + final GT_ClientPreference tPreference = GT_Mod.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) GT_Utility.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] = GT_Utility.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] = GT_Utility.copyOrNull(mOutputItems[i]); + if (mOutputItems[i] != null && mOutputItems[i].stackSize > 64) + mOutputItems[i].stackSize = 64; + mOutputItems[i] = GT_OreDictUnificator.get(true, mOutputItems[i]); + } + if (mFluid != null && mFluid.amount <= 0) mFluid = null; + mMaxProgresstime = Math.max(1, mMaxProgresstime); + if (GT_Utility.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(GT_Recipe recipe) { + GT_OverclockCalculator calculator = overclockDescriber.createCalculator( + new GT_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) { + GT_OverclockCalculator calculator = new GT_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(GT_Recipe 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 + && (!GT_Utility.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) GT_Utility.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 + GT_Utility.formatNumbers((mProgresstime / 20)) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + "Stored Energy:", + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(getBaseMetaTileEntity().getStoredEU()) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(getBaseMetaTileEntity().getEUCapacity()) + + EnumChatFormatting.RESET + + " EU", + "Probably uses: " + EnumChatFormatting.RED + + GT_Utility.formatNumbers(mEUt) + + EnumChatFormatting.RESET + + " EU/t at " + + EnumChatFormatting.RED + + GT_Utility.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; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.hatch.disableFilter." + mDisableFilter)); + } else { + mAllowInputFromOutputSide = !mAllowInputFromOutputSide; + GT_Utility.sendChatToPlayer( + aPlayer, + mAllowInputFromOutputSide ? GT_Utility.trans("095", "Input from Output Side allowed") + : GT_Utility.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; + GT_Utility.sendChatToPlayer( + entityPlayer, + StatCollector.translateToLocal("GT5U.hatch.disableMultiStack." + mDisableMultiStack)); + return true; + } + + @Override + public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) { + if (side != mMainFacing) return true; + GT_CoverBehaviorBase<?> tBehavior = GregTech_API.getCoverBehaviorNew(aCoverID.toStack()); + return tBehavior.isGUIClickable( + side, + GT_Utility.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 (GT_Utility.areStacksEqual(GT_OreDictUnificator.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<ItemStack> getConfigurationCircuits() { + return GregTech_API.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 + * <p/> + * I thought about Enum too, but Enum doesn't add support for people adding other return Systems. + * <p/> + * 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(GT_Recipe 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; + GT_Recipe 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 (GT_Mod.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) { + GT_Log.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<String> 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", + GT_Utility.formatNumbers(mEUt), + GT_Utility.getAmperageForTier(mEUt, (byte) getInputTier()), + GT_Utility.getColoredTierNameFromTier((byte) getInputTier()))); + } else if (mEUt < 0) { + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.produce_with_amperage", + GT_Utility.formatNumbers(-mEUt), + GT_Utility.getAmperageForTier(-mEUt, (byte) getOutputTier()), + GT_Utility.getColoredTierNameFromTier((byte) getOutputTier()))); + } + } else { + if (mEUt > 0) { + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.use", + GT_Utility.formatNumbers(mEUt), + GT_Utility.getColoredTierNameFromVoltage(mEUt))); + } else if (mEUt < 0) { + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.produce", + GT_Utility.formatNumbers(-mEUt), + GT_Utility.getColoredTierNameFromVoltage(-mEUt))); + } + } + } + currenttip.add( + GT_Waila.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 boolean useModularUI() { + return getRecipeMap() != null; + } + + @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() ? GT_UITextures.PICTURE_STALLED_STEAM : GT_UITextures.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(GT_UITextures.OVERLAY_BUTTON_AUTOOUTPUT_ITEM) + .setVariableBackground(GT_UITextures.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(GT_UITextures.OVERLAY_BUTTON_AUTOOUTPUT_FLUID) + .setVariableBackground(GT_UITextures.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 (GT_Utility.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<SteamTexture, Pair<Size, Pos2d>> specialTexture : uiProperties.specialTexturesSteam) { + builder.widget( + new DrawableWidget().setDrawable( + specialTexture.getLeft() + .get(getSteamVariant())) + .setSize( + specialTexture.getRight() + .getLeft()) + .setPos( + specialTexture.getRight() + .getRight())); + } + } else { + for (Pair<IDrawable, Pair<Size, Pos2d>> 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<String> getErrorDescriptions() { + final GT_TooltipDataCache.TooltipData tooltip = getErrorTooltip(); + return tooltip != null ? tooltip.text : Collections.emptyList(); + } + + protected List<String> 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; + }; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java new file mode 100644 index 0000000000..5eb648d560 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Bronze.java @@ -0,0 +1,387 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.D1; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZEBRICKS_BOTTOM; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZEBRICKS_SIDE; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZEBRICKS_TOP; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZE_BOTTOM; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZE_SIDE; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_BRONZE_TOP; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import java.util.Arrays; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.SteamVariant; +import gregtech.api.enums.TierEU; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.objects.overclockdescriber.SteamOverclockDescriber; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * 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 GT_MetaTileEntity_BasicMachine_Bronze extends GT_MetaTileEntity_BasicMachine { + + private static final String TT_machineType = "GT5U.MBTT.MachineType"; + private static final int NEEDS_STEAM_VENTING = 64; + public boolean mNeedsSteamVenting = false; + + public GT_MetaTileEntity_BasicMachine_Bronze(int aID, String aName, String aNameRegional, String aDescription, + int aInputSlotCount, int aOutputSlotCount, boolean aHighPressure) { + super(aID, aName, aNameRegional, aHighPressure ? 2 : 1, 0, aDescription, aInputSlotCount, aOutputSlotCount); + } + + public GT_MetaTileEntity_BasicMachine_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures, + int aInputSlotCount, int aOutputSlotCount, boolean aHighPressure) { + super(aName, aHighPressure ? 2 : 1, 0, aDescription, aTextures, aInputSlotCount, aOutputSlotCount); + } + + protected boolean isBricked() { + return false; + } + + @Override + public OverclockDescriber createOverclockDescriber() { + return new SteamOverclockDescriber(SteamVariant.BRONZE, 1, 2); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("mNeedsSteamVenting", mNeedsSteamVenting); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mNeedsSteamVenting = aNBT.getBoolean("mNeedsSteamVenting"); + } + + @Override + public boolean isElectric() { + return false; + } + + @Override + public boolean isEnetInput() { + return false; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return false; + } + + @Override + public long maxEUStore() { + return 0; + } + + @Override + public long maxEUInput() { + return 0; + } + + @Override + public int rechargerSlotCount() { + return 0; + } + + @Override + public int dechargerSlotCount() { + return 0; + } + + @Override + public boolean isSteampowered() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return super.isFacingValid(facing) && facing != mMainFacing; + } + + @Override + public long getMinimumStoredEU() { + return 1000; + } + + @Override + public long maxSteamStore() { + return 16000; + } + + @Override + public boolean isLiquidInput(ForgeDirection side) { + return side != mMainFacing; + } + + @Override + public boolean isLiquidOutput(ForgeDirection side) { + return side != mMainFacing; + } + + @Override + public boolean doesAutoOutput() { + return false; + } + + @Override + public boolean allowToCheckRecipe() { + if (mNeedsSteamVenting + && getBaseMetaTileEntity().getCoverIDAtSide(getBaseMetaTileEntity().getFrontFacing()) == 0 + && !GT_Utility.hasBlockHitBox( + getBaseMetaTileEntity().getWorld(), + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 1), + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 1), + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 1))) { + sendSound((byte) 9); + mNeedsSteamVenting = false; + try { + for (EntityLivingBase tLiving : getBaseMetaTileEntity().getWorld() + .getEntitiesWithinAABB( + EntityLivingBase.class, + AxisAlignedBB.getBoundingBox( + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 1), + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 1), + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 1), + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 1) + 1, + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 1) + 1, + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 1) + 1))) { + GT_Utility.applyHeatDamage(tLiving, getSteamDamage()); + } + } catch (Throwable e) { + if (D1) e.printStackTrace(GT_Log.err); + } + } + return !mNeedsSteamVenting; + } + + @Override + public int checkRecipe() { + GT_Recipe tRecipe = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, TierEU.LV, null, getAllInputs()); + if ((tRecipe != null) && (canOutput(tRecipe.mOutputs)) + && (tRecipe.isRecipeInputEqual(true, null, getAllInputs()))) { + this.mOutputItems[0] = tRecipe.getOutput(0); + calculateCustomOverclock(tRecipe); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + return DID_NOT_FIND_RECIPE; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + // Super already zeroed out setErrorDisplayID, add additional error codes here. + aBaseMetaTileEntity.setErrorDisplayID(aBaseMetaTileEntity.getErrorDisplayID() | (mNeedsSteamVenting ? 64 : 0)); + } + + @Override + public void endProcess() { + if (isSteampowered()) mNeedsSteamVenting = true; + } + + @Override + public void doSound(byte aIndex, double aX, double aY, double aZ) { + super.doSound(aIndex, aX, aY, aZ); + if (aIndex == 9) { + GT_Utility.doSoundAtClient(SoundResource.RANDOM_FIZZ, 5, 1.0F, aX, aY, aZ); + + new ParticleEventBuilder().setIdentifier(ParticleFX.CLOUD) + .setWorld(getBaseMetaTileEntity().getWorld()) + .setMotion( + getBaseMetaTileEntity().getFrontFacing().offsetX / 5.0, + getBaseMetaTileEntity().getFrontFacing().offsetY / 5.0, + getBaseMetaTileEntity().getFrontFacing().offsetZ / 5.0) + .<ParticleEventBuilder>times( + 8, + x -> x + .setPosition( + aX - 0.5 + XSTR_INSTANCE.nextFloat(), + aY - 0.5 + XSTR_INSTANCE.nextFloat(), + aZ - 0.5 + XSTR_INSTANCE.nextFloat()) + .run()); + } + } + + @Override + public boolean isGivingInformation() { + return false; + } + + @Override + public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) { + return GregTech_API.getCoverBehaviorNew(aCoverID.toStack()) + .isSimpleCover() && super.allowCoverOnSide(side, aCoverID); + } + + public float getSteamDamage() { + return 6.0F * mTier; + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_TOP : MACHINE_BRONZE_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_TOP : MACHINE_BRONZE_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_BOTTOM : MACHINE_BRONZE_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_BOTTOM : MACHINE_BRONZE_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_BOTTOM : MACHINE_BRONZE_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getBottomFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_BOTTOM : MACHINE_BRONZE_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTopFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_TOP : MACHINE_BRONZE_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTopFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_TOP : MACHINE_BRONZE_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getSideFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getSideFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_BRONZEBRICKS_SIDE : MACHINE_BRONZE_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public SteamVariant getSteamVariant() { + return SteamVariant.BRONZE; + } + + @Override + public GUITextureSet getGUITextureSet() { + return GUITextureSet.STEAM.apply(getSteamVariant()); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(152, 63)); + } + + @Override + protected FluidSlotWidget createFluidInputSlot(IDrawable[] backgrounds, Pos2d pos) { + return null; + } + + @Override + protected FluidSlotWidget createFluidOutputSlot(IDrawable[] backgrounds, Pos2d pos) { + return null; + } + + @Override + public String[] getDescription() { + String[] description = Arrays.copyOf(mDescriptionArray, mDescriptionArray.length + 1); + description[mDescriptionArray.length] = StatCollector.translateToLocal(TT_machineType) + ": " + + EnumChatFormatting.YELLOW + + StatCollector.translateToLocal(this.getRecipeMap().unlocalizedName) + + EnumChatFormatting.RESET; + return description; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java new file mode 100644 index 0000000000..8bba0fee25 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_GT_Recipe.java @@ -0,0 +1,820 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.GT_Values.W; +import static gregtech.api.enums.GT_Values.ticksBetweenSounds; +import static gregtech.api.enums.Mods.BartWorks; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; +import static net.minecraftforge.common.util.ForgeDirection.UP; + +import java.util.Locale; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.UITexture; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures.BlockIcons.CustomIcon; +import gregtech.api.enums.Tier; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.ExternalMaterials; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; +import ic2.core.Ic2Items; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * This is the main construct for my Basic Machines such as the Automatic Extractor Extend this class to make a simple + * Machine + */ +public class GT_MetaTileEntity_BasicMachine_GT_Recipe extends GT_MetaTileEntity_BasicMachine { + + private final RecipeMap<?> mRecipes; + private final int mTankCapacity; + private final SpecialEffects mSpecialEffect; + private final ResourceLocation mSoundResourceLocation; + private FallbackableUITexture progressBarTexture; + private int recipeCatalystPriority; + + /** + * Registers machine with single-line description, specific tank capacity, and sound specified by ResourceLocation. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + ResourceLocation aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + this( + aID, + aName, + aNameRegional, + aTier, + new String[] { aDescription }, + aRecipes, + aInputSlots, + aOutputSlots, + aTankCapacity, + aSound, + aSpecialEffect, + aOverlays, + aRecipe); + } + + /** + * Registers machine with multi-line descriptions, specific tank capacity, and sound specified by ResourceLocation. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + ResourceLocation aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + super( + aID, + aName, + aNameRegional, + aTier, + aRecipes.getAmperage(), + aDescription, + aInputSlots, + aOutputSlots, + TextureFactory.of( + TextureFactory.of( + new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_SIDE_ACTIVE")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_SIDE_ACTIVE_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory + .of(new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_SIDE")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_SIDE_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of( + new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_FRONT_ACTIVE")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_FRONT_ACTIVE_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory + .of(new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_FRONT")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_FRONT_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of( + new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_TOP_ACTIVE")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_TOP_ACTIVE_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory + .of(new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_TOP")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_TOP_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of( + new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_BOTTOM_ACTIVE")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_BOTTOM_ACTIVE_GLOW"))) + .glow() + .build()), + TextureFactory.of( + TextureFactory + .of(new CustomIcon("basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_BOTTOM")), + TextureFactory.builder() + .addIcon( + (new CustomIcon( + "basicmachines/" + aOverlays.toLowerCase(Locale.ENGLISH) + "/OVERLAY_BOTTOM_GLOW"))) + .glow() + .build())); + this.mTankCapacity = aTankCapacity; + this.mSpecialEffect = aSpecialEffect; + this.mRecipes = aRecipes; + this.mSoundResourceLocation = aSound; + this.progressBarTexture = mRecipes.getFrontend() + .getUIProperties().progressBarTexture; + + // TODO: CHECK + if (aRecipe != null) { + for (int i = 3; i < aRecipe.length; i++) { + if (!(aRecipe[i] instanceof X)) continue; + + // spotless:off + aRecipe[i] = switch ((X) aRecipe[i]) { + case CIRCUIT -> Tier.ELECTRIC[this.mTier].mManagingObject; + case BETTER_CIRCUIT -> Tier.ELECTRIC[this.mTier].mBetterManagingObject; + case HULL -> Tier.ELECTRIC[this.mTier].mHullObject; + case WIRE -> Tier.ELECTRIC[this.mTier].mConductingObject; + case WIRE4 -> Tier.ELECTRIC[this.mTier].mLargerConductingObject; + case STICK_DISTILLATION -> OrePrefixes.stick.get(Materials.Blaze); + + case GLASS -> switch (this.mTier) { + case 0, 1, 2, 3 -> new ItemStack(Blocks.glass, 1, W); + case 4, 5, 6, 7, 8 -> BartWorks.isModLoaded() ? "blockGlass" + VN[aTier] : Ic2Items.reinforcedGlass; + default -> BartWorks.isModLoaded() ? "blockGlass" + VN[8] : Ic2Items.reinforcedGlass; + }; + + case PLATE -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.plate.get(Materials.Steel); + case 2 -> OrePrefixes.plate.get(Materials.Aluminium); + case 3 -> OrePrefixes.plate.get(Materials.StainlessSteel); + case 4 -> OrePrefixes.plate.get(Materials.Titanium); + case 5 -> OrePrefixes.plate.get(Materials.TungstenSteel); + case 6 -> OrePrefixes.plate.get(Materials.HSSG); + case 7 -> OrePrefixes.plate.get(Materials.HSSE); + default -> OrePrefixes.plate.get(Materials.Neutronium); + }; + + case PIPE -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.pipeMedium.get(Materials.Bronze); + case 2 -> OrePrefixes.pipeMedium.get(Materials.Steel); + case 3 -> OrePrefixes.pipeMedium.get(Materials.StainlessSteel); + case 4 -> OrePrefixes.pipeMedium.get(Materials.Titanium); + case 5 -> OrePrefixes.pipeMedium.get(Materials.TungstenSteel); + case 6 -> OrePrefixes.pipeSmall.get(Materials.Ultimate); + case 7 -> OrePrefixes.pipeMedium.get(Materials.Ultimate); + case 8 -> OrePrefixes.pipeLarge.get(Materials.Ultimate); + default -> OrePrefixes.pipeHuge.get(Materials.Ultimate); + }; + + case COIL_HEATING -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.wireGt02.get(Materials.AnyCopper); + case 2 -> OrePrefixes.wireGt02.get(Materials.Cupronickel); + case 3 -> OrePrefixes.wireGt02.get(Materials.Kanthal); + case 4 -> OrePrefixes.wireGt02.get(Materials.Nichrome); + case 5 -> OrePrefixes.wireGt02.get(Materials.TPV); + case 6 -> OrePrefixes.wireGt02.get(Materials.HSSG); + case 7 -> OrePrefixes.wireGt02.get(Materials.Naquadah); + case 8 -> OrePrefixes.wireGt02.get(Materials.NaquadahAlloy); + case 9 -> OrePrefixes.wireGt04.get(Materials.NaquadahAlloy); + default -> OrePrefixes.wireGt08.get(Materials.NaquadahAlloy); + }; + + case COIL_HEATING_DOUBLE -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.wireGt04.get(Materials.AnyCopper); + case 2 -> OrePrefixes.wireGt04.get(Materials.Cupronickel); + case 3 -> OrePrefixes.wireGt04.get(Materials.Kanthal); + case 4 -> OrePrefixes.wireGt04.get(Materials.Nichrome); + case 5 -> OrePrefixes.wireGt04.get(Materials.TPV); + case 6 -> OrePrefixes.wireGt04.get(Materials.HSSG); + case 7 -> OrePrefixes.wireGt04.get(Materials.Naquadah); + case 8 -> OrePrefixes.wireGt04.get(Materials.NaquadahAlloy); + case 9 -> OrePrefixes.wireGt08.get(Materials.NaquadahAlloy); + default -> OrePrefixes.wireGt16.get(Materials.NaquadahAlloy); + }; + + case STICK_MAGNETIC -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.stick.get(Materials.IronMagnetic); + case 2, 3 -> OrePrefixes.stick.get(Materials.SteelMagnetic); + case 4, 5 -> OrePrefixes.stick.get(Materials.NeodymiumMagnetic); + case 6, 7, 8, 9 -> OrePrefixes.stick.get(Materials.SamariumMagnetic); + default -> OrePrefixes.stick.get(Materials.TengamAttuned); + }; + + case STICK_ELECTROMAGNETIC -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.stick.get(Materials.AnyIron); + case 2, 3 -> OrePrefixes.stick.get(Materials.Steel); + case 4 -> OrePrefixes.stick.get(Materials.Neodymium); + default -> OrePrefixes.stick.get(Materials.VanadiumGallium); + }; + + case COIL_ELECTRIC -> switch (this.mTier) { + case 0 -> OrePrefixes.wireGt01.get(Materials.Lead); + case 1 -> OrePrefixes.wireGt02.get(Materials.Tin); + case 2 -> OrePrefixes.wireGt02.get(Materials.AnyCopper); + case 3 -> OrePrefixes.wireGt04.get(Materials.AnyCopper); + case 4 -> OrePrefixes.wireGt08.get(Materials.AnnealedCopper); + case 5 -> OrePrefixes.wireGt16.get(Materials.AnnealedCopper); + case 6 -> OrePrefixes.wireGt04.get(Materials.YttriumBariumCuprate); + case 7 -> OrePrefixes.wireGt08.get(Materials.Iridium); + default -> OrePrefixes.wireGt16.get(Materials.Osmium); + }; + + case ROBOT_ARM -> switch (this.mTier) { + case 0, 1 -> ItemList.Robot_Arm_LV; + case 2 -> ItemList.Robot_Arm_MV; + case 3 -> ItemList.Robot_Arm_HV; + case 4 -> ItemList.Robot_Arm_EV; + case 5 -> ItemList.Robot_Arm_IV; + case 6 -> ItemList.Robot_Arm_LuV; + case 7 -> ItemList.Robot_Arm_ZPM; + case 8 -> ItemList.Robot_Arm_UV; + case 9 -> ItemList.Robot_Arm_UHV; + case 10 -> ItemList.Robot_Arm_UEV; + case 11 -> ItemList.Robot_Arm_UIV; + case 12 -> ItemList.Robot_Arm_UMV; + case 13 -> ItemList.Robot_Arm_UXV; + default -> ItemList.Robot_Arm_MAX; + }; + + case PUMP -> switch (this.mTier) { + case 0, 1 -> ItemList.Electric_Pump_LV; + case 2 -> ItemList.Electric_Pump_MV; + case 3 -> ItemList.Electric_Pump_HV; + case 4 -> ItemList.Electric_Pump_EV; + case 5 -> ItemList.Electric_Pump_IV; + case 6 -> ItemList.Electric_Pump_LuV; + case 7 -> ItemList.Electric_Pump_ZPM; + case 8 -> ItemList.Electric_Pump_UV; + case 9 -> ItemList.Electric_Pump_UHV; + case 10 -> ItemList.Electric_Pump_UEV; + case 11 -> ItemList.Electric_Pump_UIV; + case 12 -> ItemList.Electric_Pump_UMV; + case 13 -> ItemList.Electric_Pump_UXV; + default -> ItemList.Electric_Pump_MAX; + }; + + case MOTOR -> switch (this.mTier) { + case 0, 1 -> ItemList.Electric_Motor_LV; + case 2 -> ItemList.Electric_Motor_MV; + case 3 -> ItemList.Electric_Motor_HV; + case 4 -> ItemList.Electric_Motor_EV; + case 5 -> ItemList.Electric_Motor_IV; + case 6 -> ItemList.Electric_Motor_LuV; + case 7 -> ItemList.Electric_Motor_ZPM; + case 8 -> ItemList.Electric_Motor_UV; + case 9 -> ItemList.Electric_Motor_UHV; + case 10 -> ItemList.Electric_Motor_UEV; + case 11 -> ItemList.Electric_Motor_UIV; + case 12 -> ItemList.Electric_Motor_UMV; + case 13 -> ItemList.Electric_Motor_UXV; + default -> ItemList.Electric_Motor_MAX; + }; + + case PISTON -> switch (this.mTier) { + case 0, 1 -> ItemList.Electric_Piston_LV; + case 2 -> ItemList.Electric_Piston_MV; + case 3 -> ItemList.Electric_Piston_HV; + case 4 -> ItemList.Electric_Piston_EV; + case 5 -> ItemList.Electric_Piston_IV; + case 6 -> ItemList.Electric_Piston_LuV; + case 7 -> ItemList.Electric_Piston_ZPM; + case 8 -> ItemList.Electric_Piston_UV; + case 9 -> ItemList.Electric_Piston_UHV; + case 10 -> ItemList.Electric_Piston_UEV; + case 11 -> ItemList.Electric_Piston_UIV; + case 12 -> ItemList.Electric_Piston_UMV; + case 13 -> ItemList.Electric_Piston_UXV; + default -> ItemList.Electric_Piston_MAX; + }; + + case CONVEYOR -> switch (this.mTier) { + case 0, 1 -> ItemList.Conveyor_Module_LV; + case 2 -> ItemList.Conveyor_Module_MV; + case 3 -> ItemList.Conveyor_Module_HV; + case 4 -> ItemList.Conveyor_Module_EV; + case 5 -> ItemList.Conveyor_Module_IV; + case 6 -> ItemList.Conveyor_Module_LuV; + case 7 -> ItemList.Conveyor_Module_ZPM; + case 8 -> ItemList.Conveyor_Module_UV; + case 9 -> ItemList.Conveyor_Module_UHV; + case 10 -> ItemList.Conveyor_Module_UEV; + case 11 -> ItemList.Conveyor_Module_UIV; + case 12 -> ItemList.Conveyor_Module_UMV; + case 13 -> ItemList.Conveyor_Module_UXV; + default -> ItemList.Conveyor_Module_MAX; + }; + + case EMITTER -> switch (this.mTier) { + case 0, 1 -> ItemList.Emitter_LV; + case 2 -> ItemList.Emitter_MV; + case 3 -> ItemList.Emitter_HV; + case 4 -> ItemList.Emitter_EV; + case 5 -> ItemList.Emitter_IV; + case 6 -> ItemList.Emitter_LuV; + case 7 -> ItemList.Emitter_ZPM; + case 8 -> ItemList.Emitter_UV; + case 9 -> ItemList.Emitter_UHV; + case 10 -> ItemList.Emitter_UEV; + case 11 -> ItemList.Emitter_UIV; + case 12 -> ItemList.Emitter_UMV; + case 13 -> ItemList.Emitter_UXV; + default -> ItemList.Emitter_MAX; + }; + + case SENSOR -> switch (this.mTier) { + case 0, 1 -> ItemList.Sensor_LV; + case 2 -> ItemList.Sensor_MV; + case 3 -> ItemList.Sensor_HV; + case 4 -> ItemList.Sensor_EV; + case 5 -> ItemList.Sensor_IV; + case 6 -> ItemList.Sensor_LuV; + case 7 -> ItemList.Sensor_ZPM; + case 8 -> ItemList.Sensor_UV; + case 9 -> ItemList.Sensor_UHV; + case 10 -> ItemList.Sensor_UEV; + case 11 -> ItemList.Sensor_UIV; + case 12 -> ItemList.Sensor_UMV; + case 13 -> ItemList.Sensor_UXV; + default -> ItemList.Sensor_MAX; + }; + + case FIELD_GENERATOR -> switch (this.mTier) { + case 0, 1 -> ItemList.Field_Generator_LV; + case 2 -> ItemList.Field_Generator_MV; + case 3 -> ItemList.Field_Generator_HV; + case 4 -> ItemList.Field_Generator_EV; + case 5 -> ItemList.Field_Generator_IV; + case 6 -> ItemList.Field_Generator_LuV; + case 7 -> ItemList.Field_Generator_ZPM; + case 8 -> ItemList.Field_Generator_UV; + case 9 -> ItemList.Field_Generator_UHV; + case 10 -> ItemList.Field_Generator_UEV; + case 11 -> ItemList.Field_Generator_UIV; + case 12 -> ItemList.Field_Generator_UMV; + case 13 -> ItemList.Field_Generator_UXV; + default -> ItemList.Field_Generator_MAX; + }; + + case ROTOR -> switch (this.mTier) { + case 0, 1 -> OrePrefixes.rotor.get(Materials.Tin); + case 2 -> OrePrefixes.rotor.get(Materials.Bronze); + case 3 -> OrePrefixes.rotor.get(Materials.Steel); + case 4 -> OrePrefixes.rotor.get(Materials.StainlessSteel); + case 5 -> OrePrefixes.rotor.get(Materials.TungstenSteel); + case 6 -> OrePrefixes.rotor.get(ExternalMaterials.getRhodiumPlatedPalladium()); + case 7 -> OrePrefixes.rotor.get(Materials.Iridium); + default -> OrePrefixes.rotor.get(Materials.Osmium); + }; + + default -> throw new IllegalArgumentException("MISSING TIER MAPPING FOR: " + aRecipe[i] + " AT TIER " + this.mTier); + }; + // spotless:on + } + + if (!GT_ModHandler.addCraftingRecipe( + getStackForm(1), + GT_ModHandler.RecipeBits.DISMANTLEABLE | GT_ModHandler.RecipeBits.BUFFERED + | GT_ModHandler.RecipeBits.NOT_REMOVABLE + | GT_ModHandler.RecipeBits.REVERSIBLE, + aRecipe)) { + throw new IllegalArgumentException("INVALID CRAFTING RECIPE FOR: " + getStackForm(1).getDisplayName()); + } + } + } + + /** + * Registers machine with single-line description, auto-scaled fluid tank, and sound specified by SoundResource. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + this( + aID, + aName, + aNameRegional, + aTier, + aDescription, + aRecipes, + aInputSlots, + aOutputSlots, + usesFluids ? getCapacityForTier(aTier) : 0, + aSound.resourceLocation, + aSpecialEffect, + aOverlays, + aRecipe); + } + + /** + * Registers machine with multi-line descriptions, auto-scaled fluid tank, and sound specified by SoundResource. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, boolean usesFluids, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + this( + aID, + aName, + aNameRegional, + aTier, + aDescription, + aRecipes, + aInputSlots, + aOutputSlots, + usesFluids ? getCapacityForTier(aTier) : 0, + aSound.resourceLocation, + aSpecialEffect, + aOverlays, + aRecipe); + } + + /** + * Registers machine with single-line description, specific tank capacity, and sound specified by SoundResource. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + this( + aID, + aName, + aNameRegional, + aTier, + aDescription, + aRecipes, + aInputSlots, + aOutputSlots, + aTankCapacity, + aSound.resourceLocation, + aSpecialEffect, + aOverlays, + aRecipe); + } + + /** + * Registers machine with multi-line descriptions, specific tank capacity, and sound specified by SoundResource. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription, RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, + SoundResource aSound, SpecialEffects aSpecialEffect, String aOverlays, Object[] aRecipe) { + this( + aID, + aName, + aNameRegional, + aTier, + aDescription, + aRecipes, + aInputSlots, + aOutputSlots, + aTankCapacity, + aSound.resourceLocation, + aSpecialEffect, + aOverlays, + aRecipe); + } + + /** + * For {@link #newMetaEntity}. + */ + public GT_MetaTileEntity_BasicMachine_GT_Recipe(String aName, int aTier, String[] aDescription, + RecipeMap<?> aRecipes, int aInputSlots, int aOutputSlots, int aTankCapacity, int aAmperage, + ITexture[][][] aTextures, ResourceLocation aSound, SpecialEffects aSpecialEffect) { + super(aName, aTier, aAmperage, aDescription, aTextures, aInputSlots, aOutputSlots); + this.mTankCapacity = aTankCapacity; + this.mSpecialEffect = aSpecialEffect; + this.mRecipes = aRecipes; + this.mSoundResourceLocation = aSound; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicMachine_GT_Recipe( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mRecipes, + this.mInputSlotCount, + this.mOutputItems == null ? 0 : this.mOutputItems.length, + this.mTankCapacity, + this.mAmperage, + this.mTextures, + this.mSoundResourceLocation, + this.mSpecialEffect).setProgressBarTexture(this.progressBarTexture) + .setRecipeCatalystPriority(this.recipeCatalystPriority); + } + + public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTexture(FallbackableUITexture progressBarTexture) { + this.progressBarTexture = progressBarTexture; + return this; + } + + public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTextureName(String name, UITexture fallback) { + return setProgressBarTexture(GT_UITextures.fallbackableProgressbar(name, fallback)); + } + + public GT_MetaTileEntity_BasicMachine_GT_Recipe setProgressBarTextureName(String name) { + return setProgressBarTextureName(name, GT_UITextures.PROGRESSBAR_ARROW); + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (!super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack)) return false; + switch (this.mInputSlotCount) { + case 0 -> { + return false; + } + case 1 -> { + if (this.getFillableStack() == null) return this.getRecipeMap() + .containsInput(aStack); + else return this.getRecipeMap() + .findRecipe( + this.getBaseMetaTileEntity(), + this.mLastRecipe, + true, + true, + V[this.mTier], + new FluidStack[] { this.getFillableStack() }, + this.getSpecialSlot(), + appendSelectedCircuit(aStack)) + != null; + } + case 2 -> { + return ((this.getInputAt(0) != null && this.getInputAt(1) != null) + || (this.getInputAt(0) == null && this.getInputAt(1) == null ? this.getRecipeMap() + .containsInput(aStack) + : (this.getRecipeMap() + .containsInput(aStack) + && this.getRecipeMap() + .findRecipe( + this.getBaseMetaTileEntity(), + this.mLastRecipe, + true, + true, + V[this.mTier], + new FluidStack[] { this.getFillableStack() }, + this.getSpecialSlot(), + aIndex == this.getInputSlot() ? appendSelectedCircuit(aStack, this.getInputAt(1)) + : appendSelectedCircuit(this.getInputAt(0), aStack)) + != null))); + } + default -> { + int tID = this.getBaseMetaTileEntity() + .getMetaTileID(); + if (tID >= 211 && tID <= 218 || tID >= 1180 && tID <= 1187 || tID >= 10780 && tID <= 10786) { // assembler + // lv-iv; + // circuit + // asseblers + // lv - + // uv; + // assemblers + // luv-uev + if (GT_Utility.isStackValid(aStack)) for (int oreID : OreDictionary.getOreIDs(aStack)) { + if (OreDictionary.getOreName(oreID) + .startsWith("circuit")) return true; + } + } + return this.getRecipeMap() + .containsInput(aStack); + } + } + } + + @Override + public boolean allowSelectCircuit() { + return true; + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPreTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isClientSide() && aBaseMetaTileEntity.isActive()) { + // noinspection SwitchStatementWithTooFewBranches + switch (this.mSpecialEffect) { + case TOP_SMOKE -> { + if (aBaseMetaTileEntity.getFrontFacing() != UP && aBaseMetaTileEntity.getCoverIDAtSide(UP) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(UP)) { + + new ParticleEventBuilder().setMotion(0.0D, 0.0D, 0.0D) + .setIdentifier(ParticleFX.SMOKE) + .setPosition( + aBaseMetaTileEntity.getXCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F, + aBaseMetaTileEntity.getYCoord() + 0.9F + XSTR_INSTANCE.nextFloat() * 0.2F, + aBaseMetaTileEntity.getZCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F) + .setWorld(aBaseMetaTileEntity.getWorld()) + .run(); + } + } + default -> {} + } + } + } + + /** + * Handles {@link Block#randomDisplayTick} driven Special Effects + * + * @param aBaseMetaTileEntity The entity that will handle the {@see Block#randomDisplayTick} + */ + @SideOnly(Side.CLIENT) + @Override + public void onRandomDisplayTick(IGregTechTileEntity aBaseMetaTileEntity) { + + // noinspection SwitchStatementWithTooFewBranches + switch (this.mSpecialEffect) { + case MAIN_RANDOM_SPARKS -> { + // Random Sparkles at main face + if (aBaseMetaTileEntity.isActive() && XSTR_INSTANCE.nextInt(3) == 0) { + + final ForgeDirection mainFacing = this.mMainFacing; + + if ((mainFacing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 + && aBaseMetaTileEntity.getCoverIDAtSide(mainFacing) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(mainFacing)) { + + final double oX = aBaseMetaTileEntity.getXCoord(); + final double oY = aBaseMetaTileEntity.getYCoord(); + final double oZ = aBaseMetaTileEntity.getZCoord(); + final double offset = 0.02D; + final double horizontal = 0.5D + XSTR_INSTANCE.nextFloat() * 8D / 16D - 4D / 16D; + + final double x, y, z, mX, mZ; + + y = oY + XSTR_INSTANCE.nextFloat() * 10D / 16D + 5D / 16D; + + if (mainFacing == ForgeDirection.WEST) { + x = oX - offset; + mX = -.05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.EAST) { + x = oX + offset; + mX = .05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.NORTH) { + x = oX + horizontal; + mX = 0D; + z = oZ - offset; + mZ = -.05D; + } else // if (frontFacing == ForgeDirection.SOUTH.ordinal()) + { + x = oX + horizontal; + mX = 0D; + z = oZ + offset; + mZ = .05D; + } + + ParticleEventBuilder particleEventBuilder = (new ParticleEventBuilder()).setMotion(mX, 0, mZ) + .setPosition(x, y, z) + .setWorld(getBaseMetaTileEntity().getWorld()); + particleEventBuilder.setIdentifier(ParticleFX.LAVA) + .run(); + } + } + } + default -> {} + } + } + + @Override + public RecipeMap<?> getRecipeMap() { + return this.mRecipes; + } + + @Override + public int getRecipeCatalystPriority() { + return recipeCatalystPriority; + } + + public GT_MetaTileEntity_BasicMachine_GT_Recipe setRecipeCatalystPriority(int recipeCatalystPriority) { + this.recipeCatalystPriority = recipeCatalystPriority; + return this; + } + + @Override + public int getCapacity() { + return this.mTankCapacity; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1 && this.mSoundResourceLocation != null + && GT_Utility.isStringValid(this.mSoundResourceLocation.getResourceDomain()) + && GT_Utility.isStringValid(this.mSoundResourceLocation.getResourcePath())) + GT_Utility.doSoundAtClient(this.mSoundResourceLocation, 100, 1.0F, aX, aY, aZ); + } + + @Override + public void startProcess() { + BaseMetaTileEntity myMetaTileEntity = ((BaseMetaTileEntity) this.getBaseMetaTileEntity()); + // Added to throttle sounds. To reduce lag, this is on the server side so BlockUpdate packets aren't sent. + if (myMetaTileEntity.mTickTimer > (myMetaTileEntity.mLastSoundTick + ticksBetweenSounds)) { + if (this.mSoundResourceLocation != null + && GT_Utility.isStringValid(this.mSoundResourceLocation.getResourceDomain()) + && GT_Utility.isStringValid(this.mSoundResourceLocation.getResourcePath())) + this.sendLoopStart((byte) 1); + // Does not have overflow protection, but they are longs. + myMetaTileEntity.mLastSoundTick = myMetaTileEntity.mTickTimer; + } + } + + @Override + protected BasicUIProperties getUIProperties() { + return super.getUIProperties().toBuilder() + .progressBarTexture(progressBarTexture) + .build(); + } + + public enum X { + PUMP, + WIRE, + WIRE4, + HULL, + PIPE, + GLASS, + PLATE, + MOTOR, + ROTOR, + SENSOR, + PISTON, + CIRCUIT, + EMITTER, + CONVEYOR, + ROBOT_ARM, + COIL_HEATING, + COIL_ELECTRIC, + STICK_MAGNETIC, + STICK_DISTILLATION, + BETTER_CIRCUIT, + FIELD_GENERATOR, + COIL_HEATING_DOUBLE, + STICK_ELECTROMAGNETIC + } + + /** + * Special Effects + */ + public enum SpecialEffects { + + NONE, + TOP_SMOKE, + MAIN_RANDOM_SPARKS; + + static final SpecialEffects[] VALID_SPECIAL_EFFECTS = { NONE, TOP_SMOKE, MAIN_RANDOM_SPARKS }; + + static SpecialEffects fromId(int id) { + return id >= 0 && id < VALID_SPECIAL_EFFECTS.length ? VALID_SPECIAL_EFFECTS[id] : NONE; + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java new file mode 100644 index 0000000000..d6ae385430 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine_Steel.java @@ -0,0 +1,150 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEELBRICKS_BOTTOM; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEELBRICKS_SIDE; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEELBRICKS_TOP; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEEL_BOTTOM; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEEL_SIDE; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_STEEL_TOP; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.SteamVariant; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IGetTitleColor; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.objects.overclockdescriber.SteamOverclockDescriber; +import gregtech.api.render.TextureFactory; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * 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 GT_MetaTileEntity_BasicMachine_Steel extends GT_MetaTileEntity_BasicMachine_Bronze + implements IGetTitleColor { + + public GT_MetaTileEntity_BasicMachine_Steel(int aID, String aName, String aNameRegional, String aDescription, + int aInputSlotCount, int aOutputSlotCount, boolean aHighPressure) { + super(aID, aName, aNameRegional, aDescription, aInputSlotCount, aOutputSlotCount, aHighPressure); + } + + public GT_MetaTileEntity_BasicMachine_Steel(String aName, String[] aDescription, ITexture[][][] aTextures, + int aInputSlotCount, int aOutputSlotCount, boolean aHighPressure) { + super(aName, aDescription, aTextures, aInputSlotCount, aOutputSlotCount, aHighPressure); + } + + @Override + public OverclockDescriber createOverclockDescriber() { + return new SteamOverclockDescriber(SteamVariant.STEEL, 2, 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_TOP : MACHINE_STEEL_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_TOP : MACHINE_STEEL_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_BOTTOM : MACHINE_STEEL_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_BOTTOM : MACHINE_STEEL_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)) }; + } + + @Override + public ITexture[] getBottomFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_BOTTOM : MACHINE_STEEL_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getBottomFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_BOTTOM : MACHINE_STEEL_BOTTOM, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTopFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_TOP : MACHINE_STEEL_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTopFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_TOP : MACHINE_STEEL_TOP, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getSideFacingPipeActive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getSideFacingPipeInactive(byte aColor) { + return new ITexture[] { TextureFactory.of( + isBricked() ? MACHINE_STEELBRICKS_SIDE : MACHINE_STEEL_SIDE, + Dyes.getModulation(aColor, Dyes._NULL.mRGBa)), TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public SteamVariant getSteamVariant() { + return SteamVariant.STEEL; + } + + @Override + public int getTitleColor() { + return COLOR_TITLE_WHITE.get(); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicTank.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicTank.java new file mode 100644 index 0000000000..c810614161 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_BasicTank.java @@ -0,0 +1,348 @@ +package gregtech.api.metatileentity.implementations; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; + +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.fluid.FluidStackTank; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.gui.GT_Container_BasicTank; +import gregtech.api.gui.GT_GUIContainer_BasicTank; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Utility; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p> + * This is the main construct for my generic Tanks. Filling and emptying behavior have to be implemented manually + */ +public abstract class GT_MetaTileEntity_BasicTank extends GT_MetaTileEntity_TieredMachineBlock + implements IAddUIWidgets { + + public FluidStack mFluid; + // Due to class initializing order, getCapacity might not work properly at this time. + // So we pass supplier instead of current value here. + protected final FluidStackTank fluidTank = new FluidStackTank( + () -> mFluid, + fluidStack -> mFluid = fluidStack, + this::getRealCapacity); + + /** + * @param aInvSlotCount should be 3 + */ + public GT_MetaTileEntity_BasicTank(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicTank(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicTank(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicTank(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex != getStackDisplaySlot(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + if (mFluid != null) aNBT.setTag("mFluid", mFluid.writeToNBT(new NBTTagCompound())); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + mFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid")); + } + + public abstract boolean doesFillContainers(); + + public abstract boolean doesEmptyContainers(); + + public abstract boolean canTankBeFilled(); + + public abstract boolean canTankBeEmptied(); + + public abstract boolean displaysItemStack(); + + /** + * @return If fluid amount is shown on FluidDisplayItem + */ + public abstract boolean displaysStackSize(); + + public int getInputSlot() { + return 0; + } + + public int getOutputSlot() { + return 1; + } + + public int getStackDisplaySlot() { + return 2; + } + + public boolean isFluidInputAllowed(FluidStack aFluid) { + return true; + } + + public boolean isFluidChangingAllowed() { + return true; + } + + public FluidStack getFillableStack() { + return mFluid; + } + + public FluidStack setFillableStack(FluidStack aFluid) { + mFluid = aFluid; + return mFluid; + } + + /** + * If you override this and change the field returned, be sure to override {@link #isDrainableStackSeparate()} as + * well! + */ + public FluidStack getDrainableStack() { + return mFluid; + } + + public FluidStack setDrainableStack(FluidStack aFluid) { + mFluid = aFluid; + return mFluid; + } + + public boolean isDrainableStackSeparate() { + return false; + } + + @Deprecated + public FluidStack getDisplayedFluid() { + return getDrainableStack(); + } + + @Deprecated + @Override + public Object getServerGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_Container_BasicTank(aPlayerInventory, aBaseMetaTileEntity); + } + + @Deprecated + @Override + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_GUIContainer_BasicTank(aPlayerInventory, aBaseMetaTileEntity, getLocalName()); + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (isFluidChangingAllowed() && getFillableStack() != null && getFillableStack().amount <= 0) + setFillableStack(null); + + if (doesEmptyContainers()) { + FluidStack tFluid = GT_Utility.getFluidForFilledItem(mInventory[getInputSlot()], true); + if (tFluid != null && isFluidInputAllowed(tFluid)) { + if (getFillableStack() == null) { + if (isFluidInputAllowed(tFluid) && tFluid.amount <= getCapacity()) { + if (aBaseMetaTileEntity.addStackToSlot( + getOutputSlot(), + GT_Utility.getContainerForFilledItem(mInventory[getInputSlot()], true), + 1)) { + setFillableStack(tFluid.copy()); + this.onEmptyingContainerWhenEmpty(); + aBaseMetaTileEntity.decrStackSize(getInputSlot(), 1); + } + } + } else { + if (tFluid.isFluidEqual(getFillableStack()) + && ((long) tFluid.amount + getFillableStack().amount) <= (long) getCapacity()) { + if (aBaseMetaTileEntity.addStackToSlot( + getOutputSlot(), + GT_Utility.getContainerForFilledItem(mInventory[getInputSlot()], true), + 1)) { + getFillableStack().amount += tFluid.amount; + aBaseMetaTileEntity.decrStackSize(getInputSlot(), 1); + } + } + } + } + } + + if (doesFillContainers()) { + ItemStack tOutput = GT_Utility + .fillFluidContainer(getDrainableStack(), mInventory[getInputSlot()], false, true); + if (tOutput != null && aBaseMetaTileEntity.addStackToSlot(getOutputSlot(), tOutput, 1)) { + FluidStack tFluid = GT_Utility.getFluidForFilledItem(tOutput, true); + aBaseMetaTileEntity.decrStackSize(getInputSlot(), 1); + if (tFluid != null) getDrainableStack().amount -= tFluid.amount; + if (getDrainableStack().amount <= 0 && isFluidChangingAllowed()) setDrainableStack(null); + } + } + } + } + + @Override + public FluidStack getFluid() { + return getDrainableStack(); + } + + @Override + public int getFluidAmount() { + return getDrainableStack() != null ? getDrainableStack().amount : 0; + } + + @Override + public int fill(FluidStack aFluid, boolean doFill) { + if (aFluid == null || aFluid.getFluid() + .getID() <= 0 || aFluid.amount <= 0 || !canTankBeFilled() || !isFluidInputAllowed(aFluid)) return 0; + + if (getFillableStack() == null || getFillableStack().getFluid() + .getID() <= 0) { + if (aFluid.amount <= getCapacity()) { + if (doFill) { + setFillableStack(aFluid.copy()); + getBaseMetaTileEntity().markDirty(); + } + return aFluid.amount; + } + if (doFill) { + setFillableStack(aFluid.copy()); + getFillableStack().amount = getCapacity(); + getBaseMetaTileEntity().markDirty(); + } + return getCapacity(); + } + + if (!getFillableStack().isFluidEqual(aFluid)) return 0; + + int space = getCapacity() - getFillableStack().amount; + if (aFluid.amount <= space) { + if (doFill) { + getFillableStack().amount += aFluid.amount; + getBaseMetaTileEntity().markDirty(); + } + return aFluid.amount; + } + if (doFill) getFillableStack().amount = getCapacity(); + return space; + } + + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + if (getDrainableStack() == null || !canTankBeEmptied()) return null; + if (getDrainableStack().amount <= 0 && isFluidChangingAllowed()) { + setDrainableStack(null); + getBaseMetaTileEntity().markDirty(); + return null; + } + + int used = maxDrain; + if (getDrainableStack().amount < used) used = getDrainableStack().amount; + + if (doDrain) { + getDrainableStack().amount -= used; + getBaseMetaTileEntity().markDirty(); + } + + FluidStack drained = getDrainableStack().copy(); + drained.amount = used; + + if (getDrainableStack().amount <= 0 && isFluidChangingAllowed()) { + setDrainableStack(null); + getBaseMetaTileEntity().markDirty(); + } + + return drained; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection side) { + if (getCapacity() <= 0 && !getBaseMetaTileEntity().hasSteamEngineUpgrade()) return new FluidTankInfo[] {}; + if (isDrainableStackSeparate()) { + return new FluidTankInfo[] { new FluidTankInfo(getFillableStack(), getCapacity()), + new FluidTankInfo(getDrainableStack(), getCapacity()) }; + } else { + return new FluidTankInfo[] { new FluidTankInfo(this) }; + } + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return aIndex == getOutputSlot(); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return aIndex == getInputSlot(); + } + + protected void onEmptyingContainerWhenEmpty() { + // Do nothing + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) + .setPos(7, 16) + .setSize(71, 45)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_GAUGE) + .setPos(79, 34) + .setSize(18, 18)) + .widget( + new SlotWidget(inventoryHandler, getInputSlot()) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_IN) + .setPos(79, 16)) + .widget( + new SlotWidget(inventoryHandler, getOutputSlot()).setAccess(true, false) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_OUT) + .setPos(79, 52)) + .widget( + createFluidSlot().setBackground(GT_UITextures.TRANSPARENT) + .setPos(58, 41)) + .widget( + new TextWidget("Liquid Amount").setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(10, 20)) + .widget( + new TextWidget().setStringSupplier(() -> numberFormat.format(mFluid != null ? mFluid.amount : 0)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(10, 30)); + } + + protected FluidSlotWidget createFluidSlot() { + return new FluidSlotWidget(fluidTank); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Buffer.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Buffer.java new file mode 100644 index 0000000000..1fc347da1f --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Buffer.java @@ -0,0 +1,568 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_DOWN; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_DOWN_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_LEFT; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_LEFT_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_RIGHT; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_RIGHT_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_UP; +import static gregtech.api.enums.Textures.BlockIcons.ARROW_UP_GLOW; +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.TOOLTIP_DELAY; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.UITexture; +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.widget.CycleButtonWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; + +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_TooltipDataCache; +import gregtech.api.util.GT_Utility; + +public abstract class GT_MetaTileEntity_Buffer extends GT_MetaTileEntity_TieredMachineBlock implements IAddUIWidgets { + + private static final int OUTPUT_INDEX = 0; + private static final int ARROW_RIGHT_INDEX = 1; + private static final int ARROW_DOWN_INDEX = 2; + private static final int ARROW_LEFT_INDEX = 3; + private static final int ARROW_UP_INDEX = 4; + private static final int FRONT_INDEX = 5; + + private static final String EMIT_ENERGY_TOOLTIP = "GT5U.machines.emit_energy.tooltip"; + private static final String EMIT_REDSTONE_IF_FULL_TOOLTIP = "GT5U.machines.emit_redstone_if_full.tooltip"; + private static final String INVERT_REDSTONE_TOOLTIP = "GT5U.machines.invert_redstone.tooltip"; + private static final String STOCKING_MODE_TOOLTIP = "GT5U.machines.buffer_stocking_mode.tooltip"; + private static final String SORTING_MODE_TOOLTIP = "GT5U.machines.sorting_mode.tooltip"; + private static final int BUTTON_SIZE = 18; + + public int mMaxStackSize = 64; + public static int MAX = 8; + public boolean bOutput = false, bRedstoneIfFull = false, bInvert = false, bStockingMode = false, + bSortStacks = false; + public int mSuccess = 0, mTargetStackSize = 0; + private int uiButtonCount = 0; + + public GT_MetaTileEntity_Buffer(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription); + } + + public GT_MetaTileEntity_Buffer(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription); + } + + public GT_MetaTileEntity_Buffer(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Buffer(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[ForgeDirection.VALID_DIRECTIONS.length][17][]; + ITexture tIcon = getOverlayIcon(); + ITexture tOut = TextureFactory.of(OVERLAY_PIPE_OUT); + ITexture tUp = TextureFactory.of( + TextureFactory.of(ARROW_UP), + TextureFactory.builder() + .addIcon(ARROW_UP_GLOW) + .glow() + .build()); + ITexture tDown = TextureFactory.of( + TextureFactory.of(ARROW_DOWN), + TextureFactory.builder() + .addIcon(ARROW_DOWN_GLOW) + .glow() + .build()); + ITexture tLeft = TextureFactory.of( + TextureFactory.of(ARROW_LEFT), + TextureFactory.builder() + .addIcon(ARROW_LEFT_GLOW) + .glow() + .build()); + ITexture tRight = TextureFactory.of( + TextureFactory.of(ARROW_RIGHT), + TextureFactory.builder() + .addIcon(ARROW_RIGHT_GLOW) + .glow() + .build()); + for (int i = 0; i < rTextures[0].length; i++) { + rTextures[OUTPUT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tOut }; + rTextures[ARROW_RIGHT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tRight, tIcon }; + rTextures[ARROW_DOWN_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tDown, tIcon }; + rTextures[ARROW_LEFT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tLeft, tIcon }; + rTextures[ARROW_UP_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tUp, tIcon }; + rTextures[FRONT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], tIcon }; + } + return rTextures; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + colorIndex = colorIndex + 1; + if (sideDirection == facingDirection) return mTextures[FRONT_INDEX][colorIndex]; + if (sideDirection.getOpposite() == facingDirection) return mTextures[OUTPUT_INDEX][colorIndex]; + switch (facingDirection) { + case DOWN -> { + return mTextures[ARROW_UP_INDEX][colorIndex]; // ARROW_UP + } + case UP -> { + return mTextures[ARROW_DOWN_INDEX][colorIndex]; // ARROW_DOWN + } + case NORTH -> { + switch (sideDirection) { + case DOWN, UP -> { + return mTextures[ARROW_DOWN_INDEX][colorIndex]; // ARROW_DOWN + } + case WEST -> { + return mTextures[ARROW_RIGHT_INDEX][colorIndex]; // ARROW_RIGHT + } + case EAST -> { + return mTextures[ARROW_LEFT_INDEX][colorIndex]; // ARROW_LEFT + } + default -> {} + } + } + case SOUTH -> { + switch (sideDirection) { + case DOWN, UP -> { + return mTextures[ARROW_UP_INDEX][colorIndex]; // ARROW_UP + } + case WEST -> { + return mTextures[ARROW_LEFT_INDEX][colorIndex]; // ARROW_LEFT + } + case EAST -> { + return mTextures[ARROW_RIGHT_INDEX][colorIndex]; // ARROW_RIGHT + } + default -> {} + } + } + case WEST -> { + switch (sideDirection) { + case UP, SOUTH -> { + return mTextures[ARROW_RIGHT_INDEX][colorIndex]; // ARROW_RIGHT + } + case DOWN, NORTH -> { + return mTextures[ARROW_LEFT_INDEX][colorIndex]; // ARROW_LEFT + } + default -> {} + } + } + case EAST -> { + switch (sideDirection) { + case UP, SOUTH -> { + return mTextures[ARROW_LEFT_INDEX][colorIndex]; // ARROW_LEFT + } + case DOWN, NORTH -> { + return mTextures[ARROW_RIGHT_INDEX][colorIndex]; // ARROW_RIGHT + } + default -> {} + } + } + default -> {} + } + return mTextures[FRONT_INDEX][colorIndex]; + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex < mInventory.length - 1; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return !isOutputFacing(side); + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return getBaseMetaTileEntity().getBackFacing() == side; + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 512L; + } + + @Override + public long maxEUStore() { + return 512L + V[mTier] * 50L; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxEUOutput() { + // Return full value if we're an item and don't exist in the world for tooltip purposes + return getBaseMetaTileEntity().getWorld() == null || bOutput ? V[mTier] : 0L; + } + + @Override + public long maxAmperesIn() { + return 2; + } + + @Override + public long maxAmperesOut() { + return 2; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + public abstract ITexture getOverlayIcon(); + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setBoolean("bInvert", bInvert); + aNBT.setBoolean("bOutput", bOutput); + aNBT.setBoolean("bRedstoneIfFull", bRedstoneIfFull); + aNBT.setBoolean("bStockingMode", bStockingMode); + aNBT.setInteger("mTargetStackSize", mTargetStackSize); + aNBT.setBoolean("bSortStacks", bSortStacks); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + bInvert = aNBT.getBoolean("bInvert"); + bOutput = aNBT.getBoolean("bOutput"); + bRedstoneIfFull = aNBT.getBoolean("bRedstoneIfFull"); + bSortStacks = aNBT.getBoolean("bSortStacks"); + bStockingMode = aNBT.getBoolean("bStockingMode"); + mTargetStackSize = aNBT.getInteger("mTargetStackSize"); + } + + @Override + public void setItemNBT(NBTTagCompound aNBT) { + super.setItemNBT(aNBT); + if (mTargetStackSize > 0) aNBT.setInteger("mTargetStackSize", mTargetStackSize); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (side == getBaseMetaTileEntity().getBackFacing()) { + + mTargetStackSize = (byte) ((mTargetStackSize + (aPlayer.isSneaking() ? -1 : 1)) % 65); + if (mTargetStackSize < 0) { + mTargetStackSize = mMaxStackSize; + } + if (mTargetStackSize == 0) { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("098", "Do not regulate Item Stack Size")); + } else { + GT_Utility.sendChatToPlayer( + aPlayer, + GT_Utility.trans("099", "Regulate Item Stack Size to: ") + mTargetStackSize); + } + } + } + + @Override + public boolean onWrenchRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, + float aX, float aY, float aZ) { + wrenchingSide = wrenchingSide.getOpposite(); + if (getBaseMetaTileEntity().isValidFacing(wrenchingSide)) { + getBaseMetaTileEntity().setFrontFacing(wrenchingSide); + return true; + } + return false; + } + + protected void handleRedstoneOutput(IGregTechTileEntity aBaseMetaTileEntity) { + int redstoneOutput = getRedstoneOutput(); + Arrays.stream(ForgeDirection.VALID_DIRECTIONS) + .forEach(side -> aBaseMetaTileEntity.setInternalOutputRedstoneSignal(side, (byte) redstoneOutput)); + } + + protected int getRedstoneOutput() { + return (!bRedstoneIfFull || (bInvert ^ hasEmptySlots())) ? 0 : 15; + } + + private boolean hasEmptySlots() { + return IntStream.range(0, mInventory.length) + .anyMatch(i -> isValidSlot(i) && mInventory[i] == null); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + if (aBaseMetaTileEntity.isAllowedToWork() && aBaseMetaTileEntity.isServerSide() + && (aBaseMetaTileEntity.hasWorkJustBeenEnabled() || aBaseMetaTileEntity.hasInventoryBeenModified() + || aTimer % 200 == 0 + || mSuccess > 0)) { + mSuccess--; + updateSlots(); + moveItems(aBaseMetaTileEntity, aTimer); + handleRedstoneOutput(aBaseMetaTileEntity); + } + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) + aBaseMetaTileEntity.setInternalOutputRedstoneSignal(side, (byte) 0); + } + + protected void moveItems(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + moveItems(aBaseMetaTileEntity, aTimer, 1); + } + + protected void moveItems(IGregTechTileEntity aBaseMetaTileEntity, long ignoredTimer, int stacks) { + int tCost; + if (bStockingMode) tCost = GT_Utility.moveMultipleItemStacks( + aBaseMetaTileEntity, + aBaseMetaTileEntity.getTileEntityAtSide(aBaseMetaTileEntity.getBackFacing()), + aBaseMetaTileEntity.getBackFacing(), + aBaseMetaTileEntity.getFrontFacing(), + null, + false, + mTargetStackSize == 0 ? 64 : (byte) mTargetStackSize, + mTargetStackSize == 0 ? 1 : (byte) mTargetStackSize, + (byte) 64, + (byte) 1, + stacks); + else tCost = GT_Utility.moveMultipleItemStacks( + aBaseMetaTileEntity, + aBaseMetaTileEntity.getTileEntityAtSide(aBaseMetaTileEntity.getBackFacing()), + aBaseMetaTileEntity.getBackFacing(), + aBaseMetaTileEntity.getFrontFacing(), + null, + false, + (byte) 64, + (byte) 1, + mTargetStackSize == 0 ? 64 : (byte) mTargetStackSize, + mTargetStackSize == 0 ? 1 : (byte) mTargetStackSize, + stacks); + + if (tCost > 0 || aBaseMetaTileEntity.hasInventoryBeenModified()) { + mSuccess = 50; + } + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return true; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side != aBaseMetaTileEntity.getBackFacing(); + } + + @Override + public boolean allowGeneralRedstoneOutput() { + return true; + } + + public void updateSlots() { + for (int i = 0; i < mInventory.length; i++) + if (mInventory[i] != null && mInventory[i].stackSize <= 0) mInventory[i] = null; + if (bSortStacks) fillStacksIntoFirstSlots(); + } + + protected void fillStacksIntoFirstSlots() { + HashMap<GT_Utility.ItemId, Integer> slots = new HashMap<>(mInventory.length); + HashMap<GT_Utility.ItemId, ItemStack> stacks = new HashMap<>(mInventory.length); + List<GT_Utility.ItemId> order = new ArrayList<>(mInventory.length); + List<Integer> validSlots = new ArrayList<>(mInventory.length); + for (int i = 0; i < mInventory.length - 1; i++) { + if (!isValidSlot(i)) continue; + validSlots.add(i); + ItemStack s = mInventory[i]; + if (s == null) continue; + GT_Utility.ItemId sID = GT_Utility.ItemId.createNoCopy(s); + slots.merge(sID, s.stackSize, Integer::sum); + if (!stacks.containsKey(sID)) stacks.put(sID, s); + order.add(sID); + mInventory[i] = null; + } + int slotindex = 0; + for (GT_Utility.ItemId sID : order) { + int toSet = slots.get(sID); + if (toSet == 0) continue; + int slot = validSlots.get(slotindex); + slotindex++; + mInventory[slot] = stacks.get(sID) + .copy(); + toSet = Math.min(toSet, mInventory[slot].getMaxStackSize()); + mInventory[slot].stackSize = toSet; + slots.merge(sID, toSet, (a, b) -> a - b); + } + } + + @Override + public boolean onSolderingToolRightClick(ForgeDirection side, ForgeDirection wrenchingSide, + EntityPlayer entityPlayer, float aX, float aY, float aZ) { + if (entityPlayer.isSneaking()) { + // I was so proud of all this but I literally just copied code from OutputBus + bSortStacks = !bSortStacks; + GT_Utility.sendChatToPlayer( + entityPlayer, + GT_Utility.trans("200", "Sort mode: ") + + (bSortStacks ? GT_Utility.trans("088", "Enabled") : GT_Utility.trans("087", "Disabled"))); + return true; + } + return super.onSolderingToolRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ); + } + + @Override + public boolean useModularUI() { + return true; + } + + protected void addEmitEnergyButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bOutput, + val -> bOutput = val, + GT_UITextures.OVERLAY_BUTTON_EMIT_ENERGY, + this::getEmitEnergyButtonTooltip)); + } + + private GT_TooltipDataCache.TooltipData getEmitEnergyButtonTooltip() { + return mTooltipCache.getData( + EMIT_ENERGY_TOOLTIP, + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(V[mTier]) + + " (" + + GT_Utility.getColoredTierNameFromTier(mTier) + + EnumChatFormatting.GREEN + + ")" + + EnumChatFormatting.GRAY, + maxAmperesOut()); + } + + protected void addEmitRedstoneIfFullButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bRedstoneIfFull, + val -> bRedstoneIfFull = val, + GT_UITextures.OVERLAY_BUTTON_EMIT_REDSTONE, + this::getEmitRedstoneIfFullButtonTooltip).setUpdateTooltipEveryTick(true)); + } + + private GT_TooltipDataCache.TooltipData getEmitRedstoneIfFullButtonTooltip() { + return mTooltipCache.getUncachedTooltipData( + EMIT_REDSTONE_IF_FULL_TOOLTIP, + StatCollector.translateToLocal(hasEmptySlots() ? "gui.yes" : "gui.no"), + getRedstoneOutput()); + } + + protected void addInvertRedstoneButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bInvert, + val -> bInvert = val, + GT_UITextures.OVERLAY_BUTTON_INVERT_REDSTONE, + () -> mTooltipCache.getData(INVERT_REDSTONE_TOOLTIP))); + } + + protected void addStockingModeButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bStockingMode, + val -> bStockingMode = val, + GT_UITextures.OVERLAY_BUTTON_STOCKING_MODE, + () -> mTooltipCache.getData(STOCKING_MODE_TOOLTIP))); + } + + protected void addSortStacksButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bSortStacks, + val -> bSortStacks = val, + GT_UITextures.OVERLAY_BUTTON_SORTING_MODE, + () -> mTooltipCache.getData(SORTING_MODE_TOOLTIP))); + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + buildContext.addCloseListener(() -> uiButtonCount = 0); + addEmitEnergyButton(builder); + } + + protected Widget createToggleButton(Supplier<Boolean> getter, Consumer<Boolean> setter, UITexture picture, + Supplier<GT_TooltipDataCache.TooltipData> tooltipDataSupplier) { + return new CycleButtonWidget().setToggle(getter, setter) + .setStaticTexture(picture) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(7 + (uiButtonCount++ * BUTTON_SIZE), 62) + .setSize(BUTTON_SIZE, BUTTON_SIZE) + .setGTTooltip(tooltipDataSupplier); + } + + protected void addInventorySlots(ModularWindow.Builder builder) { + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 9) + .endAtSlot(26) + .build() + .setPos(7, 4)); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java new file mode 100644 index 0000000000..efb91e3a26 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java @@ -0,0 +1,141 @@ +package gregtech.api.metatileentity.implementations; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; + +import java.util.List; + +import net.minecraft.item.ItemStack; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.IStructureElement; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_StructureUtility; + +/** + * A simple 3x3x3 hollow cubic multiblock, that can be arbitrarily rotated, made of a single type of machine casing and + * accepts hatches everywhere. Controller will be placed in front center of the structure. + * <p> + * Note: You cannot use different casing for the same Class. Make a new subclass for it. You also should not change the + * casing dynamically, i.e. it should be a dumb method returning some sort of constant. + * <p> + * Implementation tips: 1. To restrict hatches, override {@link #addDynamoToMachineList(IGregTechTileEntity, int)} and + * its cousins instead of overriding the whole {@link #getStructureDefinition()} or change + * {@link #checkHatches(IGregTechTileEntity, ItemStack)}. The former is a total overkill, while the later cannot stop + * the structure check early. 2. To limit rotation, override {@link #getInitialAlignmentLimits()} + * + * @param <T> + */ +public abstract class GT_MetaTileEntity_CubicMultiBlockBase<T extends GT_MetaTileEntity_CubicMultiBlockBase<T>> + extends GT_MetaTileEntity_EnhancedMultiBlockBase<T> implements ISurvivalConstructable { + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + protected static final ClassValue<IStructureDefinition<GT_MetaTileEntity_CubicMultiBlockBase<?>>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_CubicMultiBlockBase<?>> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_CubicMultiBlockBase<?>>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "hhh", "hhh", "hhh" }, { "h~h", "h-h", "hhh" }, { "hhh", "hhh", "hhh" }, })) + .addElement( + 'h', + ofChain( + lazy( + t -> GT_StructureUtility.<GT_MetaTileEntity_CubicMultiBlockBase<?>>buildHatchAdder() + .atLeastList(t.getAllowedHatches()) + .casingIndex(t.getHatchTextureIndex()) + .dot(1) + .build()), + onElementPass( + GT_MetaTileEntity_CubicMultiBlockBase::onCorrectCasingAdded, + lazy(GT_MetaTileEntity_CubicMultiBlockBase::getCasingElement)))) + .build(); + } + }; + private int mCasingAmount = 0; + + protected GT_MetaTileEntity_CubicMultiBlockBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected GT_MetaTileEntity_CubicMultiBlockBase(String aName) { + super(aName); + } + + /** + * Create a simple 3x3x3 hollow cubic structure made of a single type of machine casing and accepts hatches + * everywhere. + * <p> + * The created definition contains a single piece named {@link #STRUCTURE_PIECE_MAIN}. + */ + @Override + @SuppressWarnings("unchecked") + public IStructureDefinition<T> getStructureDefinition() { + return (IStructureDefinition<T>) STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + public void construct(ItemStack aStack, boolean aHintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, aStack, aHintsOnly, 1, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 1, 0, elementBudget, env, false, true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mCasingAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 1, 0) && mCasingAmount >= getRequiredCasingCount() + && checkHatches(aBaseMetaTileEntity, aStack); + } + + /** + * Called by {@link #checkMachine(IGregTechTileEntity, ItemStack)} to check if all required hatches are present. + * <p> + * Default implementation requires EXACTLY ONE maintenance hatch to be present, and ignore all other conditions. + * + * @param aBaseMetaTileEntity the tile entity of self + * @param aStack The item stack inside the controller + * @return true if the test passes, false otherwise + */ + protected boolean checkHatches(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + return mMaintenanceHatches.size() == 1; + } + + protected abstract IStructureElement<GT_MetaTileEntity_CubicMultiBlockBase<?>> getCasingElement(); + + protected List<IHatchElement<? super GT_MetaTileEntity_CubicMultiBlockBase<?>>> getAllowedHatches() { + return ImmutableList.of(InputHatch, OutputHatch, InputBus, OutputBus, Muffler, Maintenance, Energy); + } + + /** + * The hatch's texture index. + */ + protected abstract int getHatchTextureIndex(); + + protected abstract int getRequiredCasingCount(); + + protected void onCorrectCasingAdded() { + mCasingAmount++; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java new file mode 100644 index 0000000000..c7f0e6cdd5 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java @@ -0,0 +1,318 @@ +package gregtech.api.metatileentity.implementations; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.IAlignment; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; +import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; +import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; +import com.gtnewhorizon.structurelib.structure.IItemSource; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import cpw.mods.fml.common.network.NetworkRegistry; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; + +/** + * Enhanced multiblock base class, featuring following improvement over {@link GT_MetaTileEntity_MultiBlockBase} + * <p> + * 1. TecTech style declarative structure check utilizing StructureLib. 2. Arbitrarily rotating the whole structure, if + * allowed to. + * + * @param <T> type of this + */ +public abstract class GT_MetaTileEntity_EnhancedMultiBlockBase<T extends GT_MetaTileEntity_EnhancedMultiBlockBase<T>> + extends GT_MetaTileEntity_TooltipMultiBlockBase implements IAlignment, IConstructable { + + private ExtendedFacing mExtendedFacing = ExtendedFacing.DEFAULT; + private IAlignmentLimits mLimits = getInitialAlignmentLimits(); + + protected GT_MetaTileEntity_EnhancedMultiBlockBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected GT_MetaTileEntity_EnhancedMultiBlockBase(String aName) { + super(aName); + } + + @Override + public ExtendedFacing getExtendedFacing() { + return mExtendedFacing; + } + + @Override + public void setExtendedFacing(ExtendedFacing newExtendedFacing) { + if (mExtendedFacing != newExtendedFacing) { + if (mMachine) stopMachine(ShutDownReasonRegistry.STRUCTURE_INCOMPLETE); + mExtendedFacing = newExtendedFacing; + final IGregTechTileEntity base = getBaseMetaTileEntity(); + mMachine = false; + mUpdated = false; + mUpdate = 100; + if (getBaseMetaTileEntity().isServerSide() + && !GregTech_API.isDummyWorld(getBaseMetaTileEntity().getWorld())) { + StructureLibAPI.sendAlignment( + (IAlignmentProvider) base, + new NetworkRegistry.TargetPoint( + base.getWorld().provider.dimensionId, + base.getXCoord(), + base.getYCoord(), + base.getZCoord(), + 512)); + } else { + base.issueTextureUpdate(); + } + } + } + + @Override + public final boolean isFacingValid(ForgeDirection facing) { + return canSetToDirectionAny(facing); + } + + @Override + public boolean onWrenchRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, + float aX, float aY, float aZ) { + if (wrenchingSide != getBaseMetaTileEntity().getFrontFacing()) + return super.onWrenchRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ); + if (entityPlayer.isSneaking()) { + if (isFlipChangeAllowed()) { + toolSetFlip(getFlip().isHorizontallyFlipped() ? Flip.NONE : Flip.HORIZONTAL); + } else { + return false; + } + } else { + if (isRotationChangeAllowed()) { + toolSetRotation(null); + } else { + return false; + } + } + return true; + } + + @Override + public void onFacingChange() { + toolSetDirection(getBaseMetaTileEntity().getFrontFacing()); + } + + @Override + public IAlignmentLimits getAlignmentLimits() { + return mLimits; + } + + protected void setAlignmentLimits(IAlignmentLimits mLimits) { + this.mLimits = mLimits; + } + + /** + * Due to limitation of Java type system, you might need to do an unchecked cast. HOWEVER, the returned + * IStructureDefinition is expected to be evaluated against current instance only, and should not be used against + * other instances, even for those of the same class. + */ + public abstract IStructureDefinition<T> getStructureDefinition(); + + protected abstract GT_Multiblock_Tooltip_Builder createTooltip(); + + @Override + public String[] getStructureDescription(ItemStack stackSize) { + return getTooltip().getStructureHint(); + } + + protected IAlignmentLimits getInitialAlignmentLimits() { + return (d, r, f) -> !f.isVerticallyFliped(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setByte( + "eRotation", + (byte) mExtendedFacing.getRotation() + .getIndex()); + aNBT.setByte( + "eFlip", + (byte) mExtendedFacing.getFlip() + .getIndex()); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mExtendedFacing = ExtendedFacing.of( + getBaseMetaTileEntity().getFrontFacing(), + Rotation.byIndex(aNBT.getByte("eRotation")), + Flip.byIndex(aNBT.getByte("eFlip"))); + if (!getAlignmentLimits().isNewExtendedFacingValid(mExtendedFacing)) { + mExtendedFacing = getCorrectedAlignment(mExtendedFacing); + } + } + + /** + * When an old {@link ExtendedFacing} is loaded upon MTE deserialization, and the loaded facing cannot pass test of + * current {@link #getAlignmentLimits()}, this method will be called to retrieve a corrected version. This method + * is currently only intended to be used as a mean to migrate alignment limits, so if you never change the alignment + * limit then you can probably just use the default implementation. + * + * The returned new facing must be able to pass the test of {@link #isNewExtendedFacingValid(ExtendedFacing)} + */ + protected ExtendedFacing getCorrectedAlignment(ExtendedFacing aOldFacing) { + if (isNewExtendedFacingValid(ExtendedFacing.DEFAULT)) { + return ExtendedFacing.DEFAULT; + } + for (ExtendedFacing facing : ExtendedFacing.VALUES) { + if (facing.getFlip() + .isVerticallyFliped()) { + continue; + } + if (isNewExtendedFacingValid(facing)) { + return facing; + } + } + throw new AssertionError("No ExtendedFacing can pass the test of isNewExtendedFacingValid"); + } + + @SuppressWarnings("unchecked") + private IStructureDefinition<GT_MetaTileEntity_EnhancedMultiBlockBase<T>> getCastedStructureDefinition() { + return (IStructureDefinition<GT_MetaTileEntity_EnhancedMultiBlockBase<T>>) getStructureDefinition(); + } + + /** + * Explanation of the world coordinate these offset means: + * <p> + * Imagine you stand in front of the controller, with controller facing towards you not rotated or flipped. + * <p> + * The horizontalOffset would be the number of blocks on the left side of the controller, not counting controller + * itself. The verticalOffset would be the number of blocks on the top side of the controller, not counting + * controller itself. The depthOffset would be the number of blocks between you and controller, not counting + * controller itself. + * <p> + * All these offsets can be negative. + */ + protected final boolean checkPiece(String piece, int horizontalOffset, int verticalOffset, int depthOffset) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + return getCastedStructureDefinition().check( + this, + piece, + tTile.getWorld(), + getExtendedFacing(), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + horizontalOffset, + verticalOffset, + depthOffset, + !mMachine); + } + + protected final boolean buildPiece(String piece, ItemStack trigger, boolean hintOnly, int horizontalOffset, + int verticalOffset, int depthOffset) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + return getCastedStructureDefinition().buildOrHints( + this, + trigger, + piece, + tTile.getWorld(), + getExtendedFacing(), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + horizontalOffset, + verticalOffset, + depthOffset, + hintOnly); + } + + @Deprecated + protected final int survivialBuildPiece(String piece, ItemStack trigger, int horizontalOffset, int verticalOffset, + int depthOffset, int elementsBudget, IItemSource source, EntityPlayerMP actor, boolean check) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + return getCastedStructureDefinition().survivalBuild( + this, + trigger, + piece, + tTile.getWorld(), + getExtendedFacing(), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + horizontalOffset, + verticalOffset, + depthOffset, + elementsBudget, + source, + actor, + check); + } + + protected final int survivialBuildPiece(String piece, ItemStack trigger, int horizontalOffset, int verticalOffset, + int depthOffset, int elementsBudget, ISurvivalBuildEnvironment env, boolean check) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + return getCastedStructureDefinition().survivalBuild( + this, + trigger, + piece, + tTile.getWorld(), + getExtendedFacing(), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + horizontalOffset, + verticalOffset, + depthOffset, + elementsBudget, + env, + check); + } + + @Deprecated + protected final int survivialBuildPiece(String piece, ItemStack trigger, int horizontalOffset, int verticalOffset, + int depthOffset, int elementsBudget, IItemSource source, EntityPlayerMP actor, boolean check, + boolean checkIfPlaced) { + int built = survivialBuildPiece( + piece, + trigger, + horizontalOffset, + verticalOffset, + depthOffset, + elementsBudget, + source, + actor, + check); + if (checkIfPlaced && built > 0) checkStructure(true, getBaseMetaTileEntity()); + return built; + } + + protected final int survivialBuildPiece(String piece, ItemStack trigger, int horizontalOffset, int verticalOffset, + int depthOffset, int elementsBudget, ISurvivalBuildEnvironment env, boolean check, boolean checkIfPlaced) { + int built = survivialBuildPiece( + piece, + trigger, + horizontalOffset, + verticalOffset, + depthOffset, + elementsBudget, + env, + check); + if (checkIfPlaced && built > 0) checkStructure(true, getBaseMetaTileEntity()); + return built; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (aBaseMetaTileEntity.isClientSide()) + StructureLibAPI.queryAlignment((IAlignmentProvider) aBaseMetaTileEntity); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java new file mode 100644 index 0000000000..b7f34f264c --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_ExtendedPowerMultiBlockBase.java @@ -0,0 +1,242 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.util.GT_ExoticEnergyInputHelper; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; + +/** + * Multiblock base class that allows machine to use power over int. + */ +public abstract class GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T extends GT_MetaTileEntity_EnhancedMultiBlockBase<T>> + extends GT_MetaTileEntity_EnhancedMultiBlockBase<T> { + + public long lEUt; + + protected GT_MetaTileEntity_ExtendedPowerMultiBlockBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected GT_MetaTileEntity_ExtendedPowerMultiBlockBase(String aName) { + super(aName); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + // NBT can be loaded as any primitive type, so we can load it as long. + this.lEUt = aNBT.getLong("mEUt"); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setLong("mEUt", this.lEUt); + } + + @Override + protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, + boolean perfectOC) { + GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(aEUt) + .setEUt(maxInputVoltage * mAmperage) + .setDuration(aDuration) + .setDurationDecreasePerOC(perfectOC ? 2 : 1) + .calculate(); + lEUt = calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); + } + + @Override + public boolean onRunningTick(ItemStack aStack) { + if (this.lEUt > 0) { + addEnergyOutput((this.lEUt * mEfficiency) / 10000); + return true; + } + if (this.lEUt < 0) { + if (!drainEnergyInput(getActualEnergyUsage())) { + stopMachine(ShutDownReasonRegistry.POWER_LOSS); + return false; + } + } + return true; + } + + @Override + public void stopMachine(@NotNull ShutDownReason reason) { + this.lEUt = 0; + super.stopMachine(reason); + } + + @Override + protected long getActualEnergyUsage() { + return (-this.lEUt * 10000) / Math.max(1000, mEfficiency); + } + + public List<GT_MetaTileEntity_Hatch> getExoticAndNormalEnergyHatchList() { + List<GT_MetaTileEntity_Hatch> tHatches = new ArrayList<>(); + tHatches.addAll(filterValidMTEs(mExoticEnergyHatches)); + tHatches.addAll(filterValidMTEs(mEnergyHatches)); + return tHatches; + } + + @Override + public boolean drainEnergyInput(long aEU) { + return GT_ExoticEnergyInputHelper.drainEnergy(aEU, getExoticAndNormalEnergyHatchList()); + } + + @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); + + final IGregTechTileEntity tileEntity = getBaseMetaTileEntity(); + if (tileEntity != null) { + if (tileEntity.isActive()) { + if (lEUt < 0) tag.setLong("energyUsage", getActualEnergyUsage()); + else tag.setLong("energyUsage", -lEUt * mEfficiency / 10000); + } + } + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(getAverageInputVoltage()); + logic.setAvailableAmperage(getMaxInputAmps()); + logic.setAmperageOC(true); + } + + @Nonnull + @Override + protected CheckRecipeResult postCheckRecipe(@Nonnull CheckRecipeResult result, + @Nonnull ProcessingLogic processingLogic) { + return result; + } + + @Override + protected void setEnergyUsage(ProcessingLogic processingLogic) { + lEUt = processingLogic.getCalculatedEut(); + if (lEUt > 0) { + lEUt = (-lEUt); + } + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch tHatch : getExoticAndNormalEnergyHatchList()) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + long voltage = getAverageInputVoltage(); + long amps = getMaxInputAmps(); + + return new String[] { + /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(getActualEnergyUsage()) + + EnumChatFormatting.RESET + + " EU/t", + /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(voltage) + + EnumChatFormatting.RESET + + " EU/t(*" + + amps + + " A)" + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(voltage)] + + EnumChatFormatting.RESET, + /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + /* 6 */ StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } + + @Override + public long getMaxInputVoltage() { + return GT_ExoticEnergyInputHelper.getMaxInputVoltageMulti(getExoticAndNormalEnergyHatchList()); + } + + @Override + public long getAverageInputVoltage() { + return GT_ExoticEnergyInputHelper.getAverageInputVoltageMulti(getExoticAndNormalEnergyHatchList()); + } + + @Override + public long getMaxInputAmps() { + return GT_ExoticEnergyInputHelper.getMaxWorkingInputAmpsMulti(getExoticAndNormalEnergyHatchList()); + } + + @Override + public long getMaxInputEu() { + return GT_ExoticEnergyInputHelper.getTotalEuMulti(getExoticAndNormalEnergyHatchList()); + } + + @Override + public void clearHatches() { + super.clearHatches(); + mExoticEnergyHatches.clear(); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_FilterBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_FilterBase.java new file mode 100644 index 0000000000..896cb223f3 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_FilterBase.java @@ -0,0 +1,106 @@ +package gregtech.api.metatileentity.implementations; + +import net.minecraft.nbt.NBTTagCompound; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.util.GT_TooltipDataCache; + +public abstract class GT_MetaTileEntity_FilterBase extends GT_MetaTileEntity_Buffer { + + private static final String INVERT_FILTER_TOOLTIP = "GT5U.machines.invert_filter.tooltip"; + protected static final int FILTER_SLOT_INDEX = 9; + protected static final int NUM_INVENTORY_SLOTS = 9; + private static final String EMIT_REDSTONE_GRADUALLY_TOOLTIP = "GT5U" + ".machines.emit_redstone_gradually.tooltip"; + protected boolean invertFilter = false; + + public GT_MetaTileEntity_FilterBase(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription); + } + + public GT_MetaTileEntity_FilterBase(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription); + } + + public GT_MetaTileEntity_FilterBase(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_FilterBase(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex < NUM_INVENTORY_SLOTS; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("bInvertFilter", this.invertFilter); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + this.invertFilter = aNBT.getBoolean("bInvertFilter"); + } + + @Override + protected int getRedstoneOutput() { + if (!bRedstoneIfFull) { + return 0; + } + int redstoneOutput = getEmptySlots(); + if (!bInvert) redstoneOutput = NUM_INVENTORY_SLOTS - redstoneOutput; + return redstoneOutput; + } + + private int getEmptySlots() { + int emptySlots = 0; + for (int i = 0; i < NUM_INVENTORY_SLOTS; i++) { + if (mInventory[i] == null) ++emptySlots; + } + return emptySlots; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + addSortStacksButton(builder); + addEmitRedstoneGraduallyButton(builder); + addInvertRedstoneButton(builder); + addInvertFilterButton(builder); + } + + private void addEmitRedstoneGraduallyButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> bRedstoneIfFull, + val -> bRedstoneIfFull = val, + GT_UITextures.OVERLAY_BUTTON_EMIT_REDSTONE, + this::getEmitRedstoneGraduallyButtonTooltip).setUpdateTooltipEveryTick(true)); + } + + private GT_TooltipDataCache.TooltipData getEmitRedstoneGraduallyButtonTooltip() { + return mTooltipCache + .getUncachedTooltipData(EMIT_REDSTONE_GRADUALLY_TOOLTIP, getEmptySlots(), getRedstoneOutput()); + } + + private void addInvertFilterButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> invertFilter, + val -> invertFilter = val, + GT_UITextures.OVERLAY_BUTTON_INVERT_FILTER, + () -> mTooltipCache.getData(INVERT_FILTER_TOOLTIP))); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch.java new file mode 100644 index 0000000000..1e974f5e9d --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch.java @@ -0,0 +1,252 @@ +package gregtech.api.metatileentity.implementations; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import appeng.api.crafting.ICraftingIconProvider; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +/** + * Handles texture changes internally. No special calls are necessary other than updateTexture in add***ToMachineList. + */ +public abstract class GT_MetaTileEntity_Hatch extends GT_MetaTileEntity_BasicTank implements ICraftingIconProvider { + + public enum ConnectionType { + CABLE, + WIRELESS, + LASER + } + + /** + * Uses new texture changing methods to avoid limitations of byte as texture index... + */ + @Deprecated + public byte mMachineBlock = 0; + + private byte mTexturePage = 0; + private byte actualTexture = 0; + + private ItemStack ae2CraftingIcon; + + public GT_MetaTileEntity_Hatch(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public static int getSlots(int aTier) { + return aTier < 1 ? 1 : aTier == 1 ? 4 : aTier == 2 ? 9 : 16; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + return new ITexture[0][0][0]; + } + + public abstract ITexture[] getTexturesActive(ITexture aBaseTexture); + + public abstract ITexture[] getTexturesInactive(ITexture aBaseTexture); + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + int texturePointer = (byte) (actualTexture & 0x7F); // just to be sure, from my testing the 8th bit cannot be + // set clientside + int textureIndex = texturePointer | (mTexturePage << 7); // Shift seven since one page is 128 textures! + try { + if (side != aFacing) { + if (textureIndex > 0) + return new ITexture[] { Textures.BlockIcons.casingTexturePages[mTexturePage][texturePointer] }; + else return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1] }; + } else { + if (textureIndex > 0) { + if (aActive) + return getTexturesActive(Textures.BlockIcons.casingTexturePages[mTexturePage][texturePointer]); + else return getTexturesInactive( + Textures.BlockIcons.casingTexturePages[mTexturePage][texturePointer]); + } else { + if (aActive) return getTexturesActive(Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1]); + else return getTexturesInactive(Textures.BlockIcons.MACHINE_CASINGS[mTier][colorIndex + 1]); + } + } + } catch (NullPointerException npe) { + return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[0][0] }; + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setByte("mMachineBlock", actualTexture); + aNBT.setByte("mTexturePage", mTexturePage); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + actualTexture = aNBT.getByte("mMachineBlock"); + mTexturePage = aNBT.getByte("mTexturePage"); + + if (mTexturePage != 0 && GT_Values.GT.isServerSide()) actualTexture |= 0x80; // <- lets just hope no one needs + // the correct value for that on + // server + mMachineBlock = actualTexture; + } + + /** + * Sets texture with page and index, called on add to machine list + * + * @param id (page<<7)+index of the texture + */ + public final void updateTexture(int id) { + onValueUpdate((byte) id); + onTexturePageUpdate((byte) (id >> 7)); + } + + /** + * Sets the icon for the owning multiblock used for AE2 crafting display of attached interfaces, called on add to + * machine list + */ + public final void updateCraftingIcon(ItemStack icon) { + this.ae2CraftingIcon = icon; + } + + @Override + public ItemStack getMachineCraftingIcon() { + return this.ae2CraftingIcon; + } + + /** + * Some multiblocks restrict hatches by tier. This method allows hatches to specify custom tier used for + * structure check, while keeping {@link #mTier} for other uses. + * + * @return Tier used for multiblock structure + */ + public byte getTierForStructure() { + return mTier; + } + + /** + * Sets texture with page and index, rather unusable, but kept FFS + * + * @param page page of texure + * @param index index of texure + */ + @Deprecated + public final void updateTexture(byte page, byte index) { + onValueUpdate(index); + onTexturePageUpdate(page); + } + + @Override + public final void onValueUpdate(byte aValue) { + actualTexture = (byte) (aValue & 0x7F); + mMachineBlock = actualTexture; + mTexturePage = 0; + } + + /** + * Get the maximum amount of amperes to work with, which excludes the additional amps in for loss + * + * @return Working amps + */ + public long maxWorkingAmperesIn() { + return maxAmperesIn(); + } + + /** + * Get the type of connection this hatch allows + * + * @return Connection type + */ + public ConnectionType getConnectionType() { + return ConnectionType.CABLE; + } + + @Override + public final byte getUpdateData() { + return (byte) (actualTexture & 0x7F); + } + + public final void onTexturePageUpdate(byte aValue) { + mTexturePage = (byte) (aValue & 0x7F); + if (mTexturePage != 0 && getBaseMetaTileEntity().isServerSide()) { // just to be sure + mMachineBlock |= 0x80; // <- lets just hope no one needs the correct value for that on server + actualTexture = mMachineBlock; + } + // set last bit to allow working of the page reset-er to 0 in rare case when texture id is the same but page + // changes to 0 + } + + public final byte getTexturePage() { + return (byte) (mTexturePage & 0x7F); + } + + @Override + public boolean doesFillContainers() { + return false; + } + + @Override + public boolean doesEmptyContainers() { + return false; + } + + @Override + public boolean canTankBeFilled() { + return false; + } + + @Override + public boolean canTankBeEmptied() { + return false; + } + + @Override + public boolean displaysItemStack() { + return false; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { // in that method since it is usually + // not overriden, especially for + // hatches. + if (actualTexture != mMachineBlock) { // revert to page 0 on edition of the field - old code way + actualTexture = (byte) (mMachineBlock & 0x7F); + mMachineBlock = actualTexture; // clear last bit in mMachineBlock since now we are at page 0 after the + // direct field + // change + mTexturePage = 0; // assuming old code only supports page 0 + } + super.onPreTick(aBaseMetaTileEntity, aTick); + } + + // To change to other page -> use the setter method -> updateTexture + + public int getCircuitSlot() { + return -1; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_DataAccess.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_DataAccess.java new file mode 100644 index 0000000000..122dcfa746 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_DataAccess.java @@ -0,0 +1,157 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DATA_ACCESS; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_AssemblyLineUtils; + +public class GT_MetaTileEntity_Hatch_DataAccess extends GT_MetaTileEntity_Hatch implements IAddUIWidgets { + + private int timeout = 4; + + public GT_MetaTileEntity_Hatch_DataAccess(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 16, + new String[] { "Data Access for Multiblocks", + "Adds " + (aTier == 4 ? 4 : 16) + " extra slots for Data Sticks" }); + } + + public GT_MetaTileEntity_Hatch_DataAccess(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aTier == 4 ? 4 : 16, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_DataAccess(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aTier == 4 ? 4 : 16, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_DATA_ACCESS) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_DATA_ACCESS) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_DataAccess(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return mTier >= 8 && !aBaseMetaTileEntity.isActive(); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return mTier >= 8 && !aBaseMetaTileEntity.isActive(); + } + + @Override + public int getInventoryStackLimit() { + return 1; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isActive()) { + timeout--; + if (timeout <= 0) { + aBaseMetaTileEntity.setActive(false); + } + } + } + + public void setActive(boolean mActive) { + getBaseMetaTileEntity().setActive(mActive); + timeout = mActive ? 4 : 0; + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.getByte("mSticksUpdated") != 1) { + for (int i = 0; i < getSizeInventory(); i++) { + GT_AssemblyLineUtils.processDataStick(getStackInSlot(i)); + } + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + // reminder: remove this marker after many years + aNBT.setByte("mSticksUpdated", (byte) 1); + } + + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + super.setInventorySlotContents(aIndex, aStack); + GT_AssemblyLineUtils.processDataStick(aStack); + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + if (mTier == 4) { + getBaseMetaTileEntity() + .add2by2Slots(builder, getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_CIRCUIT); + } else { + getBaseMetaTileEntity() + .add4by4Slots(builder, getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_CIRCUIT); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Dynamo.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Dynamo.java new file mode 100644 index 0000000000..8e621434db --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Dynamo.java @@ -0,0 +1,110 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; + +public class GT_MetaTileEntity_Hatch_Dynamo extends GT_MetaTileEntity_Hatch { + + public GT_MetaTileEntity_Hatch_Dynamo(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 0, + new String[] { "Generating electric Energy from Multiblocks", "Puts out up to 1 Amp" }); + } + + public GT_MetaTileEntity_Hatch_Dynamo(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, 0, aDescription); + } + + public GT_MetaTileEntity_Hatch_Dynamo(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Dynamo(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 512; + } + + @Override + public long maxEUOutput() { + return V[mTier]; + } + + @Override + public long maxEUStore() { + return 512L + V[mTier + 1] * 2L; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Dynamo(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Energy.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Energy.java new file mode 100644 index 0000000000..d9be12671d --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Energy.java @@ -0,0 +1,125 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; + +public class GT_MetaTileEntity_Hatch_Energy extends GT_MetaTileEntity_Hatch { + + public GT_MetaTileEntity_Hatch_Energy(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, 0, aDescription); + } + + public GT_MetaTileEntity_Hatch_Energy(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 0, + new String[] { "Energy Injector for Multiblocks", "Accepts up to 2 Amps" }); + } + + public GT_MetaTileEntity_Hatch_Energy(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Energy(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Energy(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Energy(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[mTier] }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[mTier] }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 512; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxEUStore() { + return 512L + V[mTier] * 8L; + } + + @Override + public long maxAmperesIn() { + return 2; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Energy(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java new file mode 100644 index 0000000000..18aef371b6 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Input.java @@ -0,0 +1,201 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.FLUID_IN_SIGN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_IN; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Hatch_Input extends GT_MetaTileEntity_Hatch { + + public RecipeMap<?> mRecipeMap = null; + + public GT_MetaTileEntity_Hatch_Input(int aID, String aName, String aNameRegional, int aTier) { + this( + aID, + aName, + aNameRegional, + aTier, + new String[] { "Fluid Input for Multiblocks", + "Capacity: " + GT_Utility.formatNumbers(8000L * (1L << aTier)) + "L" }); + } + + public GT_MetaTileEntity_Hatch_Input(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription) { + this(aID, 3, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_Hatch_Input(int aID, int aSlot, String aName, String aNameRegional, int aTier) { + this( + aID, + aSlot, + aName, + aNameRegional, + aTier, + new String[] { "Fluid Input for Multiblocks", "", "Can hold " + aSlot + " types of fluid." }); + mDescriptionArray[1] = "Capacity: " + GT_Utility.formatNumbers(getCapacityPerTank(aTier, aSlot)) + "L"; + } + + public GT_MetaTileEntity_Hatch_Input(int aID, int aSlot, String aName, String aNameRegional, int aTier, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, aSlot, aDescription); + } + + public GT_MetaTileEntity_Hatch_Input(int aID, String aName, String aNameRegional, int aTier, int allSlotCount, + String[] strings) { + super(aID, aName, aNameRegional, aTier, allSlotCount, strings); + } + + public int getCapacityPerTank(int aTier, int aSlot) { + return (int) (8000L * (1L << aTier) / aSlot); + } + + public GT_MetaTileEntity_Hatch_Input(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Input(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Input(String aName, int aSlots, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aSlots, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(FLUID_IN_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(FLUID_IN_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Input(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (mRecipeMap != null) { + aNBT.setString("recipeMap", mRecipeMap.unlocalizedName); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mRecipeMap = RecipeMap.getFromOldIdentifier(aNBT.getString("recipeMap")); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public boolean doesFillContainers() { + // return true; + return false; + } + + @Override + public boolean doesEmptyContainers() { + return true; + } + + @Override + public boolean canTankBeFilled() { + return true; + } + + @Override + public boolean canTankBeEmptied() { + return true; + } + + @Override + public boolean displaysItemStack() { + return true; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + public void updateSlots() { + if (mInventory[getInputSlot()] != null && mInventory[getInputSlot()].stackSize <= 0) + mInventory[getInputSlot()] = null; + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return mRecipeMap == null || mRecipeMap.containsInput(aFluid); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == aBaseMetaTileEntity.getFrontFacing() && aIndex == 1; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == aBaseMetaTileEntity.getFrontFacing() && aIndex == 0 + && (mRecipeMap == null || mRecipeMap.containsInput(aStack) + || mRecipeMap.containsInput(GT_Utility.getFluidForFilledItem(aStack, true))); + } + + @Override + public int getCapacity() { + return 8000 * (1 << mTier); + } + + @Override + public int getTankPressure() { + return -100; + } + + @Override + public boolean useModularUI() { + return true; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java new file mode 100644 index 0000000000..f4c4eb6a14 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_InputBus.java @@ -0,0 +1,323 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.ITEM_IN_SIGN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_IN; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.UITexture; +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.widget.CycleButtonWidget; + +import gregtech.GT_Mod; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ClientPreference; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_TooltipDataCache; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.extensions.ArrayExt; + +public class GT_MetaTileEntity_Hatch_InputBus extends GT_MetaTileEntity_Hatch + implements IConfigurationCircuitSupport, IAddUIWidgets { + + private static final String SORTING_MODE_TOOLTIP = "GT5U.machines.sorting_mode.tooltip"; + private static final String ONE_STACK_LIMIT_TOOLTIP = "GT5U.machines.one_stack_limit.tooltip"; + private static final int BUTTON_SIZE = 18; + + public RecipeMap<?> mRecipeMap = null; + public boolean disableSort; + public boolean disableFilter = true; + public boolean disableLimited = true; + private int uiButtonCount = 0; + + public GT_MetaTileEntity_Hatch_InputBus(int id, String name, String nameRegional, int tier) { + this(id, name, nameRegional, tier, getSlots(tier) + 1); + } + + protected GT_MetaTileEntity_Hatch_InputBus(int id, String name, String nameRegional, int tier, int slots, + String[] description) { + super(id, name, nameRegional, tier, slots, description); + } + + public GT_MetaTileEntity_Hatch_InputBus(int id, String name, String nameRegional, int tier, int slots) { + super( + id, + name, + nameRegional, + tier, + slots, + ArrayExt.of( + "Item Input for Multiblocks", + "Shift + right click with screwdriver to turn Sort mode on/off", + "Capacity: " + getSlots(tier) + " stack" + (getSlots(tier) >= 2 ? "s" : ""))); + } + + @Deprecated + // having too many constructors is bad, don't be so lazy, use GT_MetaTileEntity_Hatch_InputBus(String, int, + // String[], ITexture[][][]) + public GT_MetaTileEntity_Hatch_InputBus(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + this(aName, aTier, ArrayExt.of(aDescription), aTextures); + } + + public GT_MetaTileEntity_Hatch_InputBus(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + this(aName, aTier, getSlots(aTier) + 1, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_InputBus(String aName, int aTier, int aSlots, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aSlots, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(ITEM_IN_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(ITEM_IN_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_IN) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex != getCircuitSlot(); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_InputBus(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public int getCircuitSlotX() { + return 153; + } + + @Override + public int getCircuitSlotY() { + return 63; + } + + @Override + public void initDefaultModes(NBTTagCompound aNBT) { + if (!getBaseMetaTileEntity().getWorld().isRemote) { + GT_ClientPreference tPreference = GT_Mod.gregtechproxy + .getClientPreference(getBaseMetaTileEntity().getOwnerUuid()); + if (tPreference != null) disableFilter = !tPreference.isInputBusInitialFilterEnabled(); + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.hasInventoryBeenModified()) { + updateSlots(); + } + } + + public void updateSlots() { + for (int i = 0; i < mInventory.length - 1; i++) + if (mInventory[i] != null && mInventory[i].stackSize <= 0) mInventory[i] = null; + if (!disableSort) fillStacksIntoFirstSlots(); + } + + protected void fillStacksIntoFirstSlots() { + final int L = mInventory.length - 1; + HashMap<GT_Utility.ItemId, Integer> slots = new HashMap<>(L); + HashMap<GT_Utility.ItemId, ItemStack> stacks = new HashMap<>(L); + List<GT_Utility.ItemId> order = new ArrayList<>(L); + List<Integer> validSlots = new ArrayList<>(L); + for (int i = 0; i < L; i++) { + if (!isValidSlot(i)) continue; + validSlots.add(i); + ItemStack s = mInventory[i]; + if (s == null) continue; + GT_Utility.ItemId sID = GT_Utility.ItemId.createNoCopy(s); + slots.merge(sID, s.stackSize, Integer::sum); + if (!stacks.containsKey(sID)) stacks.put(sID, s); + order.add(sID); + mInventory[i] = null; + } + int slotindex = 0; + for (GT_Utility.ItemId sID : order) { + int toSet = slots.get(sID); + if (toSet == 0) continue; + int slot = validSlots.get(slotindex); + slotindex++; + mInventory[slot] = stacks.get(sID) + .copy(); + toSet = Math.min(toSet, mInventory[slot].getMaxStackSize()); + mInventory[slot].stackSize = toSet; + slots.merge(sID, toSet, (a, b) -> a - b); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("disableSort", disableSort); + aNBT.setBoolean("disableFilter", disableFilter); + aNBT.setBoolean("disableLimited", disableLimited); + if (mRecipeMap != null) { + aNBT.setString("recipeMap", mRecipeMap.unlocalizedName); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + disableSort = aNBT.getBoolean("disableSort"); + disableFilter = aNBT.getBoolean("disableFilter"); + if (aNBT.hasKey("disableLimited")) { + disableLimited = aNBT.getBoolean("disableLimited"); + } + mRecipeMap = RecipeMap.getFromOldIdentifier(aNBT.getString("recipeMap")); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return; + if (aPlayer.isSneaking()) { + if (disableSort) { + disableSort = false; + } else { + if (disableLimited) { + disableLimited = false; + } else { + disableSort = true; + disableLimited = true; + } + } + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.hatch.disableSort." + disableSort) + " " + + StatCollector.translateToLocal("GT5U.hatch.disableLimited." + disableLimited)); + } else { + disableFilter = !disableFilter; + GT_Utility + .sendChatToPlayer(aPlayer, StatCollector.translateToLocal("GT5U.hatch.disableFilter." + disableFilter)); + } + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (aIndex == getCircuitSlot()) return false; + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == getBaseMetaTileEntity().getFrontFacing() && aIndex != getCircuitSlot() + && (mRecipeMap == null || disableFilter || mRecipeMap.containsInput(aStack)) + && (disableLimited || limitedAllowPutStack(aIndex, aStack)); + } + + protected boolean limitedAllowPutStack(int aIndex, ItemStack aStack) { + for (int i = 0; i < getSizeInventory(); i++) + if (GT_Utility.areStacksEqual(GT_OreDictUnificator.get_nocopy(aStack), mInventory[i])) return i == aIndex; + return mInventory[aIndex] == null; + } + + @Override + public boolean allowSelectCircuit() { + return true; + } + + @Override + public int getCircuitSlot() { + return getSlots(mTier); + } + + @Override + public boolean useModularUI() { + return true; + } + + private void addSortStacksButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> !disableSort, + val -> disableSort = !val, + GT_UITextures.OVERLAY_BUTTON_SORTING_MODE, + () -> mTooltipCache.getData(SORTING_MODE_TOOLTIP))); + } + + private void addOneStackLimitButton(ModularWindow.Builder builder) { + builder.widget(createToggleButton(() -> !disableLimited, val -> { + disableLimited = !val; + updateSlots(); + }, GT_UITextures.OVERLAY_BUTTON_ONE_STACK_LIMIT, () -> mTooltipCache.getData(ONE_STACK_LIMIT_TOOLTIP))); + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + buildContext.addCloseListener(() -> uiButtonCount = 0); + addSortStacksButton(builder); + addOneStackLimitButton(builder); + switch (mTier) { + case 0 -> getBaseMetaTileEntity().add1by1Slot(builder); + case 1 -> getBaseMetaTileEntity().add2by2Slots(builder); + case 2 -> getBaseMetaTileEntity().add3by3Slots(builder); + default -> getBaseMetaTileEntity().add4by4Slots(builder); + } + } + + private Widget createToggleButton(Supplier<Boolean> getter, Consumer<Boolean> setter, UITexture picture, + Supplier<GT_TooltipDataCache.TooltipData> tooltipDataSupplier) { + return new CycleButtonWidget().setToggle(getter, setter) + .setStaticTexture(picture) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(7 + (uiButtonCount++ * BUTTON_SIZE), 62) + .setSize(BUTTON_SIZE, BUTTON_SIZE) + .setGTTooltip(tooltipDataSupplier); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Maintenance.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Maintenance.java new file mode 100644 index 0000000000..e1b5ee8f03 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Maintenance.java @@ -0,0 +1,464 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_AUTOMAINTENANCE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_AUTOMAINTENANCE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_AUTOMAINTENANCE_IDLE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_AUTOMAINTENANCE_IDLE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DUCTTAPE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_MAINTENANCE; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.IAlignment; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; +import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; +import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import cpw.mods.fml.common.network.NetworkRegistry; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; +import ic2.core.IHasGui; +import ic2.core.item.ItemToolbox; + +public class GT_MetaTileEntity_Hatch_Maintenance extends GT_MetaTileEntity_Hatch implements IAddUIWidgets, IAlignment { + + private Rotation rotation = Rotation.NORMAL; + + private static ItemStack[] sAutoMaintenanceInputs; + public boolean mWrench = false, mScrewdriver = false, mSoftHammer = false, mHardHammer = false, + mSolderingTool = false, mCrowbar = false, mAuto; + + public GT_MetaTileEntity_Hatch_Maintenance(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, 1, "For maintaining Multiblocks"); + mAuto = false; + } + + public GT_MetaTileEntity_Hatch_Maintenance(int aID, String aName, String aNameRegional, int aTier, boolean aAuto) { + super(aID, aName, aNameRegional, aTier, 4, "For automatically maintaining Multiblocks"); + mAuto = aAuto; + } + + public GT_MetaTileEntity_Hatch_Maintenance(String aName, int aTier, String aDescription, ITexture[][][] aTextures, + boolean aAuto) { + super(aName, aTier, aAuto ? 4 : 1, aDescription, aTextures); + mAuto = aAuto; + } + + public GT_MetaTileEntity_Hatch_Maintenance(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures, + boolean aAuto) { + super(aName, aTier, aAuto ? 4 : 1, aDescription, aTextures); + mAuto = aAuto; + } + + private static ItemStack[] getAutoMaintenanceInputs() { + if (sAutoMaintenanceInputs == null) sAutoMaintenanceInputs = new ItemStack[] { ItemList.Duct_Tape.get(4), + GT_OreDictUnificator.get(OrePrefixes.cell, Materials.Lubricant, 2), + GT_OreDictUnificator.get(OrePrefixes.screw, Materials.Steel, 4), + GT_OreDictUnificator.get(OrePrefixes.circuit, Materials.Advanced, 2) }; + return sAutoMaintenanceInputs; + } + + @Override + public String[] getDescription() { + String[] desc; + if (mAuto) { + desc = new String[mDescriptionArray.length + 3]; + System.arraycopy(mDescriptionArray, 0, desc, 0, mDescriptionArray.length); + desc[mDescriptionArray.length] = "4 Ducttape, 2 Lubricant Cells"; + desc[mDescriptionArray.length + 1] = "4 Steel Screws, 2 HV Circuits"; + desc[mDescriptionArray.length + 2] = "For each autorepair"; + } else { + desc = new String[mDescriptionArray.length + 1]; + System.arraycopy(mDescriptionArray, 0, desc, 0, mDescriptionArray.length); + desc[mDescriptionArray.length] = "Cannot be shared between Multiblocks!"; + } + return desc; + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + if (mAuto) return new ITexture[] { aBaseTexture, TextureFactory.builder() + .addIcon(OVERLAY_AUTOMAINTENANCE_IDLE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_AUTOMAINTENANCE_IDLE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { aBaseTexture, TextureFactory.builder() + .addIcon(OVERLAY_MAINTENANCE) + .extFacing() + .build() }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + if (mAuto) return new ITexture[] { aBaseTexture, TextureFactory.builder() + .addIcon(OVERLAY_AUTOMAINTENANCE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_AUTOMAINTENANCE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { aBaseTexture, TextureFactory.builder() + .addIcon(OVERLAY_MAINTENANCE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_DUCTTAPE) + .extFacing() + .build() }; + } + + @Override + public void initDefaultModes(NBTTagCompound aNBT) { + getBaseMetaTileEntity().setActive(true); + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return mAuto && GT_Mod.gregtechproxy.mAMHInteraction; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + if (aTileEntity.getMetaTileID() == 111) + return new GT_MetaTileEntity_Hatch_Maintenance(mName, mTier, mDescriptionArray, mTextures, true); + return new GT_MetaTileEntity_Hatch_Maintenance(mName, mTier, mDescriptionArray, mTextures, false); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (aBaseMetaTileEntity.isClientSide()) return true; + if (side == aBaseMetaTileEntity.getFrontFacing()) { + // only allow OC robot fake player + if (aPlayer instanceof FakePlayer && !aPlayer.getGameProfile() + .getName() + .endsWith(".robot")) return false; + ItemStack tStack = aPlayer.getCurrentEquippedItem(); + if (tStack != null) { + if (tStack.getItem() instanceof ItemToolbox) { + applyToolbox(tStack, aPlayer); + } else if (ItemList.Duct_Tape.isStackEqual(tStack)) { + mWrench = mScrewdriver = mSoftHammer = mHardHammer = mCrowbar = mSolderingTool = true; + getBaseMetaTileEntity().setActive(false); + if (--tStack.stackSize == 0) { + aPlayer.inventory.mainInventory[aPlayer.inventory.currentItem] = null; + } + } else GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + } else { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + } + return true; + } + return false; + } + + public void updateSlots() { + for (int i = 0; i < mInventory.length; i++) + if (mInventory[i] != null && mInventory[i].stackSize <= 0) mInventory[i] = null; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (aBaseMetaTileEntity.isClientSide()) + StructureLibAPI.queryAlignment((IAlignmentProvider) aBaseMetaTileEntity); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && mAuto && aTick % 100L == 0L) { + aBaseMetaTileEntity.setActive(!isRecipeInputEqual(false)); + } + } + + @Override + public boolean onWrenchRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer entityPlayer, + float aX, float aY, float aZ) { + if (wrenchingSide != getBaseMetaTileEntity().getFrontFacing()) + return super.onWrenchRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ); + if (!entityPlayer.isSneaking() && isRotationChangeAllowed()) { + toolSetRotation(null); + return true; + } + return false; + } + + public boolean autoMaintainance() { + return isRecipeInputEqual(true); + } + + public boolean isRecipeInputEqual(boolean aDecreaseStacksizeBySuccess) { + ItemStack[] mInputs = getAutoMaintenanceInputs(); + + int amt; + + for (ItemStack tStack : mInputs) { + if (tStack != null) { + amt = tStack.stackSize; + boolean temp = true; + for (ItemStack aStack : mInventory) { + if ((GT_Utility.areUnificationsEqual(aStack, tStack, true) + || GT_Utility.areUnificationsEqual(GT_OreDictUnificator.get(false, aStack), tStack, true))) { + amt -= aStack.stackSize; + if (amt < 1) { + temp = false; + break; + } + } + } + if (temp) return false; + } + } + + if (aDecreaseStacksizeBySuccess) { + for (ItemStack tStack : mInputs) { + if (tStack != null) { + amt = tStack.stackSize; + for (ItemStack aStack : mInventory) { + if ((GT_Utility.areUnificationsEqual(aStack, tStack, true) || GT_Utility + .areUnificationsEqual(GT_OreDictUnificator.get(false, aStack), tStack, true))) { + if (aStack.stackSize < amt) { + amt -= aStack.stackSize; + aStack.stackSize = 0; + } else { + aStack.stackSize -= amt; + amt = 0; + break; + } + } + } + } + } + mCrowbar = true; + mHardHammer = true; + mScrewdriver = true; + mSoftHammer = true; + mSolderingTool = true; + mWrench = true; + updateSlots(); + } + return true; + } + + public void onToolClick(ItemStack aStack, EntityLivingBase aPlayer, IInventory aToolboxInventory) { + if (aStack == null || aPlayer == null) return; + + // Allow IC2 Toolbox with tools to function for maint issues. + if (aStack.getItem() instanceof ItemToolbox && aPlayer instanceof EntityPlayer) { + applyToolbox(aStack, (EntityPlayer) aPlayer); + return; + } + + if (GT_Utility.isStackInList(aStack, GregTech_API.sWrenchList) && !mWrench + && GT_ModHandler.damageOrDechargeItem(aStack, 1, 1000, aPlayer)) mWrench = true; + if (GT_Utility.isStackInList(aStack, GregTech_API.sScrewdriverList) && !mScrewdriver + && GT_ModHandler.damageOrDechargeItem(aStack, 1, 1000, aPlayer)) mScrewdriver = true; + if (GT_Utility.isStackInList(aStack, GregTech_API.sSoftHammerList) && !mSoftHammer + && GT_ModHandler.damageOrDechargeItem(aStack, 1, 1000, aPlayer)) mSoftHammer = true; + if (GT_Utility.isStackInList(aStack, GregTech_API.sHardHammerList) && !mHardHammer + && GT_ModHandler.damageOrDechargeItem(aStack, 1, 1000, aPlayer)) mHardHammer = true; + if (GT_Utility.isStackInList(aStack, GregTech_API.sCrowbarList) && !mCrowbar + && GT_ModHandler.damageOrDechargeItem(aStack, 1, 1000, aPlayer)) mCrowbar = true; + if (!mSolderingTool && GT_ModHandler.useSolderingIron(aStack, aPlayer, aToolboxInventory)) + mSolderingTool = true; + if (GT_OreDictUnificator.isItemStackInstanceOf(aStack, "craftingDuctTape")) { + mWrench = mScrewdriver = mSoftHammer = mHardHammer = mCrowbar = mSolderingTool = true; + getBaseMetaTileEntity().setActive(false); + aStack.stackSize--; + } + if (mSolderingTool && aPlayer instanceof EntityPlayerMP tPlayer) { + try { + GT_Mod.achievements.issueAchievement(tPlayer, "maintainance"); + } catch (Exception ignored) {} + } + } + + public void onToolClick(ItemStack aStack, EntityLivingBase aPlayer) { + onToolClick(aStack, aPlayer, null); + } + + private void applyToolbox(ItemStack aStack, EntityPlayer aPlayer) { + final ItemToolbox aToolbox = (ItemToolbox) aStack.getItem(); + final IHasGui aToolboxGUI = aToolbox.getInventory(aPlayer, aStack); + for (int i = 0; i < aToolboxGUI.getSizeInventory(); i++) { + if (aToolboxGUI.getStackInSlot(i) != null) { + onToolClick(aToolboxGUI.getStackInSlot(i), aPlayer, aToolboxGUI); + if (aToolboxGUI.getStackInSlot(i) != null && aToolboxGUI.getStackInSlot(i).stackSize <= 0) + aToolboxGUI.setInventorySlotContents(i, null); + } + } + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return mAuto && GT_Mod.gregtechproxy.mAMHInteraction; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (mAuto && GT_Mod.gregtechproxy.mAMHInteraction) { + for (int i = 0; i < getSizeInventory(); i++) if (GT_Utility.areStacksEqual( + GT_OreDictUnificator.get(false, aStack), + GT_OreDictUnificator.get(false, getStackInSlot(i)))) return i == aIndex; + for (ItemStack tInput : getAutoMaintenanceInputs()) + if (GT_Utility.areUnificationsEqual(tInput, aStack, true) + || GT_Utility.areUnificationsEqual(GT_OreDictUnificator.get(false, aStack), tInput, true)) + return true; + } + return false; + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + if (mAuto) { + getBaseMetaTileEntity().add2by2Slots(builder); + } else { + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.SLOT_MAINTENANCE) + .setPos(78, 33) + .setSize(20, 20)) + .widget(new SlotWidget(BaseSlot.empty()) { + + @Override + public boolean handleDragAndDrop(ItemStack draggedStack, int button) { + return false; + } + + @Override + protected void phantomClick(ClickData clickData, ItemStack cursorStack) { + if (cursorStack == null) return; + onToolClick(cursorStack, getContext().getPlayer()); + if (cursorStack.stackSize < 1) { + getContext().getPlayer().inventory.setItemStack(null); + } + if (getContext().getPlayer() instanceof EntityPlayerMP) { + ((EntityPlayerMP) getContext().getPlayer()).updateHeldItem(); + } + } + }.disableShiftInsert() + .setBackground(GT_UITextures.TRANSPARENT) + .setPos(79, 34)) + .widget( + new TextWidget("Click with Tool to repair.").setDefaultColor(COLOR_TEXT_GRAY.get()) + .setPos(8, 12)); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setByte("mRotation", (byte) rotation.getIndex()); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + rotation = Rotation.byIndex(aNBT.getByte("mRotation")); + super.loadNBTData(aNBT); + } + + @Override + public ExtendedFacing getExtendedFacing() { + return ExtendedFacing.of(getBaseMetaTileEntity().getFrontFacing(), rotation, Flip.NONE); + } + + @Override + public void setExtendedFacing(ExtendedFacing alignment) { + boolean changed = false; + final IGregTechTileEntity base = getBaseMetaTileEntity(); + if (base.getFrontFacing() != alignment.getDirection()) { + base.setFrontFacing(alignment.getDirection()); + changed = true; + } + if (rotation != alignment.getRotation()) { + rotation = alignment.getRotation(); + changed = true; + } + if (changed) { + if (base.isServerSide() && !GregTech_API.isDummyWorld(base.getWorld())) { + StructureLibAPI.sendAlignment( + (IAlignmentProvider) base, + new NetworkRegistry.TargetPoint( + base.getWorld().provider.dimensionId, + base.getXCoord(), + base.getYCoord(), + base.getZCoord(), + 512)); + } else { + base.issueTextureUpdate(); + } + } + } + + @Override + public IAlignmentLimits getAlignmentLimits() { + return (d, r, f) -> f.isNotFlipped(); + } + + @Override + public boolean isFlipChangeAllowed() { + return false; + } + + @Override + public boolean isRotationChangeAllowed() { + return true; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Muffler.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Muffler.java new file mode 100644 index 0000000000..8707d0f804 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Muffler.java @@ -0,0 +1,208 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_MUFFLER; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.GT_Mod; +import gregtech.api.enums.ParticleFX; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.WorldSpawnedEventBuilder; +import gregtech.common.GT_Pollution; + +@SuppressWarnings("unused") // Unused API is expected within scope +public class GT_MetaTileEntity_Hatch_Muffler extends GT_MetaTileEntity_Hatch { + + private static final String localizedDescFormat = GT_LanguageManager.addStringLocalization( + "gt.blockmachines.hatch.muffler.desc.format", + "Outputs the Pollution (Might cause ... things)%n" + "DO NOT OBSTRUCT THE OUTPUT!%n" + + "Reduces Pollution to %d%%%n" + + "Recovers %d%% of CO2/CO/SO2"); + private final int pollutionReduction = calculatePollutionReduction(100); + private final int pollutionRecover = 100 - pollutionReduction; + private final String[] description = String.format(localizedDescFormat, pollutionReduction, pollutionRecover) + .split("\\R"); + + public GT_MetaTileEntity_Hatch_Muffler(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, 0, ""); + } + + public GT_MetaTileEntity_Hatch_Muffler(int aID, String aName, String aNameRegional, int aTier, int aInvSlotCount, + String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Muffler(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + this(aName, aTier, new String[] { aDescription }, aTextures); + } + + public GT_MetaTileEntity_Hatch_Muffler(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + this(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Muffler(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public String[] getDescription() { + return description; + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_MUFFLER) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_MUFFLER) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Muffler(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isClientSide() && this.getBaseMetaTileEntity() + .isActive()) { + pollutionParticles( + this.getBaseMetaTileEntity() + .getWorld(), + ParticleFX.LARGE_SMOKE.toString()); + } + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @SideOnly(Side.CLIENT) + public void pollutionParticles(World aWorld, String name) { + boolean chk1, chk2, chk3; + float ran1 = XSTR_INSTANCE.nextFloat(), ran2, ran3; + chk1 = ran1 * 100 < calculatePollutionReduction(100); + if (GT_Pollution.getPollution(getBaseMetaTileEntity()) >= GT_Mod.gregtechproxy.mPollutionSmogLimit) { + ran2 = XSTR_INSTANCE.nextFloat(); + ran3 = XSTR_INSTANCE.nextFloat(); + chk2 = ran2 * 100 < calculatePollutionReduction(100); + chk3 = ran3 * 100 < calculatePollutionReduction(100); + if (!(chk1 || chk2 || chk3)) return; + } else { + if (!chk1) return; + ran2 = ran3 = 0.0F; + chk2 = chk3 = false; + } + + final IGregTechTileEntity aMuffler = this.getBaseMetaTileEntity(); + final ForgeDirection aDir = aMuffler.getFrontFacing(); + final float xPos = aDir.offsetX * 0.76F + aMuffler.getXCoord() + 0.25F; + final float yPos = aDir.offsetY * 0.76F + aMuffler.getYCoord() + 0.25F; + final float zPos = aDir.offsetZ * 0.76F + aMuffler.getZCoord() + 0.25F; + + final float ySpd = aDir.offsetY * 0.1F + 0.2F + 0.1F * XSTR_INSTANCE.nextFloat(); + final float xSpd; + final float zSpd; + + if (aDir.offsetY == -1) { + final float temp = XSTR_INSTANCE.nextFloat() * 2 * (float) Math.PI; + xSpd = (float) Math.sin(temp) * 0.1F; + zSpd = (float) Math.cos(temp) * 0.1F; + } else { + xSpd = aDir.offsetX * (0.1F + 0.2F * XSTR_INSTANCE.nextFloat()); + zSpd = aDir.offsetZ * (0.1F + 0.2F * XSTR_INSTANCE.nextFloat()); + } + + final WorldSpawnedEventBuilder.ParticleEventBuilder events = new WorldSpawnedEventBuilder.ParticleEventBuilder() + .setIdentifier(name) + .setWorld(aWorld) + .setMotion(xSpd, ySpd, zSpd); + + if (chk1) { + events + .setPosition( + xPos + ran1 * 0.5F, + yPos + XSTR_INSTANCE.nextFloat() * 0.5F, + zPos + XSTR_INSTANCE.nextFloat() * 0.5F) + .run(); + } + if (chk2) { + events + .setPosition( + xPos + ran2 * 0.5F, + yPos + XSTR_INSTANCE.nextFloat() * 0.5F, + zPos + XSTR_INSTANCE.nextFloat() * 0.5F) + .run(); + } + if (chk3) { + events + .setPosition( + xPos + ran3 * 0.5F, + yPos + XSTR_INSTANCE.nextFloat() * 0.5F, + zPos + XSTR_INSTANCE.nextFloat() * 0.5F) + .run(); + } + } + + public int calculatePollutionReduction(int aPollution) { + if (mTier < 2) { + return aPollution; + } + return (int) ((float) aPollution * ((100F - 12.5F * ((float) mTier - 1F)) / 100F)); + } + + /** + * @param mte The multi-block controller's {@link MetaTileEntity} MetaTileEntity is passed so newer muffler hatches + * can do wacky things with the multis + * @return pollution success + */ + public boolean polluteEnvironment(MetaTileEntity mte) { + if (getBaseMetaTileEntity().getAirAtSide(getBaseMetaTileEntity().getFrontFacing())) { + GT_Pollution.addPollution(getBaseMetaTileEntity(), calculatePollutionReduction(10000)); + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_MultiInput.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_MultiInput.java new file mode 100644 index 0000000000..cea2e25baa --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_MultiInput.java @@ -0,0 +1,305 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_INPUT_HATCH_2x2; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; + +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.fluid.FluidStackTank; +import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_Hatch_MultiInput extends GT_MetaTileEntity_Hatch_Input implements IAddUIWidgets { + + private final FluidStack[] mStoredFluid; + private final FluidStackTank[] fluidTanks; + public final int mCapacityPer; + + public GT_MetaTileEntity_Hatch_MultiInput(int aID, int aSlot, String aName, String aNameRegional, int aTier) { + super(aID, aSlot, aName, aNameRegional, aTier); + this.mStoredFluid = new FluidStack[aSlot]; + fluidTanks = new FluidStackTank[aSlot]; + mCapacityPer = getCapacityPerTank(aTier, aSlot); + } + + public GT_MetaTileEntity_Hatch_MultiInput(int aID, int aSlot, String aName, String aNameRegional, int aTier, + String[] aDescription) { + super(aID, aSlot, aName, aNameRegional, aTier, aDescription); + this.mStoredFluid = new FluidStack[aSlot]; + fluidTanks = new FluidStackTank[aSlot]; + mCapacityPer = getCapacityPerTank(aTier, aSlot); + } + + public GT_MetaTileEntity_Hatch_MultiInput(String aName, int aSlot, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aSlot, aTier, aDescription, aTextures); + this.mStoredFluid = new FluidStack[aSlot]; + fluidTanks = new FluidStackTank[aSlot]; + mCapacityPer = getCapacityPerTank(aTier, aSlot); + for (int i = 0; i < aSlot; i++) { + final int index = i; + fluidTanks[i] = new FluidStackTank( + () -> mStoredFluid[index], + fluid -> mStoredFluid[index] = fluid, + mCapacityPer); + } + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_MultiInput(mName, getMaxType(), mTier, mDescriptionArray, mTextures); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (mStoredFluid != null) { + for (int i = 0; i < mStoredFluid.length; i++) { + if (mStoredFluid[i] != null) + aNBT.setTag("mFluid" + i, mStoredFluid[i].writeToNBT(new NBTTagCompound())); + } + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (mStoredFluid != null) { + for (int i = 0; i < mStoredFluid.length; i++) { + if (aNBT.hasKey("mFluid" + i)) { + mStoredFluid[i] = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid" + i)); + } + } + } + } + + @Override + public boolean displaysStackSize() { + return true; + } + + public FluidStack[] getStoredFluid() { + return mStoredFluid; + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_INPUT_HATCH_2x2) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_INPUT_HATCH_2x2) }; + } + + public int getMaxType() { + return mStoredFluid.length; + } + + @Override + public FluidStack getFluid() { + for (FluidStack tFluid : mStoredFluid) { + if (tFluid != null && tFluid.amount > 0) return tFluid; + } + return null; + } + + public FluidStack getFluid(int aSlot) { + if (mStoredFluid == null || aSlot < 0 || aSlot >= getMaxType()) return null; + return mStoredFluid[aSlot]; + } + + @Override + public int getFluidAmount() { + if (getFluid() != null) { + return getFluid().amount; + } + return 0; + } + + @Override + public int getCapacity() { + return mCapacityPer; + } + + public int getFirstEmptySlot() { + for (int i = 0; i < mStoredFluid.length; i++) { + if (mStoredFluid[i] == null) return i; + } + return -1; + } + + public boolean hasFluid(FluidStack aFluid) { + if (aFluid == null) return false; + for (FluidStack tFluid : mStoredFluid) { + if (aFluid.isFluidEqual(tFluid)) return true; + } + return false; + } + + public int getFluidSlot(FluidStack tFluid) { + if (tFluid == null) return -1; + for (int i = 0; i < mStoredFluid.length; i++) { + if (tFluid.equals(mStoredFluid[i])) return i; + } + return -1; + } + + public int getFluidAmount(FluidStack tFluid) { + int tSlot = getFluidSlot(tFluid); + if (tSlot != -1) { + return mStoredFluid[tSlot].amount; + } + return 0; + } + + public void setFluid(FluidStack aFluid, int aSlot) { + if (aSlot < 0 || aSlot >= getMaxType()) return; + mStoredFluid[aSlot] = aFluid; + } + + public void addFluid(FluidStack aFluid, int aSlot) { + if (aSlot < 0 || aSlot >= getMaxType()) return; + if (aFluid.equals(mStoredFluid[aSlot])) mStoredFluid[aSlot].amount += aFluid.amount; + if (mStoredFluid[aSlot] == null) mStoredFluid[aSlot] = aFluid.copy(); + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + mFluid = getFluid(); + } + super.onPreTick(aBaseMetaTileEntity, aTick); + } + + @Override + public int fill(FluidStack aFluid, boolean doFill) { + if (aFluid == null || aFluid.getFluid() + .getID() <= 0 || aFluid.amount <= 0 || !canTankBeFilled() || !isFluidInputAllowed(aFluid)) return 0; + if (!hasFluid(aFluid) && getFirstEmptySlot() != -1) { + int tFilled = Math.min(aFluid.amount, mCapacityPer); + if (doFill) { + FluidStack tFluid = aFluid.copy(); + tFluid.amount = tFilled; + addFluid(tFluid, getFirstEmptySlot()); + getBaseMetaTileEntity().markDirty(); + } + return tFilled; + } + if (hasFluid(aFluid)) { + int tLeft = mCapacityPer - getFluidAmount(aFluid); + int tFilled = Math.min(tLeft, aFluid.amount); + if (doFill) { + FluidStack tFluid = aFluid.copy(); + tFluid.amount = tFilled; + addFluid(tFluid, getFluidSlot(tFluid)); + getBaseMetaTileEntity().markDirty(); + } + return tFilled; + } + return 0; + } + + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + if (getFluid() == null || !canTankBeEmptied()) return null; + if (getFluid().amount <= 0 && isFluidChangingAllowed()) { + setFluid(null, getFluidSlot(getFluid())); + getBaseMetaTileEntity().markDirty(); + return null; + } + FluidStack tRemove = getFluid().copy(); + tRemove.amount = Math.min(maxDrain, tRemove.amount); + if (doDrain) { + getFluid().amount -= tRemove.amount; + getBaseMetaTileEntity().markDirty(); + } + if (getFluid() == null || getFluid().amount <= 0 && isFluidChangingAllowed()) { + setFluid(null, getFluidSlot(getFluid())); + getBaseMetaTileEntity().markDirty(); + } + return tRemove; + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + return fill(resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack aFluid, boolean doDrain) { + if (aFluid == null || !hasFluid(aFluid)) return null; + FluidStack tStored = mStoredFluid[getFluidSlot(aFluid)]; + if (tStored.amount <= 0 && isFluidChangingAllowed()) { + setFluid(null, getFluidSlot(tStored)); + getBaseMetaTileEntity().markDirty(); + return null; + } + FluidStack tRemove = tStored.copy(); + tRemove.amount = Math.min(aFluid.amount, tRemove.amount); + if (doDrain) { + tStored.amount -= tRemove.amount; + getBaseMetaTileEntity().markDirty(); + } + if (tStored.amount <= 0 && isFluidChangingAllowed()) { + setFluid(null, getFluidSlot(tStored)); + getBaseMetaTileEntity().markDirty(); + } + return tRemove; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + FluidTankInfo[] FTI = new FluidTankInfo[getMaxType()]; + for (int i = 0; i < getMaxType(); i++) { + FTI[i] = new FluidTankInfo(mStoredFluid[i], mCapacityPer); + } + return FTI; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && mStoredFluid != null) { + for (int i = 0; i < getMaxType(); i++) { + if (mStoredFluid[i] != null && mStoredFluid[i].amount <= 0) { + mStoredFluid[i] = null; + } + } + } + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex >= 4; + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + final int SLOT_NUMBER = 4; + final Pos2d[] positions = new Pos2d[] { new Pos2d(70, 25), new Pos2d(88, 25), new Pos2d(70, 43), + new Pos2d(88, 43), }; + + for (int i = 0; i < SLOT_NUMBER; i++) { + builder.widget( + new FluidSlotWidget(fluidTanks[i]).setBackground(ModularUITextures.FLUID_SLOT) + .setPos(positions[i])); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java new file mode 100644 index 0000000000..fd83f6899b --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_Output.java @@ -0,0 +1,502 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.FLUID_OUT_SIGN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; + +import java.lang.ref.WeakReference; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; +import net.minecraftforge.fluids.IFluidHandler; + +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.GT_Mod; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.metatileentity.IFluidLockable; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.common.gui.modularui.widget.FluidLockWidget; + +public class GT_MetaTileEntity_Hatch_Output extends GT_MetaTileEntity_Hatch + implements IFluidStore, IFluidLockable, IAddUIWidgets { + + private String lockedFluidName = null; + private WeakReference<EntityPlayer> playerThatLockedfluid = null; + public byte mMode = 0; + + public GT_MetaTileEntity_Hatch_Output(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 4, + new String[] { "Fluid Output for Multiblocks", + "Capacity: " + GT_Utility.formatNumbers(8000L * (1L << aTier)) + "L", + "Right click with screwdriver to restrict output", + "Can be restricted to put out Items and/or Steam/No Steam/1 specific Fluid", + "Restricted Output Hatches are given priority for Multiblock Fluid output" }); + } + + public GT_MetaTileEntity_Hatch_Output(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 4, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Output(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 4, aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_Output(int aID, String aName, String aNameRegional, int aTier, String[] aDescription, + int inventorySize) { + super(aID, aName, aNameRegional, aTier, inventorySize, aDescription); + } + + public GT_MetaTileEntity_Hatch_Output(String name, int tier, int slots, String[] description, + ITexture[][][] textures) { + super(name, tier, slots, description, textures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(FLUID_OUT_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(FLUID_OUT_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isLiquidInput(ForgeDirection side) { + return false; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Output(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isAllowedToWork() && mFluid != null) { + IFluidHandler tTileEntity = aBaseMetaTileEntity + .getITankContainerAtSide(aBaseMetaTileEntity.getFrontFacing()); + if (tTileEntity != null) { + GT_Utility.moveFluid( + aBaseMetaTileEntity, + tTileEntity, + aBaseMetaTileEntity.getFrontFacing(), + Math.max(1, mFluid.amount), + null); + } + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setByte("mMode", mMode); + if (isFluidLocked() && lockedFluidName != null && lockedFluidName.length() != 0) + aNBT.setString("lockedFluidName", lockedFluidName); + else aNBT.removeTag("lockedFluidName"); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mMode = aNBT.getByte("mMode"); + if (isFluidLocked()) { + lockedFluidName = aNBT.getString("lockedFluidName"); + } + lockedFluidName = GT_Utility.isStringInvalid(lockedFluidName) ? null : lockedFluidName; + } + + @Override + public boolean doesFillContainers() { + return true; + } + + @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 false; + } + + public int getLockedDisplaySlot() { + return 3; + } + + @Override + public boolean isValidSlot(int aIndex) { + // Because getStackDisplaySlot() only allow return one int, this place I only can manually set. + return aIndex != getStackDisplaySlot() && aIndex != getLockedDisplaySlot(); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == aBaseMetaTileEntity.getFrontFacing() && aIndex == 1; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == aBaseMetaTileEntity.getFrontFacing() && aIndex == 0; + } + + @Override + public int getCapacity() { + return 8000 * (1 << mTier); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return; + if (aPlayer.isSneaking()) { + mMode = (byte) ((mMode + 9) % 10); + } else { + mMode = (byte) ((mMode + 1) % 10); + } + final String inBrackets; + switch (mMode) { + case 0 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("108", "Outputs misc. Fluids, Steam and Items")); + this.setLockedFluidName(null); + } + case 1 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("109", "Outputs Steam and Items")); + this.setLockedFluidName(null); + } + case 2 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("110", "Outputs Steam and misc. Fluids")); + this.setLockedFluidName(null); + } + case 3 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("111", "Outputs Steam")); + this.setLockedFluidName(null); + } + case 4 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("112", "Outputs misc. Fluids and Items")); + this.setLockedFluidName(null); + } + case 5 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("113", "Outputs only Items")); + this.setLockedFluidName(null); + } + case 6 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("114", "Outputs only misc. Fluids")); + this.setLockedFluidName(null); + } + case 7 -> { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("115", "Outputs nothing")); + this.setLockedFluidName(null); + } + case 8 -> { + playerThatLockedfluid = new WeakReference<>(aPlayer); + if (mFluid == null) { + this.setLockedFluidName(null); + inBrackets = GT_Utility.trans( + "115.3", + "currently none, will be locked to the next that is put in (or use fluid cell to lock)"); + } else { + this.setLockedFluidName( + this.getDrainableStack() + .getFluid() + .getName()); + inBrackets = this.getDrainableStack() + .getLocalizedName(); + } + GT_Utility.sendChatToPlayer( + aPlayer, + String.format( + "%s (%s)", + GT_Utility.trans("151.1", "Outputs items and 1 specific Fluid"), + inBrackets)); + } + case 9 -> { + playerThatLockedfluid = new WeakReference<>(aPlayer); + if (mFluid == null) { + this.setLockedFluidName(null); + inBrackets = GT_Utility.trans( + "115.3", + "currently none, will be locked to the next that is put in (or use fluid cell to lock)"); + } else { + this.setLockedFluidName( + this.getDrainableStack() + .getFluid() + .getName()); + inBrackets = this.getDrainableStack() + .getLocalizedName(); + } + GT_Utility.sendChatToPlayer( + aPlayer, + String.format("%s (%s)", GT_Utility.trans("151.2", "Outputs 1 specific Fluid"), inBrackets)); + } + } + } + + private boolean tryToLockHatch(EntityPlayer aPlayer, ForgeDirection side) { + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return false; + if (!isFluidLocked()) return false; + final ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem(); + if (tCurrentItem == null) return false; + FluidStack tFluid = FluidContainerRegistry.getFluidForFilledItem(tCurrentItem); + if (tFluid == null && tCurrentItem.getItem() instanceof IFluidContainerItem) + tFluid = ((IFluidContainerItem) tCurrentItem.getItem()).getFluid(tCurrentItem); + if (tFluid != null) { + if (getLockedFluidName() != null && !getLockedFluidName().equals( + tFluid.getFluid() + .getName())) { + GT_Utility.sendChatToPlayer( + aPlayer, + String.format( + "%s %s", + GT_Utility.trans( + "151.3", + "Hatch is locked to a different fluid. To change the locking, empty it and made it locked to the next fluid with a screwdriver. Currently locked to"), + StatCollector.translateToLocal(getLockedFluidName()))); + } else { + setLockedFluidName( + tFluid.getFluid() + .getName()); + if (mMode == 8) GT_Utility.sendChatToPlayer( + aPlayer, + String.format( + "%s (%s)", + GT_Utility.trans("151.1", "Outputs items and 1 specific Fluid"), + tFluid.getLocalizedName())); + else GT_Utility.sendChatToPlayer( + aPlayer, + String.format( + "%s (%s)", + GT_Utility.trans("151.2", "Outputs 1 specific Fluid"), + tFluid.getLocalizedName())); + } + return true; + } + return false; + } + + public byte getMode() { + return mMode; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (tryToLockHatch(aPlayer, side)) return true; + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + } + + public boolean outputsSteam() { + return mMode < 4; + } + + public boolean outputsLiquids() { + return mMode % 2 == 0 || mMode == 9; + } + + public boolean outputsItems() { + return mMode % 4 < 2 && mMode != 9; + } + + @Override + public String getLockedFluidName() { + return lockedFluidName; + } + + @Override + public void setLockedFluidName(String lockedFluidName) { + this.lockedFluidName = lockedFluidName; + markDirty(); + } + + @Override + public void lockFluid(boolean lock) { + if (lock) { + if (!isFluidLocked()) { + this.mMode = 9; + markDirty(); + } + } else { + this.mMode = 0; + setLockedFluidName(null); + markDirty(); + } + } + + @Override + public boolean isFluidLocked() { + return mMode == 8 || mMode == 9; + } + + @Override + public boolean acceptsFluidLock(String name) { + return true; + } + + @Override + public boolean isEmptyAndAcceptsAnyFluid() { + return mMode == 0 && getFluidAmount() == 0; + } + + @Override + public boolean canStoreFluid(@Nonnull FluidStack fluidStack) { + if (mFluid != null && !GT_Utility.areFluidsEqual(mFluid, fluidStack)) { + return false; + } + if (isFluidLocked()) { + if (lockedFluidName == null) { + return true; + } + return lockedFluidName.equals( + fluidStack.getFluid() + .getName()); + } + if (GT_ModHandler.isSteam(fluidStack)) { + return outputsSteam(); + } + return outputsLiquids(); + } + + @Override + public int getTankPressure() { + return +100; + } + + @Override + protected void onEmptyingContainerWhenEmpty() { + if (this.lockedFluidName == null && this.mFluid != null && isFluidLocked()) { + this.setLockedFluidName( + this.mFluid.getFluid() + .getName()); + final EntityPlayer player; + if (playerThatLockedfluid == null || (player = playerThatLockedfluid.get()) == null) return; + GT_Utility.sendChatToPlayer( + player, + String.format(GT_Utility.trans("151.4", "Successfully locked Fluid to %s"), mFluid.getLocalizedName())); + playerThatLockedfluid = null; + } + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + return new String[] { EnumChatFormatting.BLUE + "Output Hatch" + EnumChatFormatting.RESET, "Stored Fluid:", + EnumChatFormatting.GOLD + (mFluid == null ? "No Fluid" : mFluid.getLocalizedName()) + + EnumChatFormatting.RESET, + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(mFluid == null ? 0 : mFluid.amount) + + " L" + + EnumChatFormatting.RESET + + " " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(getCapacity()) + + " L" + + EnumChatFormatting.RESET, + (!isFluidLocked() || lockedFluidName == null) ? "Not Locked" + : ("Locked to " + StatCollector.translateToLocal( + FluidRegistry.getFluidStack(lockedFluidName, 1) + .getUnlocalizedName())) }; + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) + .setPos(98, 16) + .setSize(71, 45)) + .widget(new FluidLockWidget(this).setPos(149, 41)) + .widget( + new TextWidget("Locked Fluid").setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(101, 20)) + .widget(TextWidget.dynamicString(() -> { + FluidStack fluidStack = FluidRegistry.getFluidStack(lockedFluidName, 1); + return fluidStack != null ? fluidStack.getLocalizedName() : "None"; + }) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setTextAlignment(Alignment.CenterLeft) + .setMaxWidth(65) + .setPos(101, 30)) + .widget(new FakeSyncWidget.ByteSyncer(() -> mMode, val -> mMode = val)); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java new file mode 100644 index 0000000000..3bd92c6871 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_OutputBus.java @@ -0,0 +1,202 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.Textures.BlockIcons.ITEM_OUT_SIGN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; +import static gregtech.api.util.GT_Utility.moveMultipleItemStacks; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +import gregtech.GT_Mod; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.extensions.ArrayExt; + +public class GT_MetaTileEntity_Hatch_OutputBus extends GT_MetaTileEntity_Hatch implements IAddUIWidgets { + + public GT_MetaTileEntity_Hatch_OutputBus(int aID, String aName, String aNameRegional, int aTier) { + this(aID, aName, aNameRegional, aTier, getSlots(aTier)); + } + + public GT_MetaTileEntity_Hatch_OutputBus(int id, String name, String nameRegional, int tier, int slots) { + super( + id, + name, + nameRegional, + tier, + slots, + ArrayExt.of( + "Item Output for Multiblocks", + "Capacity: " + getSlots(tier) + " stack" + (getSlots(tier) >= 2 ? "s" : ""))); + } + + public GT_MetaTileEntity_Hatch_OutputBus(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription) { + super(aID, aName, aNameRegional, aTier, getSlots(aTier), aDescription); + } + + public GT_MetaTileEntity_Hatch_OutputBus(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription, int inventorySize) { + super(aID, aName, aNameRegional, aTier, inventorySize, aDescription); + } + + @Deprecated + // having too many constructors is bad, don't be so lazy, use GT_MetaTileEntity_Hatch_OutputBus(String, int, + // String[], ITexture[][][]) + public GT_MetaTileEntity_Hatch_OutputBus(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + this(aName, aTier, getSlots(aTier), ArrayExt.of(aDescription), aTextures); + } + + public GT_MetaTileEntity_Hatch_OutputBus(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, getSlots(aTier), aDescription, aTextures); + } + + public GT_MetaTileEntity_Hatch_OutputBus(String name, int tier, int slots, String[] description, + ITexture[][][] textures) { + super(name, tier, slots, description, textures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(ITEM_OUT_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return GT_Mod.gregtechproxy.mRenderIndicatorsOnHatch + ? new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(ITEM_OUT_SIGN) } + : new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_PIPE_OUT) }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_OutputBus(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + /** + * Attempt to store as many items as possible into the internal inventory of this output bus. If you need atomicity + * you should use {@link gregtech.api.interfaces.tileentity.IHasInventory#addStackToSlot(int, ItemStack)} + * + * @param aStack Assume valid. Will be mutated. Take over the ownership. Caller should not retain a reference to + * this stack if the call returns true. + * @return true if stack is fully accepted. false is stack is partially accepted or nothing is accepted + */ + public boolean storeAll(ItemStack aStack) { + markDirty(); + for (int i = 0, mInventoryLength = mInventory.length; i < mInventoryLength && aStack.stackSize > 0; i++) { + ItemStack tSlot = mInventory[i]; + if (GT_Utility.isStackInvalid(tSlot)) { + int tRealStackLimit = Math.min(getInventoryStackLimit(), aStack.getMaxStackSize()); + if (aStack.stackSize <= tRealStackLimit) { + mInventory[i] = aStack; + return true; + } + mInventory[i] = aStack.splitStack(tRealStackLimit); + } else { + int tRealStackLimit = Math.min(getInventoryStackLimit(), tSlot.getMaxStackSize()); + if (tSlot.stackSize < tRealStackLimit && tSlot.isItemEqual(aStack) + && ItemStack.areItemStackTagsEqual(tSlot, aStack)) { + if (aStack.stackSize + tSlot.stackSize <= tRealStackLimit) { + mInventory[i].stackSize += aStack.stackSize; + return true; + } else { + // more to serve + aStack.stackSize -= tRealStackLimit - tSlot.stackSize; + mInventory[i].stackSize = tRealStackLimit; + } + } + } + } + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == aBaseMetaTileEntity.getFrontFacing(); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isAllowedToWork() && (aTick & 0x7) == 0) { + final IInventory tTileEntity = aBaseMetaTileEntity + .getIInventoryAtSide(aBaseMetaTileEntity.getFrontFacing()); + if (tTileEntity != null) { + moveMultipleItemStacks( + aBaseMetaTileEntity, + tTileEntity, + aBaseMetaTileEntity.getFrontFacing(), + aBaseMetaTileEntity.getBackFacing(), + null, + false, + (byte) 64, + (byte) 1, + (byte) 64, + (byte) 1, + mInventory.length); + for (int i = 0; i < mInventory.length; i++) + if (mInventory[i] != null && mInventory[i].stackSize <= 0) mInventory[i] = null; + } + } + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + switch (mTier) { + case 0 -> getBaseMetaTileEntity().add1by1Slot(builder); + case 1 -> getBaseMetaTileEntity().add2by2Slots(builder); + case 2 -> getBaseMetaTileEntity().add3by3Slots(builder); + default -> getBaseMetaTileEntity().add4by4Slots(builder); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_QuadrupleHumongous.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_QuadrupleHumongous.java new file mode 100644 index 0000000000..e0ab7acf95 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Hatch_QuadrupleHumongous.java @@ -0,0 +1,27 @@ +package gregtech.api.metatileentity.implementations; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; + +public class GT_MetaTileEntity_Hatch_QuadrupleHumongous extends GT_MetaTileEntity_Hatch_MultiInput { + + public GT_MetaTileEntity_Hatch_QuadrupleHumongous(int aID, int aSlot, String aName, String aNameRegional) { + super(aID, aSlot, aName, aNameRegional, 13); + } + + public GT_MetaTileEntity_Hatch_QuadrupleHumongous(String aName, int aSlot, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aSlot, aTier, aDescription, aTextures); + } + + @Override + public int getCapacityPerTank(int aTier, int aSlot) { + return 500_000_000; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_QuadrupleHumongous(mName, getMaxType(), mTier, mDescriptionArray, mTextures); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java new file mode 100644 index 0000000000..32ea708773 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java @@ -0,0 +1,2540 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.util.GT_Utility.filterValidMTEs; +import static gregtech.api.util.GT_Utility.formatNumbers; +import static mcp.mobius.waila.api.SpecialChars.GREEN; +import static mcp.mobius.waila.api.SpecialChars.RED; +import static mcp.mobius.waila.api.SpecialChars.RESET; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.IntConsumer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +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.ApiStatus; +import org.jetbrains.annotations.TestOnly; +import org.lwjgl.input.Keyboard; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +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 cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ConfigCategories; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.VoidingMode; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.ControllerWithOptionalFeatures; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.modularui.IBindPlayerInventoryUI; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SingleRecipeCheck; +import gregtech.api.util.GT_ClientPreference; +import gregtech.api.util.GT_ExoticEnergyInputHelper; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Waila; +import gregtech.api.util.OutputHatchWrapper; +import gregtech.api.util.VoidProtectionHelper; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.client.GT_SoundLoop; +import gregtech.common.GT_Pollution; +import gregtech.common.gui.modularui.widget.CheckRecipeResultSyncer; +import gregtech.common.gui.modularui.widget.ShutDownReasonSyncer; +import gregtech.common.items.GT_MetaGenerated_Tool_01; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_CraftingInput_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Input_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; +import gregtech.common.tileentities.machines.IDualInputHatch; +import gregtech.common.tileentities.machines.IDualInputInventory; +import gregtech.common.tileentities.machines.IRecipeProcessingAwareHatch; +import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_LargeTurbine; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity + implements ControllerWithOptionalFeatures, IAddGregtechLogo, IAddUIWidgets, IBindPlayerInventoryUI { + + public static boolean disableMaintenance; + public boolean mMachine = false, mWrench = false, mScrewdriver = false, mSoftHammer = false, mHardHammer = false, + mSolderingTool = false, mCrowbar = false, mRunningOnLoad = false; + public boolean mStructureChanged = false; + public int mPollution = 0, mProgresstime = 0, mMaxProgresstime = 0, mEUt = 0, mEfficiencyIncrease = 0, + mStartUpCheck = 100, mRuntime = 0, mEfficiency = 0; + public volatile boolean mUpdated = false; + public int mUpdate = 0; + public ItemStack[] mOutputItems = null; + public FluidStack[] mOutputFluids = null; + public String mNEI; + public int damageFactorLow = 5; + public float damageFactorHigh = 0.6f; + + public boolean mLockedToSingleRecipe = getDefaultRecipeLockingMode(); + protected boolean inputSeparation = getDefaultInputSeparationMode(); + protected VoidingMode voidingMode = getDefaultVoidingMode(); + protected boolean batchMode = getDefaultBatchMode(); + private @Nonnull CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.NONE; + + protected static final String INPUT_SEPARATION_NBT_KEY = "inputSeparation"; + protected static final String VOID_EXCESS_NBT_KEY = "voidExcess"; + protected static final String VOIDING_MODE_NBT_KEY = "voidingMode"; + protected static final String BATCH_MODE_NBT_KEY = "batchMode"; + protected SingleRecipeCheck mSingleRecipeCheck = null; + + public ArrayList<GT_MetaTileEntity_Hatch_Input> mInputHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_Output> mOutputHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_InputBus> mInputBusses = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_OutputBus> mOutputBusses = new ArrayList<>(); + public ArrayList<IDualInputHatch> mDualInputHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_Dynamo> mDynamoHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_Muffler> mMufflerHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_Energy> mEnergyHatches = new ArrayList<>(); + public ArrayList<GT_MetaTileEntity_Hatch_Maintenance> mMaintenanceHatches = new ArrayList<>(); + protected List<GT_MetaTileEntity_Hatch> mExoticEnergyHatches = new ArrayList<>(); + protected final ProcessingLogic processingLogic; + @SideOnly(Side.CLIENT) + protected GT_SoundLoop activitySoundLoop; + + private long mLastWorkingTick = 0; + + protected static final byte INTERRUPT_SOUND_INDEX = 8; + protected static final byte PROCESS_START_SOUND_INDEX = 1; + + public GT_MetaTileEntity_MultiBlockBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, 2); + this.processingLogic = null; + GT_MetaTileEntity_MultiBlockBase.disableMaintenance = GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.disableMaintenance", false); + this.damageFactorLow = GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorLow", 5); + this.damageFactorHigh = (float) GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorHigh", 0.6f); + this.mNEI = ""; + } + + public GT_MetaTileEntity_MultiBlockBase(String aName) { + super(aName, 2); + this.processingLogic = createProcessingLogic(); + GT_MetaTileEntity_MultiBlockBase.disableMaintenance = GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.disableMaintenance", false); + this.damageFactorLow = GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorLow", 5); + this.damageFactorHigh = (float) GregTech_API.sMachineFile + .get(ConfigCategories.machineconfig, "MultiBlockMachines.damageFactorHigh", 0.6f); + } + + @Override + public boolean isDisplaySecondaryDescription() { + return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); + } + + @Override + public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) { + return side != getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (supportsSingleRecipeLocking()) { + mLockedToSingleRecipe = !mLockedToSingleRecipe; + if (mLockedToSingleRecipe) { + GT_Utility.sendChatToPlayer( + aPlayer, + GT_Utility.trans("223", "Single recipe locking enabled. Will lock to next recipe.")); + } else { + GT_Utility.sendChatToPlayer(aPlayer, GT_Utility.trans("220", "Single recipe locking disabled.")); + mSingleRecipeCheck = null; + } + } + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex > 0; + } + + @Override + public int getProgresstime() { + return mProgresstime; + } + + @Override + public int maxProgresstime() { + return mMaxProgresstime; + } + + @Override + public int increaseProgress(int aProgress) { + return aProgress; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setInteger("mEUt", mEUt); + aNBT.setInteger("mProgresstime", mProgresstime); + aNBT.setInteger("mMaxProgresstime", mMaxProgresstime); + aNBT.setInteger("mEfficiencyIncrease", mEfficiencyIncrease); + aNBT.setInteger("mEfficiency", mEfficiency); + aNBT.setInteger("mPollution", mPollution); + aNBT.setInteger("mRuntime", mRuntime); + if (supportsSingleRecipeLocking()) { + aNBT.setBoolean("mLockedToSingleRecipe", mLockedToSingleRecipe); + if (mLockedToSingleRecipe && mSingleRecipeCheck != null) + aNBT.setTag("mSingleRecipeCheck", mSingleRecipeCheck.writeToNBT()); + } + + if (mOutputItems != null) { + aNBT.setInteger("mOutputItemsLength", mOutputItems.length); + for (int i = 0; i < mOutputItems.length; i++) if (mOutputItems[i] != null) { + GT_Utility.saveItem(aNBT, "mOutputItem" + i, mOutputItems[i]); + } + } + if (mOutputFluids != null) { + aNBT.setInteger("mOutputFluidsLength", mOutputFluids.length); + for (int i = 0; i < mOutputFluids.length; i++) if (mOutputFluids[i] != null) { + NBTTagCompound tNBT = new NBTTagCompound(); + mOutputFluids[i].writeToNBT(tNBT); + aNBT.setTag("mOutputFluids" + i, tNBT); + } + } + aNBT.setBoolean("mWrench", mWrench); + aNBT.setBoolean("mScrewdriver", mScrewdriver); + aNBT.setBoolean("mSoftHammer", mSoftHammer); + aNBT.setBoolean("mHardHammer", mHardHammer); + aNBT.setBoolean("mSolderingTool", mSolderingTool); + aNBT.setBoolean("mCrowbar", mCrowbar); + aNBT.setBoolean(BATCH_MODE_NBT_KEY, batchMode); + aNBT.setBoolean(INPUT_SEPARATION_NBT_KEY, inputSeparation); + aNBT.setString(VOIDING_MODE_NBT_KEY, voidingMode.name); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + mEUt = aNBT.getInteger("mEUt"); + mProgresstime = aNBT.getInteger("mProgresstime"); + mMaxProgresstime = aNBT.getInteger("mMaxProgresstime"); + if (mMaxProgresstime > 0) mRunningOnLoad = true; + mEfficiencyIncrease = aNBT.getInteger("mEfficiencyIncrease"); + mEfficiency = aNBT.getInteger("mEfficiency"); + mPollution = aNBT.getInteger("mPollution"); + mRuntime = aNBT.getInteger("mRuntime"); + if (supportsSingleRecipeLocking()) { + mLockedToSingleRecipe = aNBT.getBoolean("mLockedToSingleRecipe"); + if (mLockedToSingleRecipe && aNBT.hasKey("mSingleRecipeCheck", Constants.NBT.TAG_COMPOUND)) { + SingleRecipeCheck c = loadSingleRecipeChecker(aNBT.getCompoundTag("mSingleRecipeCheck")); + if (c != null) mSingleRecipeCheck = c; + // the old recipe is gone. we disable the machine to prevent making garbage in case of shared inputs + // maybe use a better way to inform player in the future. + else getBaseMetaTileEntity().disableWorking(); + } + } + batchMode = aNBT.getBoolean(BATCH_MODE_NBT_KEY); + inputSeparation = aNBT.getBoolean(INPUT_SEPARATION_NBT_KEY); + if (aNBT.hasKey(VOIDING_MODE_NBT_KEY, Constants.NBT.TAG_STRING)) { + voidingMode = VoidingMode.fromName(aNBT.getString(VOIDING_MODE_NBT_KEY)); + } else if (aNBT.hasKey(VOID_EXCESS_NBT_KEY)) { + // backward compatibility + voidingMode = aNBT.getBoolean(VOID_EXCESS_NBT_KEY) ? VoidingMode.VOID_ALL : VoidingMode.VOID_NONE; + } + if (!getAllowedVoidingModes().contains(voidingMode)) voidingMode = getDefaultVoidingMode(); + + int aOutputItemsLength = aNBT.getInteger("mOutputItemsLength"); + if (aOutputItemsLength > 0) { + mOutputItems = new ItemStack[aOutputItemsLength]; + for (int i = 0; i < mOutputItems.length; i++) + mOutputItems[i] = GT_Utility.loadItem(aNBT, "mOutputItem" + i); + } + + int aOutputFluidsLength = aNBT.getInteger("mOutputFluidsLength"); + if (aOutputFluidsLength > 0) { + mOutputFluids = new FluidStack[aOutputFluidsLength]; + for (int i = 0; i < mOutputFluids.length; i++) + mOutputFluids[i] = GT_Utility.loadFluid(aNBT, "mOutputFluids" + i); + } + + mWrench = aNBT.getBoolean("mWrench"); + mScrewdriver = aNBT.getBoolean("mScrewdriver"); + mSoftHammer = aNBT.getBoolean("mSoftHammer"); + mHardHammer = aNBT.getBoolean("mHardHammer"); + mSolderingTool = aNBT.getBoolean("mSolderingTool"); + mCrowbar = aNBT.getBoolean("mCrowbar"); + } + + protected SingleRecipeCheck loadSingleRecipeChecker(NBTTagCompound aNBT) { + return SingleRecipeCheck.tryLoad(getRecipeMap(), aNBT); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public byte getTileEntityBaseType() { + return 2; + } + + /** + * Set the structure as having changed, and trigger an update. + */ + public void onStructureChange() { + mStructureChanged = true; + } + + @Override + public void onMachineBlockUpdate() { + mUpdated = true; + } + + /** + * ClearHatches as a part of structure check. If your multiblock has any hatches that need clearing override this + * method, call super, and clear your own hatches + */ + public void clearHatches() { + mInputHatches.clear(); + mInputBusses.clear(); + mOutputHatches.clear(); + mOutputBusses.clear(); + mDynamoHatches.clear(); + mEnergyHatches.clear(); + setMufflers(false); + mMufflerHatches.clear(); + mMaintenanceHatches.clear(); + mDualInputHatches.clear(); + } + + public boolean checkStructure(boolean aForceReset) { + return checkStructure(aForceReset, getBaseMetaTileEntity()); + } + + public boolean checkStructure(boolean aForceReset, IGregTechTileEntity aBaseMetaTileEntity) { + if (!aBaseMetaTileEntity.isServerSide()) return mMachine; + // Only trigger an update if forced (from onPostTick, generally), or if the structure has changed + if ((mStructureChanged || aForceReset)) { + clearHatches(); + mMachine = checkMachine(aBaseMetaTileEntity, mInventory[1]); + } + mStructureChanged = false; + return mMachine; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (mEfficiency < 0) mEfficiency = 0; + if (mUpdated) { + // duct tape fix for too many updates on an overloaded server, causing the structure check to not run + if (mUpdate <= 0) mUpdate = 50; + mUpdated = false; + } + if (--mUpdate == 0 || --mStartUpCheck == 0) { + checkStructure(true, aBaseMetaTileEntity); + } + + if (mStartUpCheck < 0) { + if (mMachine) { + checkMaintenance(); + if (getRepairStatus() > 0) { + runMachine(aBaseMetaTileEntity, aTick); + } else if (aBaseMetaTileEntity.isAllowedToWork()) { + stopMachine(ShutDownReasonRegistry.NO_REPAIR); + } + } else if (aBaseMetaTileEntity.isAllowedToWork()) { + stopMachine(ShutDownReasonRegistry.STRUCTURE_INCOMPLETE); + } + } + aBaseMetaTileEntity.setErrorDisplayID( + (aBaseMetaTileEntity.getErrorDisplayID() & ~127) | (mWrench ? 0 : 1) + | (mScrewdriver ? 0 : 2) + | (mSoftHammer ? 0 : 4) + | (mHardHammer ? 0 : 8) + | (mSolderingTool ? 0 : 16) + | (mCrowbar ? 0 : 32) + | (mMachine ? 0 : 64)); + aBaseMetaTileEntity.setActive(mMaxProgresstime > 0); + boolean active = aBaseMetaTileEntity.isActive() && mPollution > 0; + setMufflers(active); + } else { + if (!aBaseMetaTileEntity.hasMufflerUpgrade()) { + doActivitySound(getActivitySoundLoop()); + } + } + } + + @Override + public void onTickFail(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onTickFail(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide()) { + aBaseMetaTileEntity.disableWorking(); + checkRecipeResult = CheckRecipeResultRegistry.CRASH; + } + } + + private void checkMaintenance() { + if (disableMaintenance) { + mWrench = true; + mScrewdriver = true; + mSoftHammer = true; + mHardHammer = true; + mSolderingTool = true; + mCrowbar = true; + + return; + } + for (GT_MetaTileEntity_Hatch_Maintenance tHatch : filterValidMTEs(mMaintenanceHatches)) { + if (tHatch.mAuto && !(mWrench && mScrewdriver && mSoftHammer && mHardHammer && mSolderingTool && mCrowbar)) + tHatch.autoMaintainance(); + if (tHatch.mWrench) mWrench = true; + if (tHatch.mScrewdriver) mScrewdriver = true; + if (tHatch.mSoftHammer) mSoftHammer = true; + if (tHatch.mHardHammer) mHardHammer = true; + if (tHatch.mSolderingTool) mSolderingTool = true; + if (tHatch.mCrowbar) mCrowbar = true; + + tHatch.mWrench = false; + tHatch.mScrewdriver = false; + tHatch.mSoftHammer = false; + tHatch.mHardHammer = false; + tHatch.mSolderingTool = false; + tHatch.mCrowbar = false; + } + } + + /** + * Starts checking recipe with some operations needed to actually run the check. Overriding this without due care + * may result in dupe of items, hence it's marked as final. + * <p> + * See {@link #createProcessingLogic()} or {@link #checkProcessing()} for what you want to override. + * + * @return If successfully found recipe and/or started processing + */ + protected final boolean checkRecipe() { + startRecipeProcessing(); + CheckRecipeResult result = checkProcessing(); + if (!CheckRecipeResultRegistry.isRegistered(result.getID())) { + throw new RuntimeException(String.format("Result %s is not registered for registry", result.getID())); + } + if (result.wasSuccessful()) { + sendStartMultiBlockSoundLoop(); + } + this.checkRecipeResult = result; + endRecipeProcessing(); + // Don't use `result` here because `endRecipeProcessing()` might mutate `this.checkRecipeResult` + return this.checkRecipeResult.wasSuccessful(); + } + + private boolean shouldCheckRecipeThisTick(long aTick) { + // do a recipe check if any crafting input hatch just got pushed in items + boolean shouldCheck = false; + // check all of them (i.e. do not return early) to reset the state of all of them. + for (IDualInputHatch craftingInputMe : mDualInputHatches) { + shouldCheck |= craftingInputMe.justUpdated(); + } + if (shouldCheck) return true; + + // Perform more frequent recipe change after the machine just shuts down. + long timeElapsed = aTick - mLastWorkingTick; + + if (timeElapsed >= 100) return aTick % 100 == 0; + // Batch mode should be a lot less aggressive at recipe checking + if (!isBatchModeEnabled()) { + return timeElapsed == 5 || timeElapsed == 12 + || timeElapsed == 20 + || timeElapsed == 30 + || timeElapsed == 40 + || timeElapsed == 55 + || timeElapsed == 70 + || timeElapsed == 85; + } + return false; + } + + protected void runMachine(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (mMaxProgresstime > 0 && doRandomMaintenanceDamage()) { + if (onRunningTick(mInventory[1])) { + markDirty(); + if (!polluteEnvironment(getPollutionPerTick(mInventory[1]))) { + stopMachine(ShutDownReasonRegistry.POLLUTION_FAIL); + } + if (mMaxProgresstime > 0 && ++mProgresstime >= mMaxProgresstime) { + if (mOutputItems != null) { + for (ItemStack tStack : mOutputItems) { + if (tStack != null) { + try { + GT_Mod.achievements.issueAchivementHatch( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + tStack); + } catch (Exception ignored) {} + addOutput(tStack); + } + } + mOutputItems = null; + } + if (mOutputFluids != null) { + addFluidOutputs(mOutputFluids); + if (mOutputFluids.length > 1) { + try { + GT_Mod.achievements.issueAchievement( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + "oilplant"); + } catch (Exception ignored) {} + } + mOutputFluids = null; + } + mEfficiency = Math.max( + 0, + Math.min( + mEfficiency + mEfficiencyIncrease, + getMaxEfficiency(mInventory[1]) - ((getIdealStatus() - getRepairStatus()) * 1000))); + mOutputItems = null; + mProgresstime = 0; + mMaxProgresstime = 0; + mEfficiencyIncrease = 0; + mLastWorkingTick = aTick; + if (aBaseMetaTileEntity.isAllowedToWork()) { + checkRecipe(); + } + } + } + } else { + if (shouldCheckRecipeThisTick(aTick) || aBaseMetaTileEntity.hasWorkJustBeenEnabled() + || aBaseMetaTileEntity.hasInventoryBeenModified()) { + + if (aBaseMetaTileEntity.isAllowedToWork()) { + if (checkRecipe()) { + markDirty(); + } + } + if (mMaxProgresstime <= 0) mEfficiency = Math.max(0, mEfficiency - 1000); + } + } + } + + public boolean polluteEnvironment(int aPollutionLevel) { + mPollution += aPollutionLevel; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + if (mPollution >= 10000) { + if (tHatch.polluteEnvironment(this)) { + mPollution -= 10000; + } + } else { + break; + } + } + return mPollution < 10000; + } + + protected void sendStartMultiBlockSoundLoop() { + if (getProcessStartSound() != null) { + sendLoopStart(PROCESS_START_SOUND_INDEX); + } + } + + @Override + public void doSound(byte aIndex, double aX, double aY, double aZ) { + super.doSound(aIndex, aX, aY, aZ); + switch (aIndex) { + case PROCESS_START_SOUND_INDEX -> { + if (getProcessStartSound() != null) + GT_Utility.doSoundAtClient(getProcessStartSound(), getTimeBetweenProcessSounds(), 1.0F, aX, aY, aZ); + } + case INTERRUPT_SOUND_INDEX -> GT_Utility + .doSoundAtClient(SoundResource.IC2_MACHINES_INTERRUPT_ONE, 100, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == PROCESS_START_SOUND_INDEX) { + if (getProcessStartSound() != null) + GT_Utility.doSoundAtClient(getProcessStartSound(), getTimeBetweenProcessSounds(), 1.0F, aX, aY, aZ); + } + } + + @SideOnly(Side.CLIENT) + protected void doActivitySound(ResourceLocation activitySound) { + if (getBaseMetaTileEntity().isActive() && activitySound != null) { + if (activitySoundLoop == null) { + activitySoundLoop = new GT_SoundLoop(activitySound, getBaseMetaTileEntity(), false, true); + Minecraft.getMinecraft() + .getSoundHandler() + .playSound(activitySoundLoop); + } + } else { + if (activitySoundLoop != null) { + activitySoundLoop = null; + } + } + } + + /** + * @return Time before the start process sound is played again + */ + protected int getTimeBetweenProcessSounds() { + return 100; + } + + /** + * @return Sound that will be played once, when the recipe check was valid + */ + protected SoundResource getProcessStartSound() { + return null; + } + + /** + * @return Sound that will be looped for as long as the machine is doing a recipe + */ + @SideOnly(Side.CLIENT) + protected ResourceLocation getActivitySoundLoop() { + return null; + } + + /** + * Called every tick the Machine runs + */ + public boolean onRunningTick(ItemStack aStack) { + if (mEUt > 0) { + addEnergyOutput(((long) mEUt * mEfficiency) / 10000); + return true; + } + if (mEUt < 0) { + if (!drainEnergyInput(getActualEnergyUsage())) { + stopMachine(ShutDownReasonRegistry.POWER_LOSS); + return false; + } + } + return true; + } + + protected long getActualEnergyUsage() { + return ((long) -mEUt * 10_000) / Math.max(1000, mEfficiency); + } + + /** + * Checks if this is a Correct Machine Part for this kind of Machine (Turbine Rotor for example) + */ + public abstract boolean isCorrectMachinePart(ItemStack aStack); + + /** + * @deprecated Use {@link #createProcessingLogic()} or {@link #checkProcessing()} + */ + @Deprecated + public boolean checkRecipe(ItemStack aStack) { + return false; + } + + /** + * Checks recipe and setup machine if it's successful. + * <p> + * For generic machine working with recipemap, use {@link #createProcessingLogic()} to make use of shared codebase. + */ + @Nonnull + public CheckRecipeResult checkProcessing() { + // If no logic is found, try legacy checkRecipe + if (processingLogic == null) { + return checkRecipe(mInventory[1]) ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; + } + + setupProcessingLogic(processingLogic); + + CheckRecipeResult result = doCheckRecipe(); + result = postCheckRecipe(result, processingLogic); + // inputs are consumed at this point + updateSlots(); + if (!result.wasSuccessful()) return result; + + mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + mEfficiencyIncrease = 10000; + mMaxProgresstime = processingLogic.getDuration(); + setEnergyUsage(processingLogic); + + mOutputItems = processingLogic.getOutputItems(); + mOutputFluids = processingLogic.getOutputFluids(); + + return result; + } + + /** + * @return If controller slot should be considered as inputs for {@link #doCheckRecipe} + */ + protected boolean canUseControllerSlotForRecipe() { + return true; + } + + /** + * Initializes processing logic for use. Unlike {@link #createProcessingLogic}, this method is called + * every time checking for recipes. + */ + protected void setupProcessingLogic(ProcessingLogic logic) { + logic.clear(); + logic.setMachine(this); + logic.setRecipeMapSupplier(this::getRecipeMap); + logic.setVoidProtection(protectsExcessItem(), protectsExcessFluid()); + logic.setBatchSize(isBatchModeEnabled() ? getMaxBatchSize() : 1); + logic.setRecipeLocking(this, isRecipeLockingEnabled()); + setProcessingLogicPower(logic); + } + + /** + * Initializes processing logic for use, specifically for power-related parameters. + * Unlike {@link #createProcessingLogic}, this method is called every time checking for recipes. + */ + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(getAverageInputVoltage()); + logic.setAvailableAmperage(getMaxInputAmps()); + logic.setAmperageOC(mEnergyHatches.size() != 1); + } + + protected boolean supportsCraftingMEBuffer() { + return true; + } + + /** + * Iterates over hatches and tries to find recipe. Assume {@link #processingLogic} is already set up for use. + * If return value is successful, inputs are consumed. + */ + @Nonnull + protected CheckRecipeResult doCheckRecipe() { + CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE; + // check crafting input hatches first + if (supportsCraftingMEBuffer()) { + for (IDualInputHatch dualInputHatch : mDualInputHatches) { + for (var it = dualInputHatch.inventories(); it.hasNext();) { + IDualInputInventory slot = it.next(); + processingLogic.setInputItems(slot.getItemInputs()); + processingLogic.setInputFluids(slot.getFluidInputs()); + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + result = foundResult; + } + } + } + } + + processingLogic.setInputFluids(getStoredFluids()); + + if (isInputSeparationEnabled()) { + if (mInputBusses.isEmpty()) { + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + result = foundResult; + } + } else { + for (GT_MetaTileEntity_Hatch_InputBus bus : mInputBusses) { + if (bus instanceof GT_MetaTileEntity_Hatch_CraftingInput_ME) { + continue; + } + List<ItemStack> inputItems = new ArrayList<>(); + for (int i = bus.getSizeInventory() - 1; i >= 0; i--) { + ItemStack stored = bus.getStackInSlot(i); + if (stored != null) { + inputItems.add(stored); + } + } + if (canUseControllerSlotForRecipe() && getControllerSlot() != null) { + inputItems.add(getControllerSlot()); + } + processingLogic.setInputItems(inputItems.toArray(new ItemStack[0])); + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that and continue searching + result = foundResult; + } + } + } + } else { + List<ItemStack> inputItems = getStoredInputs(); + if (canUseControllerSlotForRecipe() && getControllerSlot() != null) { + inputItems.add(getControllerSlot()); + } + processingLogic.setInputItems(inputItems); + CheckRecipeResult foundResult = processingLogic.process(); + if (foundResult.wasSuccessful()) { + return foundResult; + } + if (foundResult != CheckRecipeResultRegistry.NO_RECIPE) { + // Recipe failed in interesting way, so remember that + result = foundResult; + } + } + return result; + } + + /** + * Performs additional check for {@link #processingLogic} after all the calculations are done. + * As many as checks should be done inside of custom {@link ProcessingLogic}, which you can specify with + * {@link #createProcessingLogic()}, because when this method is called, inputs might have been already consumed. + * However, certain checks cannot be done like that; Checking energy overflow should be suppressed for + * long-power machines for example. + * + * @return Modified (or not modified) result + */ + @Nonnull + protected CheckRecipeResult postCheckRecipe(@Nonnull CheckRecipeResult result, + @Nonnull ProcessingLogic processingLogic) { + if (result.wasSuccessful() && processingLogic.getCalculatedEut() > Integer.MAX_VALUE) { + return CheckRecipeResultRegistry.POWER_OVERFLOW; + } + return result; + } + + /** + * Called after {@link #doCheckRecipe} and {@link #postCheckRecipe} being successful. + * Override to set energy usage for this machine. + */ + protected void setEnergyUsage(ProcessingLogic processingLogic) { + // getCalculatedEut() is guaranteed to not exceed int by postCheckRecipe() + mEUt = (int) processingLogic.getCalculatedEut(); + if (mEUt > 0) { + mEUt = (-mEUt); + } + } + + protected int getMaxBatchSize() { + return 128; + } + + /** + * Checks the Machine. You have to assign the MetaTileEntities for the Hatches here. + */ + public abstract boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack); + + /** + * Gets the maximum Efficiency that spare Part can get (0 - 10000) + */ + public abstract int getMaxEfficiency(ItemStack aStack); + + /** + * Gets the pollution this Device outputs to a Muffler per tick (10000 = one Pullution Block) + */ + public int getPollutionPerTick(ItemStack aStack) { + return getPollutionPerSecond(aStack) / 20; + } + + /** + * Gets the pollution produced per second by this multiblock, default to 0. Override this with its actual value in + * the code of the multiblock. + */ + public int getPollutionPerSecond(ItemStack aStack) { + return 0; + } + + /** + * Gets the damage to the ItemStack, usually 0 or 1. + */ + public abstract int getDamageToComponent(ItemStack aStack); + + /** + * If it explodes when the Component has to be replaced. + */ + public abstract boolean explodesOnComponentBreak(ItemStack aStack); + + /** + * @deprecated Use {@link #stopMachine(ShutDownReason)} + */ + @Deprecated + public void stopMachine() { + stopMachine(ShutDownReasonRegistry.NONE); + } + + /** + * @deprecated Use {@link #stopMachine(ShutDownReason)} + */ + @Deprecated + public void criticalStopMachine() { + stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + } + + public void stopMachine(@Nonnull ShutDownReason reason) { + if (!ShutDownReasonRegistry.isRegistered(reason.getID())) { + throw new RuntimeException(String.format("Reason %s is not registered for registry", reason.getID())); + } + mOutputItems = null; + mOutputFluids = null; + mEUt = 0; + mEfficiency = 0; + mProgresstime = 0; + mMaxProgresstime = 0; + mEfficiencyIncrease = 0; + getBaseMetaTileEntity().disableWorking(); + getBaseMetaTileEntity().setShutDownReason(reason); + getBaseMetaTileEntity().setShutdownStatus(true); + if (reason.wasCritical()) { + sendSound(INTERRUPT_SOUND_INDEX); + } + } + + public int getRepairStatus() { + return (mWrench ? 1 : 0) + (mScrewdriver ? 1 : 0) + + (mSoftHammer ? 1 : 0) + + (mHardHammer ? 1 : 0) + + (mSolderingTool ? 1 : 0) + + (mCrowbar ? 1 : 0); + } + + public int getIdealStatus() { + return 6; + } + + public int getCurrentEfficiency(ItemStack itemStack) { + int maxEff = getMaxEfficiency(itemStack); + return maxEff - (getIdealStatus() - getRepairStatus()) * maxEff / 10; + } + + public boolean doRandomMaintenanceDamage() { + if (!isCorrectMachinePart(mInventory[1])) { + stopMachine(ShutDownReasonRegistry.NO_MACHINE_PART); + return false; + } + if (getRepairStatus() == 0) { + stopMachine(ShutDownReasonRegistry.NO_REPAIR); + return false; + } + if (mRuntime++ > 1000) { + mRuntime = 0; + if (getBaseMetaTileEntity().getRandomNumber(6000) == 0) { + switch (getBaseMetaTileEntity().getRandomNumber(6)) { + case 0 -> mWrench = false; + case 1 -> mScrewdriver = false; + case 2 -> mSoftHammer = false; + case 3 -> mHardHammer = false; + case 4 -> mSolderingTool = false; + case 5 -> mCrowbar = false; + } + } + if (mInventory[1] != null && getBaseMetaTileEntity().getRandomNumber(2) == 0 + && !mInventory[1].getUnlocalizedName() + .startsWith("gt.blockmachines.basicmachine.")) { + if (mInventory[1].getItem() instanceof GT_MetaGenerated_Tool_01) { + NBTTagCompound tNBT = mInventory[1].getTagCompound(); + ((GT_MetaGenerated_Tool) mInventory[1].getItem()).doDamage( + mInventory[1], + (long) getDamageToComponent(mInventory[1]) + * (long) Math.min(mEUt / this.damageFactorLow, Math.pow(mEUt, this.damageFactorHigh))); + if (mInventory[1].stackSize == 0) mInventory[1] = null; + } + } + } + return true; + } + + public void explodeMultiblock() { + + GT_Log.exp.println( + "MultiBlockExplosion at: " + this.getBaseMetaTileEntity() + .getXCoord() + + " | " + + this.getBaseMetaTileEntity() + .getYCoord() + + " | " + + this.getBaseMetaTileEntity() + .getZCoord() + + " DIMID: " + + this.getBaseMetaTileEntity() + .getWorld().provider.dimensionId + + "."); + + GT_Pollution.addPollution(getBaseMetaTileEntity(), GT_Mod.gregtechproxy.mPollutionOnExplosion); + mInventory[1] = null; + // noinspection unchecked // In this case, the inspection only indicates that the array can be abused in runtime + Iterable<MetaTileEntity> allHatches = Iterables.concat( + mInputBusses, + mOutputBusses, + mInputHatches, + mOutputHatches, + mDynamoHatches, + mMufflerHatches, + mEnergyHatches, + mMaintenanceHatches); + for (MetaTileEntity tTileEntity : allHatches) { + if (tTileEntity != null && tTileEntity.getBaseMetaTileEntity() != null) { + tTileEntity.getBaseMetaTileEntity() + .doExplosion(V[8]); + } + } + getBaseMetaTileEntity().doExplosion(V[8]); + } + + public boolean addEnergyOutput(long aEU) { + if (aEU <= 0) { + return true; + } + if (mDynamoHatches.size() > 0) { + return addEnergyOutputMultipleDynamos(aEU, true); + } + return false; + } + + public boolean addEnergyOutputMultipleDynamos(long aEU, boolean aAllowMixedVoltageDynamos) { + int injected = 0; + long totalOutput = 0; + long aFirstVoltageFound = -1; + boolean aFoundMixedDynamos = false; + for (GT_MetaTileEntity_Hatch_Dynamo aDynamo : filterValidMTEs(mDynamoHatches)) { + long aVoltage = aDynamo.maxEUOutput(); + long aTotal = aDynamo.maxAmperesOut() * aVoltage; + // Check against voltage to check when hatch mixing + if (aFirstVoltageFound == -1) { + aFirstVoltageFound = aVoltage; + } else { + if (aFirstVoltageFound != aVoltage) { + aFoundMixedDynamos = true; + } + } + totalOutput += aTotal; + } + + if (totalOutput < aEU || (aFoundMixedDynamos && !aAllowMixedVoltageDynamos)) { + explodeMultiblock(); + return false; + } + + long leftToInject; + long aVoltage; + int aAmpsToInject; + int aRemainder; + int ampsOnCurrentHatch; + for (GT_MetaTileEntity_Hatch_Dynamo aDynamo : filterValidMTEs(mDynamoHatches)) { + leftToInject = aEU - injected; + aVoltage = aDynamo.maxEUOutput(); + aAmpsToInject = (int) (leftToInject / aVoltage); + aRemainder = (int) (leftToInject - (aAmpsToInject * aVoltage)); + ampsOnCurrentHatch = (int) Math.min(aDynamo.maxAmperesOut(), aAmpsToInject); + for (int i = 0; i < ampsOnCurrentHatch; i++) { + aDynamo.getBaseMetaTileEntity() + .increaseStoredEnergyUnits(aVoltage, false); + } + injected += aVoltage * ampsOnCurrentHatch; + if (aRemainder > 0 && ampsOnCurrentHatch < aDynamo.maxAmperesOut()) { + aDynamo.getBaseMetaTileEntity() + .increaseStoredEnergyUnits(aRemainder, false); + injected += aRemainder; + } + } + return injected > 0; + } + + /** + * Sums up voltage of energy hatches. Amperage does not matter. + */ + public long getMaxInputVoltage() { + long rVoltage = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) + rVoltage += tHatch.getBaseMetaTileEntity() + .getInputVoltage(); + return rVoltage; + } + + public long getAverageInputVoltage() { + return GT_ExoticEnergyInputHelper.getAverageInputVoltageMulti(mEnergyHatches); + } + + public long getMaxInputAmps() { + return GT_ExoticEnergyInputHelper.getMaxWorkingInputAmpsMulti(mEnergyHatches); + } + + public long getMaxInputEu() { + return GT_ExoticEnergyInputHelper.getTotalEuMulti(mEnergyHatches); + } + + /** + * Sums up max input EU/t of energy hatches, amperage included. + */ + public long getMaxInputPower() { + long eut = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + IGregTechTileEntity baseTile = tHatch.getBaseMetaTileEntity(); + eut += baseTile.getInputVoltage() * baseTile.getInputAmperage(); + } + return eut; + } + + /** + * Returns voltage tier of energy hatches. If multiple tiers are found, returns 0. + */ + public long getInputVoltageTier() { + long rTier = 0; + if (mEnergyHatches.size() > 0) { + rTier = mEnergyHatches.get(0) + .getInputTier(); + for (int i = 1; i < mEnergyHatches.size(); i++) { + if (mEnergyHatches.get(i) + .getInputTier() != rTier) return 0; + } + } + + return rTier; + } + + /** + * Calcualtes the overclockedness using long integers + * + * @param aEUt - recipe EUt + * @param aDuration - recipe Duration + * @param mAmperage - should be 1 ? + * @param maxInputVoltage - Multiblock Max input voltage. Voltage is rounded up to higher tier voltage. + * @param perfectOC - If the Multiblock OCs perfectly, i.e. the large Chemical Reactor + */ + protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, + boolean perfectOC) { + byte tier = (byte) Math.max(0, GT_Utility.getTier(maxInputVoltage)); + GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(aEUt) + .setEUt(V[tier] * mAmperage) + .setDuration(aDuration) + .setDurationDecreasePerOC(perfectOC ? 2 : 1) + .calculate(); + mEUt = (int) calculator.getConsumption(); + mMaxProgresstime = calculator.getDuration(); + } + + @Deprecated + protected void calculateOverclockedNessMulti(int aEUt, int aDuration, int mAmperage, long maxInputVoltage) { + calculateOverclockedNessMultiInternal(aEUt, aDuration, mAmperage, maxInputVoltage, false); + } + + protected void calculateOverclockedNessMulti(long aEUt, int aDuration, int mAmperage, long maxInputVoltage) { + calculateOverclockedNessMultiInternal(aEUt, aDuration, mAmperage, maxInputVoltage, false); + } + + @Deprecated + protected void calculatePerfectOverclockedNessMulti(int aEUt, int aDuration, int mAmperage, long maxInputVoltage) { + calculateOverclockedNessMultiInternal(aEUt, aDuration, mAmperage, maxInputVoltage, true); + } + + protected void calculatePerfectOverclockedNessMulti(long aEUt, int aDuration, int mAmperage, long maxInputVoltage) { + calculateOverclockedNessMultiInternal(aEUt, aDuration, mAmperage, maxInputVoltage, true); + } + + public boolean drainEnergyInput(long aEU) { + if (aEU <= 0) return true; + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + if (tHatch.getBaseMetaTileEntity() + .decreaseStoredEnergyUnits(aEU, false)) return true; + } + return false; + } + + protected static boolean dumpFluid(List<GT_MetaTileEntity_Hatch_Output> aOutputHatches, FluidStack copiedFluidStack, + boolean restrictiveHatchesOnly) { + for (GT_MetaTileEntity_Hatch_Output tHatch : filterValidMTEs(aOutputHatches)) { + if (restrictiveHatchesOnly && tHatch.mMode == 0) { + continue; + } + if (!tHatch.canStoreFluid(copiedFluidStack)) continue; + int tAmount = tHatch.fill(copiedFluidStack, false); + if (tAmount >= copiedFluidStack.amount) { + boolean filled = tHatch.fill(copiedFluidStack, true) >= copiedFluidStack.amount; + tHatch.onEmptyingContainerWhenEmpty(); + return filled; + } else if (tAmount > 0) { + copiedFluidStack.amount = copiedFluidStack.amount - tHatch.fill(copiedFluidStack, true); + tHatch.onEmptyingContainerWhenEmpty(); + } + } + return false; + } + + public boolean addOutput(FluidStack aLiquid) { + if (aLiquid == null) return false; + FluidStack copiedFluidStack = aLiquid.copy(); + if (!dumpFluid(mOutputHatches, copiedFluidStack, true)) { + dumpFluid(mOutputHatches, copiedFluidStack, false); + } + return false; + } + + protected void addFluidOutputs(FluidStack[] mOutputFluids2) { + for (FluidStack outputFluidStack : mOutputFluids2) { + addOutput(outputFluidStack); + } + } + + public boolean depleteInput(FluidStack aLiquid) { + return depleteInput(aLiquid, false); + } + + public boolean depleteInput(FluidStack aLiquid, boolean simulate) { + if (aLiquid == null) return false; + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { + setHatchRecipeMap(tHatch); + FluidStack tLiquid = tHatch.drain(ForgeDirection.UNKNOWN, aLiquid, false); + if (tLiquid != null && tLiquid.amount >= aLiquid.amount) { + if (simulate) { + return true; + } + tLiquid = tHatch.drain(ForgeDirection.UNKNOWN, aLiquid, true); + return tLiquid != null && tLiquid.amount >= aLiquid.amount; + } + } + return false; + } + + public boolean addOutput(ItemStack aStack) { + if (GT_Utility.isStackInvalid(aStack)) return false; + aStack = GT_Utility.copyOrNull(aStack); + for (GT_MetaTileEntity_Hatch_OutputBus tHatch : filterValidMTEs(mOutputBusses)) { + if (tHatch.storeAll(aStack)) { + return true; + } + } + boolean outputSuccess = true; + while (outputSuccess && aStack.stackSize > 0) { + outputSuccess = false; + ItemStack single = aStack.splitStack(1); + for (GT_MetaTileEntity_Hatch_Output tHatch : filterValidMTEs(mOutputHatches)) { + if (!outputSuccess && tHatch.outputsItems()) { + if (tHatch.getBaseMetaTileEntity() + .addStackToSlot(1, single)) outputSuccess = true; + } + } + } + return outputSuccess; + } + + public boolean depleteInput(ItemStack aStack) { + if (GT_Utility.isStackInvalid(aStack)) return false; + FluidStack aLiquid = GT_Utility.getFluidForFilledItem(aStack, true); + if (aLiquid != null) return depleteInput(aLiquid); + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { + setHatchRecipeMap(tHatch); + if (GT_Utility.areStacksEqual( + aStack, + tHatch.getBaseMetaTileEntity() + .getStackInSlot(0))) { + if (tHatch.getBaseMetaTileEntity() + .getStackInSlot(0).stackSize >= aStack.stackSize) { + tHatch.getBaseMetaTileEntity() + .decrStackSize(0, aStack.stackSize); + return true; + } + } + } + for (GT_MetaTileEntity_Hatch_InputBus tHatch : filterValidMTEs(mInputBusses)) { + tHatch.mRecipeMap = getRecipeMap(); + for (int i = tHatch.getBaseMetaTileEntity() + .getSizeInventory() - 1; i >= 0; i--) { + if (GT_Utility.areStacksEqual( + aStack, + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i))) { + if (tHatch.getBaseMetaTileEntity() + .getStackInSlot(i).stackSize >= aStack.stackSize) { + tHatch.getBaseMetaTileEntity() + .decrStackSize(i, aStack.stackSize); + return true; + } + } + } + } + return false; + } + + public ArrayList<ItemStack> getStoredOutputs() { + ArrayList<ItemStack> rList = new ArrayList<>(); + for (GT_MetaTileEntity_Hatch_OutputBus tHatch : filterValidMTEs(mOutputBusses)) { + for (int i = tHatch.getBaseMetaTileEntity() + .getSizeInventory() - 1; i >= 0; i--) { + rList.add( + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i)); + } + } + return rList; + } + + public ArrayList<FluidStack> getStoredFluids() { + ArrayList<FluidStack> rList = new ArrayList<>(); + Map<Fluid, FluidStack> inputsFromME = new HashMap<>(); + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { + setHatchRecipeMap(tHatch); + if (tHatch instanceof GT_MetaTileEntity_Hatch_MultiInput multiInputHatch) { + for (FluidStack tFluid : multiInputHatch.getStoredFluid()) { + if (tFluid != null) { + rList.add(tFluid); + } + } + } else if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + for (FluidStack fluidStack : meHatch.getStoredFluids()) { + if (fluidStack != null) { + // Prevent the same fluid from different ME hatches from being recognized + inputsFromME.put(fluidStack.getFluid(), fluidStack); + } + } + } else { + if (tHatch.getFillableStack() != null) { + rList.add(tHatch.getFillableStack()); + } + } + } + + if (!inputsFromME.isEmpty()) { + rList.addAll(inputsFromME.values()); + } + return rList; + } + + /** + * Drains fluid from the given hatch, including {@link IDualInputHatch}. Should never be used during recipe check! + * + * @param doDrain If false, fluid will not actually be consumed + * @return Whether the hatch contains enough fluid to drain + */ + public boolean drain(GT_MetaTileEntity_Hatch hatch, FluidStack fluid, boolean doDrain) { + if (fluid == null || hatch == null) return false; + if (supportsCraftingMEBuffer() && hatch instanceof IDualInputHatch tHatch && tHatch.supportsFluids()) { + Optional<IDualInputInventory> inventory = tHatch.getFirstNonEmptyInventory(); + if (inventory.isPresent()) { + for (FluidStack storedFluid : Lists.newArrayList( + inventory.get() + .getFluidInputs())) { + if (fluid.isFluidEqual(storedFluid)) { + if (doDrain) storedFluid.amount = Math.max(storedFluid.amount - fluid.amount, 0); + return storedFluid.amount >= fluid.amount; + } + } + } + } + + if (hatch instanceof GT_MetaTileEntity_Hatch_Input tHatch && tHatch.isValid()) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + meHatch.startRecipeProcessing(); + FluidStack tFluid = meHatch.drain(ForgeDirection.UNKNOWN, fluid, doDrain); + meHatch.endRecipeProcessing(this); + return tFluid != null && tFluid.amount >= fluid.amount; + } else { + FluidStack tFluid = tHatch.drain(ForgeDirection.UNKNOWN, fluid, doDrain); + return tFluid != null && tFluid.amount >= fluid.amount; + } + } + + return false; + } + + public ArrayList<ItemStack> getStoredInputs() { + ArrayList<ItemStack> rList = new ArrayList<>(); + Map<GT_Utility.ItemId, ItemStack> inputsFromME = new HashMap<>(); + for (GT_MetaTileEntity_Hatch_InputBus tHatch : filterValidMTEs(mInputBusses)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_CraftingInput_ME) { + continue; + } + tHatch.mRecipeMap = getRecipeMap(); + IGregTechTileEntity tileEntity = tHatch.getBaseMetaTileEntity(); + boolean isMEBus = tHatch instanceof GT_MetaTileEntity_Hatch_InputBus_ME; + for (int i = tileEntity.getSizeInventory() - 1; i >= 0; i--) { + ItemStack itemStack = tileEntity.getStackInSlot(i); + if (itemStack != null) { + if (isMEBus) { + // Prevent the same item from different ME buses from being recognized + inputsFromME.put(GT_Utility.ItemId.createNoCopy(itemStack), itemStack); + } else { + rList.add(itemStack); + } + } + } + } + + if (getStackInSlot(1) != null && getStackInSlot(1).getUnlocalizedName() + .startsWith("gt.integrated_circuit")) rList.add(getStackInSlot(1)); + if (!inputsFromME.isEmpty()) { + rList.addAll(inputsFromME.values()); + } + return rList; + } + + /** + * Anything that is usually separated off in {@link #getStoredInputs()} (like crafting input bus/buffer) is also + * included here. + */ + public ArrayList<ItemStack> getAllStoredInputs() { + ArrayList<ItemStack> rList = new ArrayList<>(); + + if (supportsCraftingMEBuffer()) { + for (IDualInputHatch dualInputHatch : mDualInputHatches) { + Iterator<? extends IDualInputInventory> inventoryIterator = dualInputHatch.inventories(); + while (inventoryIterator.hasNext()) { + ItemStack[] items = inventoryIterator.next() + .getItemInputs(); + if (items == null) { + continue; + } + for (int i = 0; i < items.length; i++) { + ItemStack item = items[i]; + if (item != null) { + rList.add(item); + } + } + } + } + } + + Map<GT_Utility.ItemId, ItemStack> inputsFromME = new HashMap<>(); + for (GT_MetaTileEntity_Hatch_InputBus tHatch : filterValidMTEs(mInputBusses)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_CraftingInput_ME) { + continue; + } + tHatch.mRecipeMap = getRecipeMap(); + IGregTechTileEntity tileEntity = tHatch.getBaseMetaTileEntity(); + boolean isMEBus = tHatch instanceof GT_MetaTileEntity_Hatch_InputBus_ME; + for (int i = tileEntity.getSizeInventory() - 1; i >= 0; i--) { + ItemStack itemStack = tileEntity.getStackInSlot(i); + if (itemStack != null) { + if (isMEBus) { + // Prevent the same item from different ME buses from being recognized + inputsFromME.put(GT_Utility.ItemId.createNoCopy(itemStack), itemStack); + } else { + rList.add(itemStack); + } + } + } + } + + if (getStackInSlot(1) != null && getStackInSlot(1).getUnlocalizedName() + .startsWith("gt.integrated_circuit")) rList.add(getStackInSlot(1)); + if (!inputsFromME.isEmpty()) { + rList.addAll(inputsFromME.values()); + } + return rList; + } + + public Map<GT_Utility.ItemId, ItemStack> getStoredInputsFromME() { + Map<GT_Utility.ItemId, ItemStack> inputsFromME = new Object2ReferenceOpenHashMap<>(); + for (GT_MetaTileEntity_Hatch_InputBus tHatch : filterValidMTEs(mInputBusses)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_InputBus_ME meBus) { + for (int i = meBus.getSizeInventory() - 1; i >= 0; i--) { + ItemStack itemStack = meBus.getStackInSlot(i); + if (itemStack != null) { + // Prevent the same item from different ME buses from being recognized + inputsFromME.put(GT_Utility.ItemId.createNoCopy(itemStack), itemStack); + } + } + } + } + return inputsFromME; + } + + public Map<Fluid, FluidStack> getStoredFluidsFromME() { + Map<Fluid, FluidStack> fluidsFromME = new Reference2ReferenceOpenHashMap<>(); + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + for (FluidStack fluid : meHatch.getStoredFluids()) { + if (fluid != null) { + // Prevent the same fluid from different ME hatches from being recognized + fluidsFromME.put(fluid.getFluid(), fluid); + } + } + } + } + return fluidsFromME; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return null; + } + + /** + * Creates logic to run recipe check based on recipemap. This runs only once, on class instantiation. + * <p> + * If this machine doesn't use recipemap or does some complex things, override {@link #checkProcessing()}. + */ + @ApiStatus.OverrideOnly + protected ProcessingLogic createProcessingLogic() { + return null; + } + + public void updateSlots() { + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) tHatch.updateSlots(); + for (GT_MetaTileEntity_Hatch_InputBus tHatch : filterValidMTEs(mInputBusses)) tHatch.updateSlots(); + } + + protected void startRecipeProcessing() { + for (GT_MetaTileEntity_Hatch_InputBus hatch : filterValidMTEs(mInputBusses)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + aware.startRecipeProcessing(); + } + } + for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mInputHatches)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + aware.startRecipeProcessing(); + } + } + } + + public void setResultIfFailure(CheckRecipeResult result) { + if (!result.wasSuccessful()) { + this.checkRecipeResult = result; + } + } + + protected void endRecipeProcessing() { + for (GT_MetaTileEntity_Hatch_InputBus hatch : filterValidMTEs(mInputBusses)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + setResultIfFailure(aware.endRecipeProcessing(this)); + } + } + for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mInputHatches)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + setResultIfFailure(aware.endRecipeProcessing(this)); + } + } + } + + public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + } + if (aMetaTileEntity instanceof IDualInputHatch hatch) { + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mDualInputHatches.add(hatch); + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { + setHatchRecipeMap((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); + return mInputHatches.add((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus) { + ((GT_MetaTileEntity_Hatch_InputBus) aMetaTileEntity).mRecipeMap = getRecipeMap(); + return mInputBusses.add((GT_MetaTileEntity_Hatch_InputBus) aMetaTileEntity); + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) + return mOutputHatches.add((GT_MetaTileEntity_Hatch_Output) aMetaTileEntity); + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_OutputBus) + return mOutputBusses.add((GT_MetaTileEntity_Hatch_OutputBus) aMetaTileEntity); + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Energy) + return mEnergyHatches.add((GT_MetaTileEntity_Hatch_Energy) aMetaTileEntity); + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Dynamo) + return mDynamoHatches.add((GT_MetaTileEntity_Hatch_Dynamo) aMetaTileEntity); + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance) + return mMaintenanceHatches.add((GT_MetaTileEntity_Hatch_Maintenance) aMetaTileEntity); + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler) + return mMufflerHatches.add((GT_MetaTileEntity_Hatch_Muffler) aMetaTileEntity); + return false; + } + + public boolean addMaintenanceToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Maintenance hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mMaintenanceHatches.add(hatch); + } + return false; + } + + public boolean addEnergyInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) { + return false; + } + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Energy hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mEnergyHatches.add(hatch); + } + return false; + } + + public boolean addExoticEnergyInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch hatch + && GT_ExoticEnergyInputHelper.isExoticEnergyInput(aMetaTileEntity)) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mExoticEnergyHatches.add(hatch); + } + return false; + } + + public boolean addDynamoToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Dynamo hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mDynamoHatches.add(hatch); + } + return false; + } + + public boolean addMufflerToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mMufflerHatches.add(hatch); + } + return false; + } + + public boolean addInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return addInputBusToMachineList(aTileEntity, aBaseCasingIndex) + || addInputHatchToMachineList(aTileEntity, aBaseCasingIndex); + } + + public boolean addOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return addOutputBusToMachineList(aTileEntity, aBaseCasingIndex) + || addOutputHatchToMachineList(aTileEntity, aBaseCasingIndex); + } + + public boolean addInputBusToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof IDualInputHatch hatch) { + if (!supportsCraftingMEBuffer()) return false; + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mDualInputHatches.add(hatch); + } + + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + hatch.mRecipeMap = getRecipeMap(); + return mInputBusses.add(hatch); + } + return false; + } + + public boolean addOutputBusToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_OutputBus hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mOutputBusses.add(hatch); + } + return false; + } + + public boolean addInputHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + setHatchRecipeMap(hatch); + return mInputHatches.add(hatch); + } + return false; + } + + public boolean addOutputHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output hatch) { + hatch.updateTexture(aBaseCasingIndex); + hatch.updateCraftingIcon(this.getMachineCraftingIcon()); + return mOutputHatches.add(hatch); + } + return false; + } + + protected void setHatchRecipeMap(GT_MetaTileEntity_Hatch_Input hatch) { + if (filtersFluid()) { + hatch.mRecipeMap = getRecipeMap(); + } + } + + /** + * @return If this multi filters fluid input for hatches based on recipemap. + */ + protected boolean filtersFluid() { + return true; + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { + /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + formatNumbers(getActualEnergyUsage()) + + EnumChatFormatting.RESET + + " EU/t", + /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + formatNumbers(getMaxInputVoltage()) + + EnumChatFormatting.RESET + + " EU/t(*2A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(getMaxInputVoltage())] + + EnumChatFormatting.RESET, + /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + /* 6 */ StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + protected ItemStack[] getCompactedInputs() { + // TODO: repalce method with a cleaner one + ArrayList<ItemStack> tInputList = getStoredInputs(); + int tInputList_sS = tInputList.size(); + for (int i = 0; i < tInputList_sS - 1; i++) { + for (int j = i + 1; j < tInputList_sS; j++) { + if (!GT_Utility.areStacksEqual(tInputList.get(i), tInputList.get(j))) continue; + if (tInputList.get(i).stackSize >= tInputList.get(j).stackSize) { + tInputList.remove(j--); + tInputList_sS = tInputList.size(); + } else { + tInputList.remove(i--); + tInputList_sS = tInputList.size(); + break; + } + } + } + return tInputList.toArray(new ItemStack[0]); + } + + protected FluidStack[] getCompactedFluids() { + // TODO: repalce method with a cleaner one + ArrayList<FluidStack> tFluidList = getStoredFluids(); + int tFluidList_sS = tFluidList.size(); + for (int i = 0; i < tFluidList_sS - 1; i++) { + for (int j = i + 1; j < tFluidList_sS; j++) { + if (!GT_Utility.areFluidsEqual(tFluidList.get(i), tFluidList.get(j))) continue; + + if (tFluidList.get(i).amount >= tFluidList.get(j).amount) { + tFluidList.remove(j--); + tFluidList_sS = tFluidList.size(); + } else { + tFluidList.remove(i--); + tFluidList_sS = tFluidList.size(); + break; + } + } + } + return tFluidList.toArray(new FluidStack[0]); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + final NBTTagCompound tag = accessor.getNBTData(); + + if (tag.getBoolean("incompleteStructure")) { + currentTip.add(RED + "** INCOMPLETE STRUCTURE **" + RESET); + } + currentTip.add( + (tag.getBoolean("hasProblems") ? (RED + "** HAS PROBLEMS **") : GREEN + "Running Fine") + RESET + + " Efficiency: " + + tag.getFloat("efficiency") + + "%"); + + boolean isActive = tag.getBoolean("isActive"); + if (isActive) { + long energyTier = tag.getLong("energyTier"); + long actualEnergyUsage = tag.getLong("energyUsage"); + if (energyTier > 0) { + if (actualEnergyUsage > 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.use_with_amperage", + formatNumbers(actualEnergyUsage), + GT_Utility.getAmperageForTier(actualEnergyUsage, (byte) energyTier), + GT_Utility.getColoredTierNameFromTier((byte) energyTier))); + } else if (actualEnergyUsage < 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.produce_with_amperage", + formatNumbers(-actualEnergyUsage), + GT_Utility.getAmperageForTier(-actualEnergyUsage, (byte) energyTier), + GT_Utility.getColoredTierNameFromTier((byte) energyTier))); + } + } else { + if (actualEnergyUsage > 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.use", + formatNumbers(actualEnergyUsage), + GT_Utility.getColoredTierNameFromVoltage(actualEnergyUsage))); + } else if (actualEnergyUsage < 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.produce", + formatNumbers(-actualEnergyUsage), + GT_Utility.getColoredTierNameFromVoltage(-actualEnergyUsage))); + } + } + } + currentTip.add( + GT_Waila.getMachineProgressString(isActive, tag.getInteger("maxProgress"), tag.getInteger("progress"))); + // Show ns on the tooltip + if (GT_Mod.gregtechproxy.wailaAverageNS && tag.hasKey("averageNS")) { + int tAverageTime = tag.getInteger("averageNS"); + currentTip.add("Average CPU load of ~" + formatNumbers(tAverageTime) + " ns"); + } + super.getWailaBody(itemStack, currentTip, accessor, config); + } + + public final void getMTEWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currentTip, accessor, config); + } + + @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.setBoolean("hasProblems", (getIdealStatus() - getRepairStatus()) > 0); + tag.setFloat("efficiency", mEfficiency / 100.0F); + tag.setInteger("progress", mProgresstime); + tag.setInteger("maxProgress", mMaxProgresstime); + tag.setBoolean("incompleteStructure", (getBaseMetaTileEntity().getErrorDisplayID() & 64) != 0); + + final IGregTechTileEntity tileEntity = getBaseMetaTileEntity(); + if (tileEntity != null) { + tag.setBoolean("isActive", tileEntity.isActive()); + if (tileEntity.isActive()) { + if (mEUt < 0) tag.setLong("energyUsage", getActualEnergyUsage()); + else tag.setLong("energyUsage", (long) -mEUt * mEfficiency / 10000); + tag.setLong("energyTier", getInputVoltageTier()); + } + } + + final GT_ClientPreference preference = GT_Mod.gregtechproxy.getClientPreference(player.getUniqueID()); + if (preference != null && preference.isWailaAverageNSEnabled()) { + getBaseMetaTileEntity().startTimeStatistics(); + int tAverageTime = 0; + int amountOfZero = 0; + for (int tTime : this.getBaseMetaTileEntity() + .getTimeStatistics()) { + tAverageTime += tTime; + if (tTime == 0) { + amountOfZero += 1; + } + } + + // tick time zero means it has not been updated yet + int samples = getBaseMetaTileEntity().getTimeStatistics().length - amountOfZero; + if (samples > 0) { + tag.setInteger("averageNS", tAverageTime / samples); + } + } + } + + protected void setMufflers(boolean state) { + for (GT_MetaTileEntity_Hatch_Muffler aMuffler : mMufflerHatches) { + final IGregTechTileEntity iGTTileEntity = aMuffler.getBaseMetaTileEntity(); + if (iGTTileEntity != null && !iGTTileEntity.isDead()) { + iGTTileEntity.setActive(state); + } + } + } + + @Override + public void onRemoval() { + super.onRemoval(); + // Deactivate mufflers + setMufflers(false); + } + + public List<GT_MetaTileEntity_Hatch> getExoticEnergyHatches() { + return mExoticEnergyHatches; + } + + /** + * @return Returns true if there is 1 TT Energy Hatch OR up to 2 Energy Hatches + */ + public boolean checkExoticAndNormalEnergyHatches() { + if (mExoticEnergyHatches.isEmpty() && mEnergyHatches.isEmpty()) { + return false; + } + + if (!mExoticEnergyHatches.isEmpty()) { + if (!mEnergyHatches.isEmpty()) { + return false; + } + + if (mExoticEnergyHatches.size() != 1) { + return false; + } + } + + return mEnergyHatches.size() <= 2; + } + + /** + * Checks if all the item / fluid outputs of the recipe can be outputted to the buses / hatches. + * If void protection is enabled, it also checks for {@link #protectsExcessItem()} and + * {@link #protectsExcessFluid()}, so you don't need to call them along with this method. + * <p> + * If you're using {@link GT_ParallelHelper}, it will handle void protection and return 0 parallel + * if all the output cannot be dumped into buses / hatches. In that case you won't use this method. + */ + protected boolean canOutputAll(@Nonnull GT_Recipe recipe) { + return canOutputAll(recipe.mOutputs, recipe.mFluidOutputs); + } + + /** + * Checks if all the items can be outputted to the output buses. + * If void protection is enabled, it also checks for {@link #protectsExcessItem()}, + * so you don't need to call it along with this method. + */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + protected boolean canOutputAll(ItemStack[] items) { + return canOutputAll(items, null); + } + + /** + * Checks if all the fluids can be outputted to the output hatches. + * If void protection is enabled, it also checks for {@link #protectsExcessFluid()}, + * so you don't need to call it along with this method. + */ + protected boolean canOutputAll(FluidStack[] fluids) { + return canOutputAll(null, fluids); + } + + /** + * Checks if all the items / fluids can be outputted to output buses / hatches. + * If void protection is enabled, it also checks for {@link #protectsExcessItem()} and + * {@link #protectsExcessFluid()}, so you don't need to call them along with this method. + */ + protected boolean canOutputAll(@Nullable ItemStack[] items, @Nullable FluidStack[] fluids) { + if (!protectsExcessItem() && !protectsExcessFluid()) { + return true; + } + + VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper().setMachine(this) + .setItemOutputs(items) + .setFluidOutputs(fluids) + .build(); + return voidProtectionHelper.getMaxParallel() > 0; + } + + @Override + public boolean isAllowedToWork() { + return getBaseMetaTileEntity() != null && getBaseMetaTileEntity().isAllowedToWork(); + } + + @Override + public void disableWorking() { + if (getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().disableWorking(); + } + } + + @Override + public void enableWorking() { + if (getBaseMetaTileEntity() != null) { + getBaseMetaTileEntity().enableWorking(); + } + } + + public ItemStack getControllerSlot() { + return mInventory[1]; + } + + @Override + public Pos2d getPowerSwitchButtonPos() { + return new Pos2d(174, 148); + } + + @Override + public boolean supportsVoidProtection() { + return false; + } + + @Override + public VoidingMode getVoidingMode() { + return voidingMode; + } + + @Override + public void setVoidingMode(VoidingMode mode) { + this.voidingMode = mode; + } + + @Override + public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) { + List<ItemStack> ret = new ArrayList<>(); + for (final GT_MetaTileEntity_Hatch tBus : filterValidMTEs(mOutputBusses)) { + final IInventory tBusInv = tBus.getBaseMetaTileEntity(); + for (int i = 0; i < tBusInv.getSizeInventory(); i++) { + ret.add(tBus.getStackInSlot(i)); + } + } + return ret; + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + return filterValidMTEs(mOutputHatches); + } + + /** + * Util method for DT-like structure to collect list of output hatches. + */ + protected <T extends GT_MetaTileEntity_Hatch_Output> List<? extends IFluidStore> getFluidOutputSlotsByLayer( + FluidStack[] toOutput, List<List<T>> hatchesByLayer) { + List<IFluidStore> ret = new ArrayList<>(); + for (int i = 0; i < toOutput.length; i++) { + if (i >= hatchesByLayer.size()) { + break; + } + FluidStack fluidOutputForLayer = toOutput[i]; + for (GT_MetaTileEntity_Hatch_Output hatch : hatchesByLayer.get(i)) { + if (!hatch.isValid()) continue; + if (fluidOutputForLayer != null) { + ret.add(new OutputHatchWrapper(hatch, f -> GT_Utility.areFluidsEqual(f, fluidOutputForLayer))); + } else { + ret.add(hatch); + } + } + } + return ret; + } + + @Override + public boolean canDumpItemToME() { + for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(mOutputBusses)) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) { + return true; + } + } + return false; + } + + @Override + public boolean canDumpFluidToME() { + for (IFluidStore tHatch : getFluidOutputSlots(new FluidStack[0])) { + if (tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME) { + return true; + } + } + return false; + } + + @Override + public Pos2d getVoidingModeButtonPos() { + return new Pos2d(8, 91); + } + + @Override + public boolean supportsInputSeparation() { + return false; + } + + @Override + public boolean isInputSeparationEnabled() { + return inputSeparation; + } + + @Override + public void setInputSeparation(boolean enabled) { + this.inputSeparation = enabled; + } + + @Override + public Pos2d getInputSeparationButtonPos() { + return new Pos2d(26, 91); + } + + @Override + public boolean supportsBatchMode() { + return false; + } + + @Override + public boolean isBatchModeEnabled() { + return batchMode; + } + + @Override + public void setBatchMode(boolean enabled) { + this.batchMode = enabled; + } + + @Override + public Pos2d getBatchModeButtonPos() { + return new Pos2d(44, 91); + } + + @Override + public boolean supportsSingleRecipeLocking() { + return false; + } + + @Override + public boolean isRecipeLockingEnabled() { + return mLockedToSingleRecipe; + } + + @Override + public void setRecipeLocking(boolean enabled) { + mLockedToSingleRecipe = enabled; + if (!enabled) { + setSingleRecipeCheck(null); + } + } + + @Override + public void setSingleRecipeCheck(SingleRecipeCheck recipeCheck) { + mSingleRecipeCheck = recipeCheck; + } + + @Override + public SingleRecipeCheck getSingleRecipeCheck() { + return mSingleRecipeCheck; + } + + @Override + public Pos2d getRecipeLockingButtonPos() { + return new Pos2d(62, 91); + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public int getGUIWidth() { + return 198; + } + + @Override + public int getGUIHeight() { + return 192; + } + + @Override + public void bindPlayerInventoryUI(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.bindPlayerInventory(buildContext.getPlayer(), new Pos2d(7, 109), getGUITextureSet().getItemSlot()); + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) + .setPos(4, 4) + .setSize(190, 85)); + final SlotWidget inventorySlot = new SlotWidget(inventoryHandler, 1); + builder.widget( + inventorySlot.setPos(173, 167) + .setBackground(GT_UITextures.SLOT_DARK_GRAY)); + + final DynamicPositionedColumn screenElements = new DynamicPositionedColumn(); + drawTexts(screenElements, inventorySlot); + builder.widget(screenElements); + + builder.widget(createPowerSwitchButton(builder)) + .widget(createVoidExcessButton(builder)) + .widget(createInputSeparationButton(builder)) + .widget(createBatchModeButton(builder)) + .widget(createLockToSingleRecipeButton(builder)); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) {} + + protected boolean shouldDisplayCheckRecipeResult() { + return true; + } + + public boolean shouldDisplayShutDownReason() { + return true; + } + + protected final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + protected String generateCurrentRecipeInfoString() { + StringBuffer ret = new StringBuffer(EnumChatFormatting.WHITE + "Progress: "); + + numberFormat.setMinimumFractionDigits(2); + numberFormat.setMaximumFractionDigits(2); + numberFormat.format((double) mProgresstime / 20, ret); + ret.append("s / "); + numberFormat.format((double) mMaxProgresstime / 20, ret); + ret.append("s ("); + numberFormat.setMinimumFractionDigits(1); + numberFormat.setMaximumFractionDigits(1); + numberFormat.format((double) mProgresstime / mMaxProgresstime * 100, ret); + ret.append("%)\n"); + numberFormat.setMinimumFractionDigits(0); + numberFormat.setMaximumFractionDigits(2); + + IntConsumer appendRate = (amount) -> { + double processPerTick = (double) amount / mMaxProgresstime * 20; + if (processPerTick > 1) { + ret.append(" ("); + numberFormat.format(Math.round(processPerTick * 10) / 10.0, ret); + ret.append("/s)"); + } else { + ret.append(" ("); + numberFormat.format(Math.round(1 / processPerTick * 10) / 10.0, ret); + ret.append("s/ea)"); + } + }; + + int lines = 0; + int MAX_LINES = 5; + + if (mOutputItems != null) { + for (var item : mOutputItems) { + if (item == null) continue; + if (lines >= MAX_LINES) { + ret.append("..."); + return ret.toString(); + } + lines++; + ret.append(EnumChatFormatting.AQUA) + .append(item.getDisplayName()) + .append(EnumChatFormatting.WHITE) + .append(" x ") + .append(EnumChatFormatting.GOLD); + numberFormat.format(item.stackSize, ret); + ret.append(EnumChatFormatting.WHITE); + appendRate.accept(item.stackSize); + ret.append('\n'); + } + } + if (mOutputFluids != null) { + for (var fluid : mOutputFluids) { + if (fluid == null) continue; + if (lines >= MAX_LINES) { + ret.append("..."); + return ret.toString(); + } + lines++; + ret.append(EnumChatFormatting.AQUA) + .append(fluid.getLocalizedName()) + .append(EnumChatFormatting.WHITE) + .append(" x ") + .append(EnumChatFormatting.GOLD); + numberFormat.format(fluid.amount, ret); + ret.append("L") + .append(EnumChatFormatting.WHITE); + appendRate.accept(fluid.amount); + ret.append('\n'); + } + } + return ret.toString(); + } + + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + screenElements.setSynced(false) + .setSpace(0) + .setPos(10, 7); + + screenElements + .widget( + new TextWidget(GT_Utility.trans("132", "Pipe is loose.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mWrench)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mWrench, val -> mWrench = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("133", "Screws are loose.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mScrewdriver)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mScrewdriver, val -> mScrewdriver = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("134", "Something is stuck.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mSoftHammer)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mSoftHammer, val -> mSoftHammer = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("135", "Platings are dented.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mHardHammer)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mHardHammer, val -> mHardHammer = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("136", "Circuitry burned out.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mSolderingTool)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mSolderingTool, val -> mSolderingTool = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("137", "That doesn't belong there.")) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mCrowbar)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mCrowbar, val -> mCrowbar = val)); + screenElements + .widget( + new TextWidget(GT_Utility.trans("138", "Incomplete Structure.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mMachine)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mMachine, val -> mMachine = val)); + screenElements.widget( + new TextWidget("Too Uncertain.").setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> (getBaseMetaTileEntity().getErrorDisplayID() & 128) != 0)); + screenElements.widget( + new TextWidget("Invalid Parameters.").setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> (getBaseMetaTileEntity().getErrorDisplayID() & 256) != 0)); + + screenElements.widget( + new TextWidget(GT_Utility.trans("139", "Hit with Soft Mallet")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 && !getBaseMetaTileEntity().isActive())) + .widget( + new FakeSyncWidget.IntegerSyncer( + () -> getBaseMetaTileEntity().getErrorDisplayID(), + val -> getBaseMetaTileEntity().setErrorDisplayID(val))) + .widget( + new FakeSyncWidget.BooleanSyncer( + () -> getBaseMetaTileEntity().isActive(), + val -> getBaseMetaTileEntity().setActive(val))); + screenElements.widget( + new TextWidget(GT_Utility.trans("140", "to (re-)start the Machine")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 && !getBaseMetaTileEntity().isActive())); + screenElements.widget( + new TextWidget(GT_Utility.trans("141", "if it doesn't start.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 && !getBaseMetaTileEntity().isActive())); + screenElements.widget( + new TextWidget(GT_Utility.trans("142", "Running perfectly.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 && getBaseMetaTileEntity().isActive())); + + screenElements.widget( + TextWidget.dynamicString( + () -> getBaseMetaTileEntity().getLastShutDownReason() + .getDisplayString()) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> shouldDisplayShutDownReason() && !getBaseMetaTileEntity().isActive() + && GT_Utility.isStringValid( + getBaseMetaTileEntity().getLastShutDownReason() + .getDisplayString()) + && getBaseMetaTileEntity().wasShutdown())) + .widget( + new ShutDownReasonSyncer( + () -> getBaseMetaTileEntity().getLastShutDownReason(), + reason -> getBaseMetaTileEntity().setShutDownReason(reason))) + .widget( + new FakeSyncWidget.BooleanSyncer( + () -> getBaseMetaTileEntity().wasShutdown(), + wasShutDown -> getBaseMetaTileEntity().setShutdownStatus(wasShutDown))); + + screenElements.widget( + TextWidget.dynamicString(() -> checkRecipeResult.getDisplayString()) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> shouldDisplayCheckRecipeResult() + && GT_Utility.isStringValid(checkRecipeResult.getDisplayString()) + && (isAllowedToWork() || getBaseMetaTileEntity().isActive() + || checkRecipeResult.persistsOnShutdown()))) + .widget(new CheckRecipeResultSyncer(() -> checkRecipeResult, (result) -> checkRecipeResult = result)); + + if (showRecipeTextInGUI()) { + // Display current recipe + screenElements.widget( + TextWidget.dynamicString(this::generateCurrentRecipeInfoString) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> (mOutputFluids != null && mOutputFluids.length > 0) + || (mOutputItems != null && mOutputItems.length > 0))) + .widget( + new FakeSyncWidget.ListSyncer<>( + () -> mOutputFluids != null ? Arrays.asList(mOutputFluids) : Collections.emptyList(), + val -> mOutputFluids = val.toArray(new FluidStack[0]), + NetworkUtils::writeFluidStack, + NetworkUtils::readFluidStack)) + .widget( + new FakeSyncWidget.ListSyncer<>( + () -> mOutputItems != null ? Arrays.asList(mOutputItems) : Collections.emptyList(), + val -> mOutputItems = val.toArray(new ItemStack[0]), + NetworkUtils::writeItemStack, + NetworkUtils::readItemStack)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> mProgresstime, val -> mProgresstime = val)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> mMaxProgresstime, val -> mMaxProgresstime = val)); + } + + screenElements.widget( + new TextWidget(GT_Utility.trans("144", "Missing Turbine Rotor")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> { + if (getBaseMetaTileEntity().isAllowedToWork()) return false; + if (getBaseMetaTileEntity().getErrorDisplayID() == 0 + && this instanceof GT_MetaTileEntity_LargeTurbine) { + final ItemStack tItem = inventorySlot.getMcSlot() + .getStack(); + return tItem == null + || !(tItem.getItem() == GT_MetaGenerated_Tool_01.INSTANCE && tItem.getItemDamage() >= 170 + && tItem.getItemDamage() <= 177); + } + return false; + })); + } + + protected boolean showRecipeTextInGUI() { + return true; + } + + @TestOnly + protected void setEnergyHatches(ArrayList<GT_MetaTileEntity_Hatch_Energy> EnergyHatches) { + this.mEnergyHatches = EnergyHatches; + } + + @TestOnly + protected void setExoticEnergyHatches(List<GT_MetaTileEntity_Hatch> ExoticEnergyHatches) { + this.mExoticEnergyHatches = ExoticEnergyHatches; + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SpecialFilter.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SpecialFilter.java new file mode 100644 index 0000000000..1a71f17ec8 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_SpecialFilter.java @@ -0,0 +1,134 @@ +package gregtech.api.metatileentity.implementations; + +import java.util.List; +import java.util.function.Function; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public abstract class GT_MetaTileEntity_SpecialFilter extends GT_MetaTileEntity_FilterBase { + + private static final String ALLOW_NBT_TOOLTIP = "GT5U.machines.allow_nbt.tooltip"; + private boolean allowNbt = false; + + public GT_MetaTileEntity_SpecialFilter(int aID, String aName, String aNameRegional, int aTier, + String[] aDescription) { + // 9 buffer slot, 1 representation slot, 1 holo slot. last seems not needed... + super(aID, aName, aNameRegional, aTier, 11, aDescription); + } + + public GT_MetaTileEntity_SpecialFilter(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_SpecialFilter(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("bNBTAllowed", this.allowNbt); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + this.allowNbt = aNBT.getBoolean("bNBTAllowed"); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return (super.allowPutStack(aBaseMetaTileEntity, aIndex, side, aStack)) + && ((this.allowNbt) || (!aStack.hasTagCompound())) + && (this.isStackAllowed(aStack) != this.invertFilter); + } + + protected abstract boolean isStackAllowed(ItemStack aStack); + + protected List<Text> getEmptySlotTooltip() { + return null; + } + + protected Function<List<String>, List<String>> getItemStackReplacementTooltip() { + return list -> list; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + addAllowNbtButton(builder); + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_ARROW_24_WHITE.apply(27, false)) + .setPos(6, 19) + .setSize(27, 24)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_ARROW_24_BLUE.apply(42, true)) + .setPos(53, 19) + .setSize(42, 24)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_ARROW_24_RED.apply(19, true)) + .setPos(152, 19) + .setSize(19, 24)) + .widget( + createFilterIconSlot(BaseSlot.phantom(inventoryHandler, 9)).disableShiftInsert() + .setPos(34, 22) + .setBackground(GT_UITextures.BUTTON_STANDARD)) + .widget( + SlotGroup.ofItemHandler(inventoryHandler, 3) + .endAtSlot(8) + .build() + .setPos(97, 4)); + } + + private void addAllowNbtButton(ModularWindow.Builder builder) { + builder.widget( + createToggleButton( + () -> allowNbt, + val -> allowNbt = val, + GT_UITextures.OVERLAY_BUTTON_NBT, + () -> mTooltipCache.getData(ALLOW_NBT_TOOLTIP))); + } + + protected abstract SlotWidget createFilterIconSlot(BaseSlot slot); + + protected abstract class FilterIconSlotWidget extends SlotWidget { + + public FilterIconSlotWidget(BaseSlot slot) { + super(slot); + } + + @Override + protected abstract void phantomClick(ClickData clickData, ItemStack cursorStack); + + @Override + public void buildTooltip(List<Text> tooltip) { + super.buildTooltip(tooltip); + List<Text> emptySlotTooltip = getEmptySlotTooltip(); + if (emptySlotTooltip != null) { + tooltip.addAll(emptySlotTooltip); + } + } + + @Override + public Function<List<String>, List<String>> getOverwriteItemStackTooltip() { + return getItemStackReplacementTooltip(); + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TieredMachineBlock.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TieredMachineBlock.java new file mode 100644 index 0000000000..dd21d6f412 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TieredMachineBlock.java @@ -0,0 +1,126 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.GT; +import static gregtech.api.metatileentity.BaseTileEntity.BATTERY_SLOT_TOOLTIP; +import static gregtech.api.metatileentity.BaseTileEntity.BATTERY_SLOT_TOOLTIP_ALT; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; + +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import gregtech.api.enums.GT_Values; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.util.GT_Utility; + +public abstract class GT_MetaTileEntity_TieredMachineBlock extends MetaTileEntity { + + /** + * Value between [0 - 9] to describe the Tier of this Machine. PLZ [0-15] works - READ! GT_Values class. + */ + public final byte mTier; + + @Deprecated + public final String mDescription; + + /** + * A simple Description. + */ + public final String[] mDescriptionArray; + + /** + * Contains all Textures used by this Block. + */ + public final ITexture[][][] mTextures; + + public GT_MetaTileEntity_TieredMachineBlock(int aID, String aName, String aNameRegional, int aTier, + int aInvSlotCount, String aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aInvSlotCount); + mTier = (byte) Math.max(0, Math.min(aTier, 14)); + mDescriptionArray = aDescription == null ? new String[0] : new String[] { aDescription }; + mDescription = mDescriptionArray.length > 0 ? mDescriptionArray[0] : ""; + // must always be the last call! + if (GT.isClientSide()) mTextures = getTextureSet(aTextures); + else mTextures = null; + } + + public GT_MetaTileEntity_TieredMachineBlock(int aID, String aName, String aNameRegional, int aTier, + int aInvSlotCount, String[] aDescription, ITexture... aTextures) { + super(aID, aName, aNameRegional, aInvSlotCount); + mTier = (byte) Math.max(0, Math.min(aTier, 15)); + mDescriptionArray = aDescription == null ? new String[0] : aDescription; + mDescription = mDescriptionArray.length > 0 ? mDescriptionArray[0] : ""; + + // must always be the last call! + if (GT.isClientSide()) mTextures = getTextureSet(aTextures); + else mTextures = null; + } + + public GT_MetaTileEntity_TieredMachineBlock(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aInvSlotCount); + mTier = (byte) aTier; + mDescriptionArray = aDescription == null ? new String[0] : new String[] { aDescription }; + mDescription = mDescriptionArray.length > 0 ? mDescriptionArray[0] : ""; + mTextures = aTextures; + } + + public GT_MetaTileEntity_TieredMachineBlock(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aInvSlotCount); + mTier = (byte) aTier; + mDescriptionArray = aDescription == null ? new String[0] : aDescription; + mDescription = mDescriptionArray.length > 0 ? mDescriptionArray[0] : ""; + mTextures = aTextures; + } + + @Override + public byte getTileEntityBaseType() { + return (byte) (Math.min(3, mTier <= 0 ? 0 : 1 + ((mTier - 1) / 4))); + } + + @Override + public long getInputTier() { + return mTier; + } + + @Override + public long getOutputTier() { + return mTier; + } + + @Override + public String[] getDescription() { + return mDescriptionArray; + } + + /** + * Used Client Side to get a Texture Set for this Block. Called after setting the Tier and the Description so that + * those two are accessible. + * + * @param aTextures is the optional Array you can give to the Constructor. + */ + public abstract ITexture[][][] getTextureSet(ITexture[] aTextures); + + protected SlotWidget createChargerSlot(int x, int y) { + final String batterySlotTooltipKey; + final Object[] batterySlotTooltipArgs; + final String pTier1 = GT_Utility.getColoredTierNameFromTier(mTier); + if (mTier == GT_Values.VN.length - 1) { + batterySlotTooltipKey = BATTERY_SLOT_TOOLTIP_ALT; + batterySlotTooltipArgs = new String[] { pTier1 }; + } else { + batterySlotTooltipKey = BATTERY_SLOT_TOOLTIP; + batterySlotTooltipArgs = new String[] { pTier1, GT_Utility.getColoredTierNameFromTier((byte) (mTier + 1)) }; + } + return createChargerSlot(x, y, batterySlotTooltipKey, batterySlotTooltipArgs); + } + + protected SlotWidget createChargerSlot(int x, int y, String tooltipKey, Object[] tooltipArgs) { + return (SlotWidget) new SlotWidget(inventoryHandler, rechargerSlotStartIndex()).disableShiftInsert() + .setGTTooltip(() -> mTooltipCache.getData(tooltipKey, tooltipArgs)) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_CHARGER) + .setPos(x, y); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TooltipMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TooltipMultiBlockBase.java new file mode 100644 index 0000000000..c12c7c1442 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_TooltipMultiBlockBase.java @@ -0,0 +1,57 @@ +package gregtech.api.metatileentity.implementations; + +import java.util.concurrent.atomic.AtomicReferenceArray; + +import org.lwjgl.input.Keyboard; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ISecondaryDescribable; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +/** + * A multiblock with tooltip {@link GT_Multiblock_Tooltip_Builder} + */ +public abstract class GT_MetaTileEntity_TooltipMultiBlockBase extends GT_MetaTileEntity_MultiBlockBase + implements ISecondaryDescribable { + + private static final AtomicReferenceArray<GT_Multiblock_Tooltip_Builder> tooltips = new AtomicReferenceArray<>( + GregTech_API.METATILEENTITIES.length); + + public GT_MetaTileEntity_TooltipMultiBlockBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_TooltipMultiBlockBase(String aName) { + super(aName); + } + + protected GT_Multiblock_Tooltip_Builder getTooltip() { + int tId = getBaseMetaTileEntity().getMetaTileID(); + GT_Multiblock_Tooltip_Builder tooltip = tooltips.get(tId); + if (tooltip == null) { + tooltip = createTooltip(); + tooltips.set(tId, tooltip); + } + return tooltip; + } + + protected abstract GT_Multiblock_Tooltip_Builder createTooltip(); + + @Override + public String[] getDescription() { + return getCurrentDescription(); + } + + @Override + public boolean isDisplaySecondaryDescription() { + return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); + } + + public String[] getPrimaryDescription() { + return getTooltip().getInformation(); + } + + public String[] getSecondaryDescription() { + return getTooltip().getStructureInformation(); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Transformer.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Transformer.java new file mode 100644 index 0000000000..a8c26957f8 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Transformer.java @@ -0,0 +1,325 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.V; +import static mcp.mobius.waila.api.SpecialChars.BLUE; +import static mcp.mobius.waila.api.SpecialChars.GOLD; +import static mcp.mobius.waila.api.SpecialChars.GREEN; +import static mcp.mobius.waila.api.SpecialChars.RED; +import static mcp.mobius.waila.api.SpecialChars.RESET; + +import java.util.List; + +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.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import cofh.api.energy.IEnergyProvider; +import cofh.api.energy.IEnergyStorage; +import crazypants.enderio.machine.capbank.TileCapBank; +import crazypants.enderio.machine.capbank.network.ICapBankNetwork; +import crazypants.enderio.power.IPowerContainer; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Utility; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * This is the main construct for my Basic Machines such as the Automatic Extractor Extend this class to make a simple + * Machine + */ +public class GT_MetaTileEntity_Transformer extends GT_MetaTileEntity_TieredMachineBlock { + + public GT_MetaTileEntity_Transformer(int aID, String aName, String aNameRegional, int aTier, String aDescription) { + super(aID, aName, aNameRegional, aTier, 0, aDescription); + } + + public GT_MetaTileEntity_Transformer(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Transformer(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[12][17][]; + for (byte i = -1; i < 16; i++) { + rTextures[0][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + rTextures[1][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + rTextures[2][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier] }; + rTextures[3][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[mTier] }; + rTextures[4][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[mTier] }; + rTextures[5][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI[mTier] }; + rTextures[6][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN[mTier] }; + rTextures[7][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN[mTier] }; + rTextures[8][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_IN[mTier] }; + rTextures[9][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] }; + rTextures[10][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] }; + rTextures[11][i + 1] = new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[mTier][i + 1], + Textures.BlockIcons.OVERLAYS_ENERGY_OUT_MULTI[mTier] }; + } + return rTextures; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection side, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + return mTextures[Math.min(2, side.ordinal()) + (side == facingDirection ? 3 : 0) + + (baseMetaTileEntity.isAllowedToWork() ? 0 : 6)][colorIndex + 1]; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Transformer(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isEnetOutput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + ForgeDirection blockFrontFacing = getBaseMetaTileEntity().getFrontFacing(); + + if (getBaseMetaTileEntity().isAllowedToWork()) { + return side == blockFrontFacing; + } else { + return side != blockFrontFacing; + } + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return !isInputFacing(side); + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return V[mTier + 1]; + } + + @Override + public long maxEUStore() { + return Math.max(512L, 1L << (mTier + 2)) + V[mTier + 1] * 4L; + } + + @Override + public long maxEUInput() { + return V[getBaseMetaTileEntity().isAllowedToWork() ? mTier + 1 : mTier]; + } + + @Override + public long maxEUOutput() { + return V[getBaseMetaTileEntity().isAllowedToWork() ? mTier : mTier + 1]; + } + + @Override + public long maxAmperesOut() { + return getBaseMetaTileEntity().isAllowedToWork() ? 4 : 1; + } + + @Override + public long maxAmperesIn() { + return getBaseMetaTileEntity().isAllowedToWork() ? 1 : 4; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && GregTech_API.mInputRF) { + aBaseMetaTileEntity.setActive(aBaseMetaTileEntity.isAllowedToWork()); + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (aBaseMetaTileEntity.getStoredEU() >= aBaseMetaTileEntity.getEUCapacity()) break; + if (!aBaseMetaTileEntity.inputEnergyFrom(side)) continue; + final TileEntity tTileEntity = aBaseMetaTileEntity.getTileEntityAtSide(side); + if (tTileEntity instanceof IEnergyProvider energyProvider + && energyProvider.extractEnergy(side.getOpposite(), 1, true) == 1) { + long tEU = ((IEnergyProvider) tTileEntity).extractEnergy( + side.getOpposite(), + GT_Utility.safeInt(maxEUInput() * 100L / GregTech_API.mRFtoEU), + false); + tEU = tEU * GregTech_API.mRFtoEU / 100; + aBaseMetaTileEntity.injectEnergyUnits(ForgeDirection.UNKNOWN, Math.min(tEU, maxEUInput()), 1); + } else if (tTileEntity instanceof IEnergyStorage energyStorage + && energyStorage.extractEnergy(1, true) == 1) { + long tEU = ((IEnergyStorage) tTileEntity) + .extractEnergy(GT_Utility.safeInt(maxEUInput() * 100L / GregTech_API.mRFtoEU), false); + tEU = tEU * GregTech_API.mRFtoEU / 100; + aBaseMetaTileEntity.injectEnergyUnits(ForgeDirection.UNKNOWN, Math.min(tEU, maxEUInput()), 1); + } else if (GregTech_API.meIOLoaded && tTileEntity instanceof IPowerContainer powerContainer + && powerContainer.getEnergyStored() > 0) { + final int storedRF = powerContainer.getEnergyStored(); + final int extractRF = GT_Utility.safeInt(maxEUInput() * 100L / GregTech_API.mRFtoEU); + long tEU = 0; + if (tTileEntity instanceof TileCapBank capBank) { + ICapBankNetwork network = capBank.getNetwork(); + if (network != null && network.getEnergyStoredL() > 0) { + tEU = Math.min( + (Math.min( + Math.min(network.getEnergyStoredL(), storedRF - extractRF), + network.getMaxOutput())) * (long) GregTech_API.mRFtoEU / 100L, + maxEUInput()); + network.addEnergy(GT_Utility.safeInt(-(tEU * 100 / GregTech_API.mRFtoEU))); + } + } else { + if (storedRF > extractRF) { + powerContainer.setEnergyStored(storedRF - extractRF); + tEU = maxEUInput(); + } else { + powerContainer.setEnergyStored(0); + tEU = storedRF * (long) GregTech_API.mRFtoEU / 100L; + } + } + aBaseMetaTileEntity + .injectEnergyUnits(ForgeDirection.UNKNOWN, Math.min(tEU, maxEUInput()), 1); + } + } + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + // + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + // + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean hasAlternativeModeText() { + return true; + } + + @Override + public String getAlternativeModeText() { + return (getBaseMetaTileEntity().isAllowedToWork() ? GT_Utility.trans("145", "Step Down, In: ") + : GT_Utility.trans("146", "Step Up, In: ")) + maxEUInput() + + GT_Utility.trans("148", "V ") + + maxAmperesIn() + + GT_Utility.trans("147", "A, Out: ") + + maxEUOutput() + + GT_Utility.trans("148", "V ") + + maxAmperesOut() + + GT_Utility.trans("149", "A"); + } + + @Override + public boolean shouldJoinIc2Enet() { + return true; + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + final ForgeDirection facing = getBaseMetaTileEntity().getFrontFacing(); + final NBTTagCompound tag = accessor.getNBTData(); + final ForgeDirection side = accessor.getSide(); + final boolean allowedToWork = tag.getBoolean("isAllowedToWork"); + + final byte inputTier = GT_Utility.getTier(tag.getLong("maxEUInput")); + final byte outputTier = GT_Utility.getTier(tag.getLong("maxEUOutput")); + + currenttip.add( + String.format( + "%s %s(%dA) -> %s(%dA)", + (allowedToWork ? (GREEN + "Step Down") : (RED + "Step Up")) + RESET, + GT_Mod.gregtechproxy.mWailaTransformerVoltageTier ? GT_Utility.getColoredTierNameFromTier(inputTier) + : tag.getLong("maxEUInput"), + tag.getLong("maxAmperesIn"), + GT_Mod.gregtechproxy.mWailaTransformerVoltageTier ? GT_Utility.getColoredTierNameFromTier(outputTier) + : tag.getLong("maxEUOutput"), + tag.getLong("maxAmperesOut"))); + + if ((side == facing && allowedToWork) || (side != facing && !allowedToWork)) { + currenttip.add( + String.format( + GOLD + "Input:" + RESET + " %s(%dA)", + GT_Mod.gregtechproxy.mWailaTransformerVoltageTier ? GT_Utility.getColoredTierNameFromTier(inputTier) + : tag.getLong("maxEUInput"), + tag.getLong("maxAmperesIn"))); + } else { + currenttip.add( + String.format( + BLUE + "Output:" + RESET + " %s(%dA)", + GT_Mod.gregtechproxy.mWailaTransformerVoltageTier + ? GT_Utility.getColoredTierNameFromTier(outputTier) + : tag.getLong("maxEUOutput"), + tag.getLong("maxAmperesOut"))); + } + + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @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.setBoolean("isAllowedToWork", getBaseMetaTileEntity().isAllowedToWork()); + tag.setLong("maxEUInput", maxEUInput()); + tag.setLong("maxAmperesIn", maxAmperesIn()); + tag.setLong("maxEUOutput", maxEUOutput()); + tag.setLong("maxAmperesOut", maxAmperesOut()); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java new file mode 100644 index 0000000000..a04f5cd986 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java @@ -0,0 +1,146 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.AuthorColen; +import static gregtech.api.enums.GT_Values.V; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static gregtech.common.misc.WirelessNetworkManager.strongCheckOrAddUser; + +import java.util.UUID; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IWirelessEnergyHatchInformation; +import gregtech.api.metatileentity.MetaTileEntity; + +public class GT_MetaTileEntity_Wireless_Dynamo extends GT_MetaTileEntity_Hatch_Dynamo + implements IWirelessEnergyHatchInformation { + + private UUID owner_uuid; + + public GT_MetaTileEntity_Wireless_Dynamo(String aName, byte aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + public GT_MetaTileEntity_Wireless_Dynamo(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, new String[] { "" }); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI_WIRELESS_ON[mTier] }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI_WIRELESS_ON[mTier] }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isEnetOutput() { + return false; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 2 * V[mTier]; + } + + @Override + public long maxEUOutput() { + return V[mTier]; + } + + @Override + public long maxEUStore() { + return totalStorage(V[mTier]); + } + + @Override + public String[] getDescription() { + return new String[] { EnumChatFormatting.GRAY + "Stores energy globally in a network, up to 2^(2^31) EU.", + EnumChatFormatting.GRAY + "Does not connect to wires. This block accepts EU into the network.", + AuthorColen }; + } + + @Override + public long maxAmperesOut() { + return 2; + } + + @Override + public ConnectionType getConnectionType() { + return ConnectionType.WIRELESS; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Wireless_Dynamo(mName, mTier, new String[] { "" }, mTextures); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPreTick(aBaseMetaTileEntity, aTick); + + if (aBaseMetaTileEntity.isServerSide()) { + + // On first tick find the player name and attempt to add them to the map. + if (aTick == 1) { + + // UUID and username of the owner. + owner_uuid = aBaseMetaTileEntity.getOwnerUuid(); + + strongCheckOrAddUser(owner_uuid); + } + + // Every ticks_between_energy_addition ticks change the energy content of the machine. + if (aTick % ticks_between_energy_addition == 0L) { + addEUToGlobalEnergyMap(owner_uuid, getEUVar()); + setEUVar(0L); + } + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java new file mode 100644 index 0000000000..bf624eadd7 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java @@ -0,0 +1,168 @@ +package gregtech.api.metatileentity.implementations; + +import static gregtech.api.enums.GT_Values.AuthorColen; +import static gregtech.api.enums.GT_Values.V; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static java.lang.Long.min; + +import java.math.BigInteger; +import java.util.UUID; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IWirelessEnergyHatchInformation; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.common.misc.spaceprojects.SpaceProjectManager; + +public class GT_MetaTileEntity_Wireless_Hatch extends GT_MetaTileEntity_Hatch_Energy + implements IWirelessEnergyHatchInformation { + + private final BigInteger eu_transferred_per_operation = BigInteger + .valueOf(2 * V[mTier] * ticks_between_energy_addition); + private final long eu_transferred_per_operation_long = eu_transferred_per_operation.longValue(); + + private UUID owner_uuid; + + public GT_MetaTileEntity_Wireless_Hatch(String aName, byte aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + public GT_MetaTileEntity_Wireless_Hatch(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, new String[] { "" }); + } + + @Override + public String[] getDescription() { + return new String[] { EnumChatFormatting.GRAY + "Stores energy globally in a network, up to 2^(2^31) EU.", + EnumChatFormatting.GRAY + "Does not connect to wires. This block withdraws EU from the network.", + AuthorColen }; + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI_WIRELESS_ON[mTier] }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, Textures.BlockIcons.OVERLAYS_ENERGY_IN_MULTI_WIRELESS_ON[mTier] }; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isEnetInput() { + return false; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 2 * V[mTier]; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxEUStore() { + return totalStorage(V[mTier]); + } + + @Override + public long maxAmperesIn() { + return 2; + } + + @Override + public ConnectionType getConnectionType() { + return ConnectionType.WIRELESS; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Wireless_Hatch(mName, mTier, new String[] { "" }, mTextures); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + + if (!aBaseMetaTileEntity.isServerSide()) return; + + // UUID of the owner. + owner_uuid = aBaseMetaTileEntity.getOwnerUuid(); + + SpaceProjectManager.checkOrCreateTeam(owner_uuid);; + + tryFetchingEnergy(); + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + + super.onPreTick(aBaseMetaTileEntity, aTick); + + if (aBaseMetaTileEntity.isServerSide()) { + // This is set up in a way to be as optimised as possible. If a user has a relatively plentiful energy + // network + // it should make no difference to them. Minimising the number of operations on BigInteger is essential. + + // Every ticks_between_energy_addition add eu_transferred_per_operation to internal EU storage from network. + if (aTick % ticks_between_energy_addition == 0L) { + tryFetchingEnergy(); + } + } + } + + private void tryFetchingEnergy() { + long currentEU = getBaseMetaTileEntity().getStoredEU(); + long maxEU = maxEUStore(); + long euToTransfer = min(maxEU - currentEU, eu_transferred_per_operation_long); + if (euToTransfer <= 0) return; // nothing to transfer + if (!addEUToGlobalEnergyMap(owner_uuid, -euToTransfer)) return; + setEUVar(currentEU + euToTransfer); + } +} |