diff options
Diffstat (limited to 'src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java')
-rw-r--r-- | src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java | 2538 |
1 files changed, 2538 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java new file mode 100644 index 0000000000..bf6358c884 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java @@ -0,0 +1,2538 @@ +package gregtech.api.metatileentity; + +import static gregtech.GT_Mod.GT_FML_LOGGER; +import static gregtech.api.enums.GT_Values.NW; +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFire; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.IAlignment; +import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructableProvider; + +import appeng.api.networking.IGridNode; +import appeng.api.networking.security.IActionHost; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; +import appeng.helpers.ICustomNameObject; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.tile.TileEvent; +import appeng.tile.events.TileEventType; +import cpw.mods.fml.relauncher.ReflectionHelper; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.graphs.GenerateNodeMap; +import gregtech.api.graphs.GenerateNodeMapPower; +import gregtech.api.graphs.Node; +import gregtech.api.interfaces.ICleanroom; +import gregtech.api.interfaces.ICleanroomReceiver; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IDebugableTileEntity; +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IGregtechWailaProvider; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.net.GT_Packet_TileEntity; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.objects.blockupdate.BlockUpdateHandler; +import gregtech.api.util.GT_CoverBehaviorBase; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.GT_Pollution; +import gregtech.common.covers.CoverInfo; +import ic2.api.Direction; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * This is the main TileEntity for EVERYTHING. + */ +public class BaseMetaTileEntity extends CommonMetaTileEntity + implements IGregTechTileEntity, IActionHost, IGridProxyable, IAlignmentProvider, IConstructableProvider, + IDebugableTileEntity, IGregtechWailaProvider, ICleanroomReceiver, ICustomNameObject { + + private static final Field ENTITY_ITEM_HEALTH_FIELD = ReflectionHelper + .findField(EntityItem.class, "health", "field_70291_e"); + private final boolean[] mActiveEUInputs = new boolean[] { false, false, false, false, false, false }; + private final boolean[] mActiveEUOutputs = new boolean[] { false, false, false, false, false, false }; + private final int[] mTimeStatistics = new int[GregTech_API.TICKS_FOR_LAG_AVERAGING]; + private boolean hasTimeStatisticsStarted; + public long mLastSoundTick = 0; + public boolean mWasShutdown = false; + public @Nonnull ShutDownReason lastShutDownReason = ShutDownReasonRegistry.NONE; + protected MetaTileEntity mMetaTileEntity; + protected long mStoredEnergy = 0, mStoredSteam = 0; + protected int mAverageEUInputIndex = 0, mAverageEUOutputIndex = 0; + protected boolean mReleaseEnergy = false; + protected final long[] mAverageEUInput = new long[] { 0, 0, 0, 0, 0 }; + protected final long[] mAverageEUOutput = new long[] { 0, 0, 0, 0, 0 }; + private boolean mHasEnoughEnergy = true, mRunningThroughTick = false, mInputDisabled = false, + mOutputDisabled = false, mMuffler = false, mLockUpgrade = false; + private boolean mActive = false, mWorkUpdate = false, mSteamConverter = false, mWorks = true; + private boolean oRedstone = false; + private byte mColor = 0, oColor = 0, oStrongRedstone = 0, oRedstoneData = 63, oTextureData = 0, oUpdateData = 0, + oTexturePage = 0; + private byte oLightValueClient = 0, oLightValue = -1, mLightValue = 0, mOtherUpgrades = 0, mWorkData = 0; + private ForgeDirection mFacing = ForgeDirection.DOWN, oFacing = ForgeDirection.DOWN; + private int mDisplayErrorCode = 0, oX = 0, oY = 0, oZ = 0, mTimeStatisticsIndex = 0, mLagWarningCount = 0; + private long oOutput = 0, mAcceptedAmperes = Long.MAX_VALUE; + private long mLastCheckTick = 0; + private String mOwnerName = ""; + private UUID mOwnerUuid = GT_Utility.defaultUuid; + private NBTTagCompound mRecipeStuff = new NBTTagCompound(); + private int cableUpdateDelay = 30; + + public BaseMetaTileEntity() {} + + @Override + public void writeToNBT(NBTTagCompound aNBT) { + try { + super.writeToNBT(aNBT); + } catch (Throwable e) { + GT_FML_LOGGER.error("Encountered CRITICAL ERROR while saving MetaTileEntity.", e); + } + try { + aNBT.setInteger("mID", mID); + aNBT.setLong("mStoredSteam", mStoredSteam); + aNBT.setLong("mStoredEnergy", mStoredEnergy); + writeCoverNBT(aNBT, false); + aNBT.setByte("mColor", mColor); + aNBT.setByte("mLightValue", mLightValue); + aNBT.setByte("mOtherUpgrades", mOtherUpgrades); + aNBT.setByte("mWorkData", mWorkData); + aNBT.setShort("mFacing", (short) mFacing.ordinal()); + aNBT.setString("mOwnerName", mOwnerName); + aNBT.setString("mOwnerUuid", mOwnerUuid == null ? "" : mOwnerUuid.toString()); + aNBT.setBoolean("mLockUpgrade", mLockUpgrade); + aNBT.setBoolean("mMuffler", mMuffler); + aNBT.setBoolean("mSteamConverter", mSteamConverter); + aNBT.setBoolean("mActive", mActive); + aNBT.setBoolean("mWorks", !mWorks); + aNBT.setBoolean("mInputDisabled", mInputDisabled); + aNBT.setBoolean("mOutputDisabled", mOutputDisabled); + aNBT.setTag("GT.CraftingComponents", mRecipeStuff); + } catch (Throwable e) { + GT_FML_LOGGER.error("Encountered CRITICAL ERROR while saving MetaTileEntity.", e); + } + saveMetaTileNBT(aNBT); + } + + @Override + public void readFromNBT(NBTTagCompound aNBT) { + super.readFromNBT(aNBT); + setInitialValuesAsNBT(aNBT, (short) 0); + } + + @Override + public void setInitialValuesAsNBT(NBTTagCompound aNBT, short aID) { + if (aNBT == null) { + if (aID > 0) mID = aID; + else mID = mID > 0 ? mID : 0; + if (mID != 0) createNewMetatileEntity(mID); + mSidedRedstone = (hasValidMetaTileEntity() && mMetaTileEntity.hasSidedRedstoneOutputBehavior() + ? new byte[] { 0, 0, 0, 0, 0, 0 } + : new byte[] { 15, 15, 15, 15, 15, 15 }); + } else { + if (aID <= 0) mID = (short) aNBT.getInteger("mID"); + else mID = aID; + mStoredSteam = aNBT.getLong("mStoredSteam"); + mStoredEnergy = aNBT.getLong("mStoredEnergy"); + mColor = aNBT.getByte("mColor"); + mLightValue = aNBT.getByte("mLightValue"); + mWorkData = aNBT.getByte("mWorkData"); + mFacing = oFacing = ForgeDirection.getOrientation(aNBT.getShort("mFacing")); + mOwnerName = aNBT.getString("mOwnerName"); + try { + mOwnerUuid = UUID.fromString(aNBT.getString("mOwnerUuid")); + } catch (IllegalArgumentException e) { + mOwnerUuid = null; + } + mLockUpgrade = aNBT.getBoolean("mLockUpgrade"); + mMuffler = aNBT.getBoolean("mMuffler"); + mSteamConverter = aNBT.getBoolean("mSteamConverter"); + mActive = aNBT.getBoolean("mActive"); + mWorks = !aNBT.getBoolean("mWorks"); + mInputDisabled = aNBT.getBoolean("mInputDisabled"); + mOutputDisabled = aNBT.getBoolean("mOutputDisabled"); + mOtherUpgrades = (byte) (aNBT.getByte("mOtherUpgrades") + aNBT.getByte("mBatteries") + + aNBT.getByte("mLiBatteries")); + + mRecipeStuff = aNBT.getCompoundTag("GT.CraftingComponents"); + final int nbtVersion = aNBT.getInteger("nbtVersion"); + readCoverNBT(aNBT); + loadMetaTileNBT(aNBT); + } + + if (mSidedRedstone.length != 6) + if (hasValidMetaTileEntity() && mMetaTileEntity.hasSidedRedstoneOutputBehavior()) + mSidedRedstone = new byte[] { 0, 0, 0, 0, 0, 0 }; + else mSidedRedstone = new byte[] { 15, 15, 15, 15, 15, 15 }; + + updateCoverBehavior(); + } + + /** + * Used for ticking special BaseMetaTileEntities, which need that for Energy Conversion It's called right before + * onPostTick() + */ + public void updateStatus() { + // + } + + /** + * Called when trying to charge Items + */ + public void chargeItem(ItemStack aStack) { + decreaseStoredEU( + GT_ModHandler.chargeElectricItem( + aStack, + (int) Math.min(Integer.MAX_VALUE, getStoredEU()), + (int) Math.min(Integer.MAX_VALUE, mMetaTileEntity.getOutputTier()), + false, + false), + true); + } + + /** + * Called when trying to discharge Items + */ + public void dischargeItem(ItemStack aStack) { + increaseStoredEnergyUnits( + GT_ModHandler.dischargeElectricItem( + aStack, + (int) Math.min(Integer.MAX_VALUE, getEUCapacity() - getStoredEU()), + (int) Math.min(Integer.MAX_VALUE, mMetaTileEntity.getInputTier()), + false, + false, + false), + true); + } + + protected boolean isRainPossible() { + BiomeGenBase biome = getBiome(); + // see net.minecraft.client.renderer.EntityRenderer.renderRainSnow + return biome.rainfall > 0 && (biome.canSpawnLightningBolt() || biome.getEnableSnow()); + } + + /** + * Check if this is exposed to rain + * + * @return True if exposed to rain, else false + */ + public boolean isRainExposed() { + final int precipitationHeightAtSide2 = worldObj.getPrecipitationHeight(xCoord, zCoord - 1); + final int precipitationHeightAtSide3 = worldObj.getPrecipitationHeight(xCoord, zCoord + 1); + final int precipitationHeightAtSide4 = worldObj.getPrecipitationHeight(xCoord - 1, zCoord); + final int precipitationHeightAtSide5 = worldObj.getPrecipitationHeight(xCoord + 1, zCoord); + return (getCoverIDAtSide(ForgeDirection.UP) == 0 + && worldObj.getPrecipitationHeight(xCoord, zCoord) - 2 < yCoord) + || (getCoverIDAtSide(ForgeDirection.NORTH) == 0 && precipitationHeightAtSide2 - 1 < yCoord + && precipitationHeightAtSide2 > -1) + || (getCoverIDAtSide(ForgeDirection.SOUTH) == 0 && precipitationHeightAtSide3 - 1 < yCoord + && precipitationHeightAtSide3 > -1) + || (getCoverIDAtSide(ForgeDirection.WEST) == 0 && precipitationHeightAtSide4 - 1 < yCoord + && precipitationHeightAtSide4 > -1) + || (getCoverIDAtSide(ForgeDirection.EAST) == 0 && precipitationHeightAtSide5 - 1 < yCoord + && precipitationHeightAtSide5 > -1); + } + + @Override + public void updateEntity() { + super.updateEntity(); + + if (!hasValidMetaTileEntity()) { + if (mMetaTileEntity == null) return; + mMetaTileEntity.setBaseMetaTileEntity(this); + } + + mRunningThroughTick = true; + long tTime; + if (hasTimeStatisticsStarted) { + tTime = System.nanoTime(); + } else { + tTime = 0; + } + final boolean aSideServer = isServerSide(); + final boolean aSideClient = isClientSide(); + + try { + if (hasValidMetaTileEntity()) { + if (mTickTimer++ == 0) { + oX = xCoord; + oY = yCoord; + oZ = zCoord; + if (aSideServer) { + checkDropCover(); + } else { + requestCoverDataIfNeeded(); + } + worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); + mMetaTileEntity.onFirstTick(this); + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + } + if (aSideClient) { + if (mColor != oColor) { + mMetaTileEntity.onColorChangeClient(oColor = mColor); + issueTextureUpdate(); + } + + if (mLightValue != oLightValueClient) { + worldObj.setLightValue(EnumSkyBlock.Block, xCoord, yCoord, zCoord, mLightValue); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord + 1, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord - 1, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord + 1, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord - 1, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord + 1); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord - 1); + oLightValueClient = mLightValue; + issueTextureUpdate(); + } + + if (mNeedsUpdate) { + if (GT_Mod.gregtechproxy.mUseBlockUpdateHandler) { + BlockUpdateHandler.Instance.enqueueBlockUpdate(worldObj, getLocation()); + } else { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + mNeedsUpdate = false; + } + } + if (aSideServer && mTickTimer > 10) { + if (!doCoverThings()) { + mRunningThroughTick = false; + return; + } + } + if (aSideServer) { + if (++mAverageEUInputIndex >= mAverageEUInput.length) mAverageEUInputIndex = 0; + if (++mAverageEUOutputIndex >= mAverageEUOutput.length) mAverageEUOutputIndex = 0; + + mAverageEUInput[mAverageEUInputIndex] = 0; + mAverageEUOutput[mAverageEUOutputIndex] = 0; + } + + mMetaTileEntity.onPreTick(this, mTickTimer); + + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + if (aSideServer) { + if (mRedstone != oRedstone || mTickTimer == 10) { + updateCoverBehavior(); + oRedstone = mRedstone; + issueBlockUpdate(); + } + if (mTickTimer == 10) joinEnet(); + + if (xCoord != oX || yCoord != oY || zCoord != oZ) { + oX = xCoord; + oY = yCoord; + oZ = zCoord; + issueClientUpdate(); + clearTileEntityBuffer(); + } + + if (mFacing != oFacing) { + oFacing = mFacing; + checkDropCover(); + issueBlockUpdate(); + } + + if (mTickTimer > 20 && mMetaTileEntity.isElectric()) { + mAcceptedAmperes = 0; + + if (getOutputVoltage() != oOutput) { + oOutput = getOutputVoltage(); + } + + if (mMetaTileEntity.isEnetOutput() || mMetaTileEntity.isEnetInput()) { + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + final int ordinalSide = side.ordinal(); + boolean temp = isEnergyInputSide(side); + if (temp != mActiveEUInputs[ordinalSide]) { + mActiveEUInputs[ordinalSide] = temp; + } + temp = isEnergyOutputSide(side); + if (temp != mActiveEUOutputs[ordinalSide]) { + mActiveEUOutputs[ordinalSide] = temp; + } + } + } + + if (mMetaTileEntity.isEnetOutput() && oOutput > 0) { + final long tOutputVoltage = Math + .max(oOutput, oOutput + (1L << Math.max(0, GT_Utility.getTier(oOutput) - 1))); + final long tUsableAmperage = Math.min( + getOutputAmperage(), + (getStoredEU() - mMetaTileEntity.getMinimumStoredEU()) / tOutputVoltage); + if (tUsableAmperage > 0) { + final long tEU = tOutputVoltage + * Util.emitEnergyToNetwork(oOutput, tUsableAmperage, this); + mAverageEUOutput[mAverageEUOutputIndex] += tEU; + decreaseStoredEU(tEU, true); + } + } + if (getEUCapacity() > 0) { + if (GregTech_API.sMachineFireExplosions && getRandomNumber(1000) == 0) { + final Block tBlock = getBlockAtSide(ForgeDirection.getOrientation(getRandomNumber(6))); + if (tBlock instanceof BlockFire) doEnergyExplosion(); + } + + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + + if (GregTech_API.sMachineRainExplosions) { + if (mMetaTileEntity.willExplodeInRain()) { + if (getRandomNumber(1000) == 0 && isRainPossible()) { + // Short-circuit so raincheck happens before isRainExposed, + // saves sme TPS since rain exposed check can be slow + // This logic can be compressed further by only checking for + // isRainExposed once IF we can guarantee it never thunders without + // raining, but I don't know if this is true or not. + if (worldObj.isRaining() && isRainExposed()) { + if (getRandomNumber(10) == 0) { + try { + GT_Mod.achievements.issueAchievement( + this.getWorldObj() + .getPlayerEntityByName(mOwnerName), + "badweather"); + } catch (Exception ignored) {} + GT_Log.exp.println( + "Machine at: " + this.getXCoord() + + " | " + + this.getYCoord() + + " | " + + this.getZCoord() + + " DIMID: " + + this.worldObj.provider.dimensionId + + " explosion due to rain!"); + doEnergyExplosion(); + } else { + GT_Log.exp.println( + "Machine at: " + this.getXCoord() + + " | " + + this.getYCoord() + + " | " + + this.getZCoord() + + " DIMID: " + + this.worldObj.provider.dimensionId + + " set to Fire due to rain!"); + setOnFire(); + } + } + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + if (GregTech_API.sMachineThunderExplosions && worldObj.isThundering() + && getRandomNumber(3) == 0 + && isRainExposed()) { + try { + GT_Mod.achievements.issueAchievement( + this.getWorldObj() + .getPlayerEntityByName(mOwnerName), + "badweather"); + } catch (Exception ignored) {} + GT_Log.exp.println( + "Machine at: " + this.getXCoord() + + " | " + + this.getYCoord() + + " | " + + this.getZCoord() + + " DIMID: " + + this.worldObj.provider.dimensionId + + " explosion due to Thunderstorm!"); + doEnergyExplosion(); + } + } + } + } + } + } + + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + } + if (aSideServer) { + if (mMetaTileEntity.dechargerSlotCount() > 0 && getStoredEU() < getEUCapacity()) { + for (int i = mMetaTileEntity.dechargerSlotStartIndex(), + k = mMetaTileEntity.dechargerSlotCount() + i; i < k; i++) { + if (mMetaTileEntity.mInventory[i] != null && getStoredEU() < getEUCapacity()) { + dischargeItem(mMetaTileEntity.mInventory[i]); + if (ic2.api.info.Info.itemEnergy.getEnergyValue(mMetaTileEntity.mInventory[i]) > 0) { + if ((getStoredEU() + + ic2.api.info.Info.itemEnergy.getEnergyValue(mMetaTileEntity.mInventory[i])) + < getEUCapacity()) { + increaseStoredEnergyUnits( + (long) ic2.api.info.Info.itemEnergy + .getEnergyValue(mMetaTileEntity.mInventory[i]), + false); + mMetaTileEntity.mInventory[i].stackSize--; + mInventoryChanged = true; + } + } + if (mMetaTileEntity.mInventory[i].stackSize <= 0) { + mMetaTileEntity.mInventory[i] = null; + mInventoryChanged = true; + } + } + } + } + } + if (aSideServer) { + if (mMetaTileEntity.rechargerSlotCount() > 0 && getStoredEU() > 0) { + for (int i = mMetaTileEntity.rechargerSlotStartIndex(), + k = mMetaTileEntity.rechargerSlotCount() + i; i < k; i++) { + if (getStoredEU() > 0 && mMetaTileEntity.mInventory[i] != null) { + chargeItem(mMetaTileEntity.mInventory[i]); + if (mMetaTileEntity.mInventory[i].stackSize <= 0) { + mMetaTileEntity.mInventory[i] = null; + mInventoryChanged = true; + } + } + } + } + } + updateStatus(); + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + mMetaTileEntity.onPostTick(this, mTickTimer); + if (!hasValidMetaTileEntity()) { + mRunningThroughTick = false; + return; + } + if (aSideServer) { + if (mTickTimer > 20 && cableUpdateDelay == 0) { + generatePowerNodes(); + } + cableUpdateDelay--; + if (mTickTimer % 10 == 0) { + sendClientData(); + } + + if (mTickTimer > 10) { + byte tData = (byte) ((mFacing.ordinal() & 7) | (mActive ? 8 : 0) + | (mRedstone ? 16 : 0) + | (mLockUpgrade ? 32 : 0) + | (mWorks ? 64 : 0) + | (mMuffler ? 128 : 0)); + if (tData != oTextureData) + sendBlockEvent(GregTechTileClientEvents.CHANGE_COMMON_DATA, oTextureData = tData); + + tData = mMetaTileEntity.getUpdateData(); + if (tData != oUpdateData) + sendBlockEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, oUpdateData = tData); + if (mMetaTileEntity instanceof GT_MetaTileEntity_Hatch) { + tData = ((GT_MetaTileEntity_Hatch) mMetaTileEntity).getTexturePage(); + if (tData != oTexturePage) sendBlockEvent( + GregTechTileClientEvents.CHANGE_CUSTOM_DATA, + (byte) ((oTexturePage = tData) | 0x80)); // set last bit as a flag for page + } + if (mColor != oColor) sendBlockEvent(GregTechTileClientEvents.CHANGE_COLOR, oColor = mColor); + tData = (byte) (((mSidedRedstone[0] > 0) ? 1 : 0) | ((mSidedRedstone[1] > 0) ? 2 : 0) + | ((mSidedRedstone[2] > 0) ? 4 : 0) + | ((mSidedRedstone[3] > 0) ? 8 : 0) + | ((mSidedRedstone[4] > 0) ? 16 : 0) + | ((mSidedRedstone[5] > 0) ? 32 : 0)); + if (tData != oRedstoneData) + sendBlockEvent(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, oRedstoneData = tData); + if (mLightValue != oLightValue) { + worldObj.setLightValue(EnumSkyBlock.Block, xCoord, yCoord, zCoord, mLightValue); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord + 1, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord - 1, yCoord, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord + 1, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord - 1, zCoord); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord + 1); + worldObj.updateLightByType(EnumSkyBlock.Block, xCoord, yCoord, zCoord - 1); + issueTextureUpdate(); + sendBlockEvent(GregTechTileClientEvents.CHANGE_LIGHT, oLightValue = mLightValue); + } + } + + if (mNeedsBlockUpdate) { + updateNeighbours(mStrongRedstone, oStrongRedstone); + oStrongRedstone = mStrongRedstone; + mNeedsBlockUpdate = false; + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + e.printStackTrace(GT_Log.err); + try { + mMetaTileEntity.onTickFail(this, mTickTimer); + } catch (Throwable ex) { + ex.printStackTrace(); + ex.printStackTrace(GT_Log.err); + } + } + + if (aSideServer && hasTimeStatisticsStarted && hasValidMetaTileEntity()) { + tTime = System.nanoTime() - tTime; + mTimeStatisticsIndex = (mTimeStatisticsIndex + 1) % mTimeStatistics.length; + mTimeStatistics[mTimeStatisticsIndex] = (int) tTime; + if (tTime > 0 && tTime > (GregTech_API.MILLISECOND_THRESHOLD_UNTIL_LAG_WARNING * 1_000_000L) + && mTickTimer > 1000 + && getMetaTileEntity().doTickProfilingMessageDuringThisTick() + && mLagWarningCount++ < 10) + GT_FML_LOGGER.warn( + "WARNING: Possible Lag Source at [" + xCoord + + ", " + + yCoord + + ", " + + zCoord + + "] in Dimension " + + worldObj.provider.dimensionId + + " with " + + tTime + + "ns caused by an instance of " + + getMetaTileEntity().getClass()); + } + + mWorkUpdate = mInventoryChanged = mRunningThroughTick = false; + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + if (hasValidMetaTileEntity()) { + getMetaTileEntity().getWailaBody(itemStack, currentTip, accessor, 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); + if (hasValidMetaTileEntity()) { + getMetaTileEntity().getWailaNBTData(player, tile, tag, world, x, y, z); + } + } + + private void sendClientData() { + if (mSendClientData) { + NW.sendPacketToAllPlayersInRange( + worldObj, + new GT_Packet_TileEntity( + xCoord, + (short) yCoord, + zCoord, + mID, + getCoverInfoAtSide(ForgeDirection.DOWN).getCoverID(), + getCoverInfoAtSide(ForgeDirection.UP).getCoverID(), + getCoverInfoAtSide(ForgeDirection.NORTH).getCoverID(), + getCoverInfoAtSide(ForgeDirection.SOUTH).getCoverID(), + getCoverInfoAtSide(ForgeDirection.WEST).getCoverID(), + getCoverInfoAtSide(ForgeDirection.EAST).getCoverID(), + oTextureData = (byte) ((mFacing.ordinal() & 7) | (mActive ? 8 : 0) + | (mRedstone ? 16 : 0) + | (mLockUpgrade ? 32 : 0) + | (mWorks ? 64 : 0)), + oTexturePage = (hasValidMetaTileEntity() && mMetaTileEntity instanceof GT_MetaTileEntity_Hatch) + ? ((GT_MetaTileEntity_Hatch) mMetaTileEntity).getTexturePage() + : 0, + oUpdateData = hasValidMetaTileEntity() ? mMetaTileEntity.getUpdateData() : 0, + oRedstoneData = (byte) (((mSidedRedstone[0] > 0) ? 1 : 0) | ((mSidedRedstone[1] > 0) ? 2 : 0) + | ((mSidedRedstone[2] > 0) ? 4 : 0) + | ((mSidedRedstone[3] > 0) ? 8 : 0) + | ((mSidedRedstone[4] > 0) ? 16 : 0) + | ((mSidedRedstone[5] > 0) ? 32 : 0)), + oColor = mColor), + xCoord, + zCoord); + mSendClientData = false; + } + sendCoverDataIfNeeded(); + } + + public final void receiveMetaTileEntityData(short aID, int aCover0, int aCover1, int aCover2, int aCover3, + int aCover4, int aCover5, byte aTextureData, byte aTexturePage, byte aUpdateData, byte aRedstoneData, + byte aColorData) { + issueTextureUpdate(); + if (mID != aID && aID > 0) { + mID = aID; + createNewMetatileEntity(mID); + } + + setCoverIDAtSide(ForgeDirection.DOWN, aCover0); + setCoverIDAtSide(ForgeDirection.UP, aCover1); + setCoverIDAtSide(ForgeDirection.NORTH, aCover2); + setCoverIDAtSide(ForgeDirection.SOUTH, aCover3); + setCoverIDAtSide(ForgeDirection.WEST, aCover4); + setCoverIDAtSide(ForgeDirection.EAST, aCover5); + + receiveClientEvent(GregTechTileClientEvents.CHANGE_COMMON_DATA, aTextureData); + receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aUpdateData & 0x7F); + receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aTexturePage | 0x80); + receiveClientEvent(GregTechTileClientEvents.CHANGE_COLOR, aColorData); + receiveClientEvent(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, aRedstoneData); + } + + @Override + public boolean receiveClientEvent(int aEventID, int aValue) { + super.receiveClientEvent(aEventID, aValue); + + if (hasValidMetaTileEntity()) { + try { + mMetaTileEntity.receiveClientEvent((byte) aEventID, (byte) aValue); + } catch (Throwable e) { + GT_Log.err.println( + "Encountered Exception while receiving Data from the Server, the Client should've been crashed by now, but I prevented that. Please report immediately to GregTech Intergalactical!!!"); + e.printStackTrace(GT_Log.err); + } + } + + if (isClientSide()) { + issueTextureUpdate(); + switch (aEventID) { + case GregTechTileClientEvents.CHANGE_COMMON_DATA -> { + mFacing = ForgeDirection.getOrientation((byte) (aValue & 7)); + mActive = ((aValue & 8) != 0); + mRedstone = ((aValue & 16) != 0); + // mLockUpgrade = ((aValue&32) != 0); + mWorks = ((aValue & 64) != 0); + mMuffler = ((aValue & 128) != 0); + } + case GregTechTileClientEvents.CHANGE_CUSTOM_DATA -> { + if (hasValidMetaTileEntity()) { + if ((aValue & 0x80) == 0) // Is texture index + mMetaTileEntity.onValueUpdate((byte) (aValue & 0x7F)); + else if (mMetaTileEntity instanceof GT_MetaTileEntity_Hatch) // is texture page and hatch + ((GT_MetaTileEntity_Hatch) mMetaTileEntity).onTexturePageUpdate((byte) (aValue & 0x7F)); + } + } + case GregTechTileClientEvents.CHANGE_COLOR -> { + if (aValue > 16 || aValue < 0) aValue = 0; + mColor = (byte) aValue; + } + case GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT -> { + mSidedRedstone[0] = (byte) ((aValue & 1) == 1 ? 15 : 0); + mSidedRedstone[1] = (byte) ((aValue & 2) == 2 ? 15 : 0); + mSidedRedstone[2] = (byte) ((aValue & 4) == 4 ? 15 : 0); + mSidedRedstone[3] = (byte) ((aValue & 8) == 8 ? 15 : 0); + mSidedRedstone[4] = (byte) ((aValue & 16) == 16 ? 15 : 0); + mSidedRedstone[5] = (byte) ((aValue & 32) == 32 ? 15 : 0); + } + case GregTechTileClientEvents.DO_SOUND -> { + if (hasValidMetaTileEntity() && mTickTimer > 20) + mMetaTileEntity.doSound((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); + } + case GregTechTileClientEvents.START_SOUND_LOOP -> { + if (hasValidMetaTileEntity() && mTickTimer > 20) + mMetaTileEntity.startSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); + } + case GregTechTileClientEvents.STOP_SOUND_LOOP -> { + if (hasValidMetaTileEntity() && mTickTimer > 20) + mMetaTileEntity.stopSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); + } + case GregTechTileClientEvents.CHANGE_LIGHT -> mLightValue = (byte) aValue; + } + } + return true; + } + + @Override + public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aLogLevel) { + final ArrayList<String> tList = new ArrayList<>(); + if (aLogLevel > 2) { + tList.add( + "Meta-ID: " + EnumChatFormatting.BLUE + + mID + + EnumChatFormatting.RESET + + (canAccessData() ? EnumChatFormatting.GREEN + " valid" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + " invalid" + EnumChatFormatting.RESET) + + (mMetaTileEntity == null + ? EnumChatFormatting.RED + " MetaTileEntity == null!" + EnumChatFormatting.RESET + : " ")); + } + if (aLogLevel > 1 && mMetaTileEntity != null) { + if (hasTimeStatisticsStarted) { + double tAverageTime = 0; + double tWorstTime = 0; + int amountOfZero = 0; + for (int tTime : mTimeStatistics) { + tAverageTime += tTime; + if (tTime > tWorstTime) { + tWorstTime = tTime; + } + if (tTime == 0) { + amountOfZero += 1; + } + // Uncomment this line to print out tick-by-tick times. + // tList.add("tTime " + tTime); + } + // tick time zero means it has not been updated yet + int samples = mTimeStatistics.length - amountOfZero; + if (samples > 0) { + tList.add( + "Average CPU load of ~" + GT_Utility.formatNumbers(tAverageTime / samples) + + "ns over " + + GT_Utility.formatNumbers(samples) + + " ticks with worst time of " + + GT_Utility.formatNumbers(tWorstTime) + + "ns."); + } + } else { + startTimeStatistics(); + tList.add("Just started tick time statistics."); + } + tList.add( + "Recorded " + GT_Utility.formatNumbers(mMetaTileEntity.mSoundRequests) + + " sound requests in " + + GT_Utility.formatNumbers(mTickTimer - mLastCheckTick) + + " ticks."); + mLastCheckTick = mTickTimer; + mMetaTileEntity.mSoundRequests = 0; + if (mLagWarningCount > 0) { + tList.add( + "Caused " + (mLagWarningCount >= 10 ? "more than 10" : mLagWarningCount) + + " Lag Spike Warnings (anything taking longer than " + + GregTech_API.MILLISECOND_THRESHOLD_UNTIL_LAG_WARNING + + "ms) on the Server."); + } + tList.add( + "Is" + (mMetaTileEntity.isAccessAllowed(aPlayer) ? " " + : EnumChatFormatting.RED + " not " + EnumChatFormatting.RESET) + "accessible for you"); + } + if (aLogLevel > 0) { + if (getSteamCapacity() > 0 && hasSteamEngineUpgrade()) tList.add( + GT_Utility.formatNumbers(getStoredSteam()) + " of " + + GT_Utility.formatNumbers(getSteamCapacity()) + + " Steam"); + tList.add( + "Machine is " + (mActive ? EnumChatFormatting.GREEN + "active" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "inactive" + EnumChatFormatting.RESET)); + if (!mHasEnoughEnergy) tList + .add(EnumChatFormatting.RED + "ATTENTION: This Device needs more power." + EnumChatFormatting.RESET); + } + if (joinedIc2Enet) tList.add("Joined IC2 ENet"); + return mMetaTileEntity.getSpecialDebugInfo(this, aPlayer, aLogLevel, tList); + } + + @Override + public boolean isGivingInformation() { + if (canAccessData()) return mMetaTileEntity.isGivingInformation(); + return false; + } + + @Override + public ForgeDirection getBackFacing() { + return mFacing.getOpposite(); + } + + @Override + public ForgeDirection getFrontFacing() { + return mFacing; + } + + @Override + public void setFrontFacing(ForgeDirection aFacing) { + if (isValidFacing(aFacing)) { + mFacing = aFacing; + mMetaTileEntity.onFacingChange(); + + doEnetUpdate(); + cableUpdateDelay = 10; + + if (mMetaTileEntity.shouldTriggerBlockUpdate()) { + // If we're triggering a block update this will call onMachineBlockUpdate() + GregTech_API.causeMachineUpdate(worldObj, xCoord, yCoord, zCoord); + } else { + // If we're not trigger a cascading one, call the update here. + onMachineBlockUpdate(); + } + } + } + + @Override + public int getSizeInventory() { + if (canAccessData()) return mMetaTileEntity.getSizeInventory(); + return 0; + } + + @Override + public ItemStack getStackInSlot(int aIndex) { + if (canAccessData()) return mMetaTileEntity.getStackInSlot(aIndex); + return null; + } + + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + mInventoryChanged = true; + if (canAccessData()) { + markDirty(); + mMetaTileEntity.setInventorySlotContents( + aIndex, + worldObj.isRemote ? aStack : GT_OreDictUnificator.setStack(true, aStack)); + } + } + + @Override + public String getInventoryName() { + if (canAccessData()) return mMetaTileEntity.getInventoryName(); + if (GregTech_API.METATILEENTITIES[mID] != null) return GregTech_API.METATILEENTITIES[mID].getInventoryName(); + return ""; + } + + @Override + public int getInventoryStackLimit() { + if (canAccessData()) return mMetaTileEntity.getInventoryStackLimit(); + return 64; + } + + @Override + public void openInventory() { + if (canAccessData()) mMetaTileEntity.onOpenGUI(); + } + + @Override + public void closeInventory() { + if (canAccessData()) mMetaTileEntity.onCloseGUI(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer aPlayer) { + return canAccessData() && playerOwnsThis(aPlayer, false) + && mTickTimer > 1 + && getTileEntityOffset(0, 0, 0) == this + && aPlayer.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64 + && mMetaTileEntity.isAccessAllowed(aPlayer); + } + + @Override + public void validate() { + super.validate(); + mTickTimer = 0; + } + + @Override + public void invalidate() { + tileEntityInvalid = false; + leaveEnet(); + if (canAccessData()) { + invalidateAE(); + mMetaTileEntity.onRemoval(); + mMetaTileEntity.setBaseMetaTileEntity(null); + } + super.invalidate(); + } + + @Override + public void onChunkUnload() { + if (canAccessData()) { + mMetaTileEntity.onUnload(); + } + + super.onChunkUnload(); + onChunkUnloadAE(); + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + final ItemStack stack = getStackInSlot(slot); + if (stack != null) setInventorySlotContents(slot, null); + return stack; + } + + /** + * Checks validity of meta tile and delegates to it + */ + @Override + public void onMachineBlockUpdate() { + if (canAccessData()) mMetaTileEntity.onMachineBlockUpdate(); + cableUpdateDelay = 10; + } + + /** + * Checks validity of meta tile and delegates to it + */ + @Override + public boolean isMachineBlockUpdateRecursive() { + return canAccessData() && mMetaTileEntity.isMachineBlockUpdateRecursive(); + } + + @Override + public int getProgress() { + return canAccessData() ? mMetaTileEntity.getProgresstime() : 0; + } + + @Override + public int getMaxProgress() { + return canAccessData() ? mMetaTileEntity.maxProgresstime() : 0; + } + + @Override + public boolean increaseProgress(int aProgressAmountInTicks) { + return canAccessData() && mMetaTileEntity.increaseProgress(aProgressAmountInTicks) != aProgressAmountInTicks; + } + + @Override + public boolean hasThingsToDo() { + return getMaxProgress() > 0; + } + + @Override + public void enableWorking() { + if (!mWorks) mWorkUpdate = true; + mWorks = true; + mWasShutdown = false; + } + + @Override + public void disableWorking() { + mWorks = false; + if (hasValidMetaTileEntity()) { + mMetaTileEntity.onDisableWorking(); + } + } + + @Override + public boolean isAllowedToWork() { + return mWorks; + } + + @Override + public boolean hasWorkJustBeenEnabled() { + return mWorkUpdate; + } + + @Override + public byte getWorkDataValue() { + return mWorkData; + } + + @Override + public void setWorkDataValue(byte aValue) { + mWorkData = aValue; + } + + @Override + public int getMetaTileID() { + return mID; + } + + @Override + public int setMetaTileID(short aID) { + return mID = aID; + } + + @Override + public boolean isActive() { + return mActive; + } + + @Override + public void setActive(boolean aActive) { + mActive = aActive; + if (hasValidMetaTileEntity()) { + mMetaTileEntity.onSetActive(aActive); + } + } + + @Override + public long getTimer() { + return mTickTimer; + } + + @Override + public boolean decreaseStoredEnergyUnits(long aEnergy, boolean aIgnoreTooLessEnergy) { + if (!canAccessData()) return false; + return mHasEnoughEnergy = decreaseStoredEU(aEnergy, aIgnoreTooLessEnergy) || decreaseStoredSteam(aEnergy, false) + || (aIgnoreTooLessEnergy && (decreaseStoredSteam(aEnergy, true))); + } + + @Override + public boolean increaseStoredEnergyUnits(long aEnergy, boolean aIgnoreTooMuchEnergy) { + if (!canAccessData()) return false; + if (getStoredEU() < getEUCapacity() || aIgnoreTooMuchEnergy) { + setStoredEU(mMetaTileEntity.getEUVar() + aEnergy); + return true; + } + return false; + } + + @Override + public boolean inputEnergyFrom(ForgeDirection side) { + return inputEnergyFrom(side, true); + } + + @Override + public boolean inputEnergyFrom(ForgeDirection side, boolean waitForActive) { + if (side == ForgeDirection.UNKNOWN) return true; + if (isServerSide() && waitForActive) return mActiveEUInputs[side.ordinal()] && !mReleaseEnergy; + return isEnergyInputSide(side); + } + + @Override + public boolean outputsEnergyTo(ForgeDirection side) { + return outputsEnergyTo(side, true); + } + + @Override + public boolean outputsEnergyTo(ForgeDirection side, boolean waitForActive) { + if (side == ForgeDirection.UNKNOWN) return true; + if (isServerSide() && waitForActive) return (mActiveEUOutputs[side.ordinal()]) || mReleaseEnergy; + return isEnergyOutputSide(side); + } + + @Override + public boolean isEnetOutput() { + return mMetaTileEntity != null && mMetaTileEntity.isEnetOutput(); + } + + @Override + public boolean isEnetInput() { + return mMetaTileEntity != null && mMetaTileEntity.isEnetInput(); + } + + public void generatePowerNodes() { + if (isServerSide() && (isEnetInput() || isEnetOutput())) { + final int time = MinecraftServer.getServer() + .getTickCounter(); + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (outputsEnergyTo(side, false) || inputEnergyFrom(side, false)) { + final IGregTechTileEntity TE = getIGregTechTileEntityAtSide(side); + if (TE instanceof BaseMetaPipeEntity) { + final Node node = ((BaseMetaPipeEntity) TE).getNode(); + if (node == null) { + new GenerateNodeMapPower((BaseMetaPipeEntity) TE); + } else if (node.mCreationTime != time) { + GenerateNodeMap.clearNodeMap(node, -1); + new GenerateNodeMapPower((BaseMetaPipeEntity) TE); + } + } + } + } + } + } + + @Override + public long getOutputAmperage() { + if (canAccessData() && mMetaTileEntity.isElectric()) return mMetaTileEntity.maxAmperesOut(); + return 0; + } + + @Override + public long getOutputVoltage() { + if (canAccessData() && mMetaTileEntity.isElectric() && mMetaTileEntity.isEnetOutput()) + return mMetaTileEntity.maxEUOutput(); + return 0; + } + + @Override + public long getInputAmperage() { + if (canAccessData() && mMetaTileEntity.isElectric()) return mMetaTileEntity.maxAmperesIn(); + return 0; + } + + @Override + public long getInputVoltage() { + if (canAccessData() && mMetaTileEntity.isElectric()) return mMetaTileEntity.maxEUInput(); + return Integer.MAX_VALUE; + } + + @Override + public boolean increaseStoredSteam(long aEnergy, boolean aIgnoreTooMuchEnergy) { + if (!canAccessData()) return false; + if (mMetaTileEntity.getSteamVar() < getSteamCapacity() || aIgnoreTooMuchEnergy) { + setStoredSteam(mMetaTileEntity.getSteamVar() + aEnergy); + return true; + } + return false; + } + + @Override + public long getUniversalEnergyStored() { + return Math.max(getStoredEU(), getStoredSteam()); + } + + @Override + public long getUniversalEnergyCapacity() { + return Math.max(getEUCapacity(), getSteamCapacity()); + } + + @Override + public long getStoredEU() { + if (canAccessData()) return Math.min(mMetaTileEntity.getEUVar(), getEUCapacity()); + return 0; + } + + @Override + public long getEUCapacity() { + if (canAccessData()) return mMetaTileEntity.maxEUStore(); + return 0; + } + + @Override + public long getStoredSteam() { + if (canAccessData()) return Math.min(mMetaTileEntity.getSteamVar(), getSteamCapacity()); + return 0; + } + + @Override + public long getSteamCapacity() { + if (canAccessData()) return mMetaTileEntity.maxSteamStore(); + return 0; + } + + @Override + public ITexture[] getTexture(Block aBlock, ForgeDirection side) { + final ITexture coverTexture = getCoverTexture(side); + final ITexture[] textureUncovered = hasValidMetaTileEntity() + ? mMetaTileEntity + .getTexture(this, side, mFacing, (byte) (mColor - 1), mActive, getOutputRedstoneSignal(side) > 0) + : Textures.BlockIcons.ERROR_RENDERING; + final ITexture[] textureCovered; + if (coverTexture != null) { + textureCovered = Arrays.copyOf(textureUncovered, textureUncovered.length + 1); + textureCovered[textureUncovered.length] = coverTexture; + return textureCovered; + } else { + return textureUncovered; + } + } + + private boolean isEnergyInputSide(ForgeDirection side) { + if (side != ForgeDirection.UNKNOWN) { + if (!getCoverInfoAtSide(side).letsEnergyIn()) return false; + if (isInvalid() || mReleaseEnergy) return false; + if (canAccessData() && mMetaTileEntity.isElectric() && mMetaTileEntity.isEnetInput()) + return mMetaTileEntity.isInputFacing(side); + } + return false; + } + + private boolean isEnergyOutputSide(ForgeDirection side) { + if (side != ForgeDirection.UNKNOWN) { + if (!getCoverInfoAtSide(side).letsEnergyOut()) return false; + if (isInvalid() || mReleaseEnergy) return mReleaseEnergy; + if (canAccessData() && mMetaTileEntity.isElectric() && mMetaTileEntity.isEnetOutput()) + return mMetaTileEntity.isOutputFacing(side); + } + return false; + } + + @Override + protected boolean hasValidMetaTileEntity() { + return mMetaTileEntity != null && mMetaTileEntity.getBaseMetaTileEntity() == this; + } + + @Override + protected boolean canAccessData() { + return !isDead && hasValidMetaTileEntity(); + } + + public boolean setStoredEU(long aEnergy) { + if (!canAccessData()) return false; + if (aEnergy < 0) aEnergy = 0; + mMetaTileEntity.setEUVar(aEnergy); + return true; + } + + public boolean setStoredSteam(long aEnergy) { + if (!canAccessData()) return false; + if (aEnergy < 0) aEnergy = 0; + mMetaTileEntity.setSteamVar(aEnergy); + return true; + } + + public boolean decreaseStoredEU(long aEnergy, boolean aIgnoreTooLessEnergy) { + if (!canAccessData()) { + return false; + } + if (mMetaTileEntity.getEUVar() - aEnergy >= 0 || aIgnoreTooLessEnergy) { + setStoredEU(mMetaTileEntity.getEUVar() - aEnergy); + if (mMetaTileEntity.getEUVar() < 0) { + setStoredEU(0); + return false; + } + return true; + } + return false; + } + + public boolean decreaseStoredSteam(long aEnergy, boolean aIgnoreTooLessEnergy) { + if (!canAccessData()) return false; + if (mMetaTileEntity.getSteamVar() - aEnergy >= 0 || aIgnoreTooLessEnergy) { + setStoredSteam(mMetaTileEntity.getSteamVar() - aEnergy); + if (mMetaTileEntity.getSteamVar() < 0) { + setStoredSteam(0); + return false; + } + return true; + } + return false; + } + + public boolean playerOwnsThis(EntityPlayer aPlayer, boolean aCheckPrecicely) { + if (!canAccessData()) return false; + if (aCheckPrecicely || privateAccess() || (mOwnerName.length() == 0)) + if ((mOwnerName.length() == 0) && isServerSide()) { + setOwnerName(aPlayer.getDisplayName()); + setOwnerUuid(aPlayer.getUniqueID()); + } else return !privateAccess() || aPlayer.getDisplayName() + .equals("Player") || mOwnerName.equals("Player") || mOwnerName.equals(aPlayer.getDisplayName()); + return true; + } + + public boolean privateAccess() { + if (!canAccessData()) return mLockUpgrade; + return mLockUpgrade || mMetaTileEntity.ownerControl(); + } + + @Nullable + @Override + public ICleanroom getCleanroom() { + if (canAccessData()) { + return mMetaTileEntity.getCleanroom(); + } + return null; + } + + @Override + public void setCleanroom(ICleanroom cleanroom) { + if (canAccessData()) { + mMetaTileEntity.setCleanroom(cleanroom); + } + } + + public void doEnergyExplosion() { + if (getUniversalEnergyCapacity() > 0 && getUniversalEnergyStored() >= getUniversalEnergyCapacity() / 5) { + GT_Log.exp.println( + "Energy Explosion, injected " + getUniversalEnergyStored() + + "EU >= " + + getUniversalEnergyCapacity() / 5D + + "Capacity of the Machine!"); + + doExplosion( + oOutput * (getUniversalEnergyStored() >= getUniversalEnergyCapacity() ? 4 + : getUniversalEnergyStored() >= getUniversalEnergyCapacity() / 2 ? 2 : 1)); + GT_Mod.achievements.issueAchievement( + this.getWorldObj() + .getPlayerEntityByName(mOwnerName), + "electricproblems"); + } + } + + @Override + public void doExplosion(long aAmount) { + if (canAccessData()) { + // This is only for Electric Machines + if (GregTech_API.sMachineWireFire && mMetaTileEntity.isElectric()) { + try { + mReleaseEnergy = true; + IEnergyConnected.Util.emitEnergyToNetwork(V[5], Math.max(1, getStoredEU() / V[5]), this); + } catch (Exception ignored) {} + } + mReleaseEnergy = false; + // Normal Explosion Code + mMetaTileEntity.onExplosion(); + if (GT_Mod.gregtechproxy.mExplosionItemDrop) { + for (int i = 0; i < this.getSizeInventory(); i++) { + final ItemStack tItem = this.getStackInSlot(i); + if ((tItem != null) && (tItem.stackSize > 0) && (this.isValidSlot(i))) { + dropItems(tItem); + this.setInventorySlotContents(i, null); + } + } + } + if (mRecipeStuff != null) { + for (int i = 0; i < 9; i++) { + if (this.getRandomNumber(100) < 50) { + dropItems(GT_Utility.loadItem(mRecipeStuff, "Ingredient." + i)); + } + } + } + + GT_Pollution.addPollution((TileEntity) this, GT_Mod.gregtechproxy.mPollutionOnExplosion); + mMetaTileEntity.doExplosion(aAmount); + } + } + + public void dropItems(ItemStack tItem) { + if (tItem == null) return; + final EntityItem tItemEntity = new EntityItem( + this.worldObj, + this.xCoord + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + this.yCoord + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + this.zCoord + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + new ItemStack(tItem.getItem(), tItem.stackSize, tItem.getItemDamage())); + if (tItem.hasTagCompound()) { + tItemEntity.getEntityItem() + .setTagCompound( + (NBTTagCompound) tItem.getTagCompound() + .copy()); + } + tItemEntity.motionX = (XSTR_INSTANCE.nextGaussian() * 0.0500000007450581D); + tItemEntity.motionY = (XSTR_INSTANCE.nextGaussian() * 0.0500000007450581D + 0.2000000029802322D); + tItemEntity.motionZ = (XSTR_INSTANCE.nextGaussian() * 0.0500000007450581D); + tItemEntity.hurtResistantTime = 999999; + tItemEntity.lifespan = 60000; + try { + ENTITY_ITEM_HEALTH_FIELD.setInt(tItemEntity, 99999999); + } catch (Exception ignored) {} + this.worldObj.spawnEntityInWorld(tItemEntity); + tItem.stackSize = 0; + } + + @Override + public ArrayList<ItemStack> getDrops() { + final ItemStack rStack = new ItemStack(GregTech_API.sBlockMachines, 1, mID); + final NBTTagCompound tNBT = new NBTTagCompound(); + if (mRecipeStuff != null && !mRecipeStuff.hasNoTags()) tNBT.setTag("GT.CraftingComponents", mRecipeStuff); + if (mMuffler) tNBT.setBoolean("mMuffler", mMuffler); + if (mLockUpgrade) tNBT.setBoolean("mLockUpgrade", mLockUpgrade); + if (mSteamConverter) tNBT.setBoolean("mSteamConverter", mSteamConverter); + if (mColor > 0) tNBT.setByte("mColor", mColor); + if (mOtherUpgrades > 0) tNBT.setByte("mOtherUpgrades", mOtherUpgrades); + + writeCoverNBT(tNBT, true); + + if (hasValidMetaTileEntity()) mMetaTileEntity.setItemNBT(tNBT); + if (!tNBT.hasNoTags()) rStack.setTagCompound(tNBT); + + onBaseTEDestroyed(); + return new ArrayList<>(Collections.singletonList(rStack)); + } + + @Override + public boolean shouldDropItemAt(int index) { + return this.mMetaTileEntity == null || this.mMetaTileEntity.shouldDropItemAt(index); + } + + public int getUpgradeCount() { + return (mMuffler ? 1 : 0) + (mLockUpgrade ? 1 : 0) + (mSteamConverter ? 1 : 0) + mOtherUpgrades; + } + + @Override + public boolean onRightclick(EntityPlayer aPlayer, ForgeDirection side, float aX, float aY, float aZ) { + if (isClientSide()) { + // Configure Cover, sneak can also be: screwdriver, wrench, side cutter, soldering iron + if (aPlayer.isSneaking()) { + final ForgeDirection tSide = (getCoverIDAtSide(side) == 0) + ? GT_Utility.determineWrenchingSide(side, aX, aY, aZ) + : side; + return (getCoverBehaviorAtSideNew(tSide).hasCoverGUI()); + } else if (getCoverBehaviorAtSideNew(side).onCoverRightclickClient(side, this, aPlayer, aX, aY, aZ)) { + return true; + } + + if (!getCoverInfoAtSide(side).isGUIClickable()) return false; + } + + if (isServerSide()) { + if (!privateAccess() || aPlayer.getDisplayName() + .equalsIgnoreCase(getOwnerName())) { + final ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem(); + if (tCurrentItem != null) { + if (getColorization() >= 0 + && GT_Utility.areStacksEqual(new ItemStack(Items.water_bucket, 1), tCurrentItem)) { + tCurrentItem.func_150996_a(Items.bucket); + setColorization((byte) (getColorization() >= 16 ? -2 : -1)); + return true; + } + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWrenchList)) { + if (aPlayer.isSneaking() && mMetaTileEntity instanceof GT_MetaTileEntity_BasicMachine + && ((GT_MetaTileEntity_BasicMachine) mMetaTileEntity) + .setMainFacing(GT_Utility.determineWrenchingSide(side, aX, aY, aZ))) { + GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_WRENCH, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + cableUpdateDelay = 10; + } else if (mMetaTileEntity.onWrenchRightClick( + side, + GT_Utility.determineWrenchingSide(side, aX, aY, aZ), + aPlayer, + aX, + aY, + aZ, + tCurrentItem)) { + GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_WRENCH, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + cableUpdateDelay = 10; + } + return true; + } + + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sScrewdriverList)) { + if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 200, aPlayer)) { + setCoverDataAtSide( + side, + getCoverBehaviorAtSideNew(side).onCoverScrewdriverClick( + side, + getCoverIDAtSide(side), + getComplexCoverDataAtSide(side), + this, + aPlayer, + aX, + aY, + aZ)); + mMetaTileEntity.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ, tCurrentItem); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_WRENCH, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + } + return true; + } + + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sHardHammerList)) { + if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer)) { + mInputDisabled = !mInputDisabled; + if (mInputDisabled) mOutputDisabled = !mOutputDisabled; + GT_Utility.sendChatToPlayer( + aPlayer, + GT_Utility.trans("086", "Auto-Input: ") + (mInputDisabled + ? GT_Utility.trans("087", "Disabled") + : GT_Utility.trans("088", "Enabled") + GT_Utility.trans("089", " Auto-Output: ") + + (mOutputDisabled ? GT_Utility.trans("087", "Disabled") + : GT_Utility.trans("088", "Enabled")))); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.RANDOM_ANVIL_USE, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + } + return true; + } + + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSoftHammerList)) { + if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer)) { + if (mWorks) disableWorking(); + else enableWorking(); + { + String tChat = GT_Utility.trans("090", "Machine Processing: ") + + (isAllowedToWork() ? GT_Utility.trans("088", "Enabled") + : GT_Utility.trans("087", "Disabled")); + if (getMetaTileEntity() != null && getMetaTileEntity().hasAlternativeModeText()) + tChat = getMetaTileEntity().getAlternativeModeText(); + GT_Utility.sendChatToPlayer(aPlayer, tChat); + } + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_RUBBER_TRAMPOLINE, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + } + return true; + } + + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSolderingToolList)) { + final ForgeDirection tSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ); + if (mMetaTileEntity.onSolderingToolRightClick(side, tSide, aPlayer, aX, aY, aZ, tCurrentItem)) { + // logic handled internally + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_BATTERY_USE, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + } else if (GT_ModHandler.useSolderingIron(tCurrentItem, aPlayer)) { + mStrongRedstone ^= tSide.flag; + GT_Utility.sendChatToPlayer( + aPlayer, + GT_Utility.trans("091", "Redstone Output at Side ") + tSide + + GT_Utility.trans("092", " set to: ") + + ((mStrongRedstone & tSide.flag) != 0 ? GT_Utility.trans("093", "Strong") + : GT_Utility.trans("094", "Weak"))); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_BATTERY_USE, + 3.0F, + -1, + xCoord, + yCoord, + zCoord); + issueBlockUpdate(); + } + doEnetUpdate(); + cableUpdateDelay = 10; + return true; + } + + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWireCutterList)) { + final ForgeDirection tSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ); + if (mMetaTileEntity.onWireCutterRightClick(side, tSide, aPlayer, aX, aY, aZ, tCurrentItem)) { + // logic handled internally + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_WRENCH, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + } + doEnetUpdate(); + cableUpdateDelay = 10; + return true; + } + + ForgeDirection coverSide = side; + if (getCoverIDAtSide(side) == 0) coverSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ); + + if (getCoverIDAtSide(coverSide) == 0) { + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sCovers.keySet())) { + final GT_CoverBehaviorBase<?> coverBehavior = GregTech_API + .getCoverBehaviorNew(tCurrentItem); + if (coverBehavior.isCoverPlaceable(coverSide, tCurrentItem, this) + && mMetaTileEntity.allowCoverOnSide(coverSide, new GT_ItemStack(tCurrentItem))) { + + setCoverItemAtSide(coverSide, tCurrentItem); + coverBehavior.onPlayerAttach(aPlayer, tCurrentItem, this, coverSide); + + if (!aPlayer.capabilities.isCreativeMode) tCurrentItem.stackSize--; + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_WRENCH, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + sendClientData(); + } + return true; + } + } else { + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sCrowbarList)) { + if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer)) { + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.RANDOM_BREAK, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + dropCover(coverSide, side, false); + } + return true; + } else if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sJackhammerList)) { + // Configuration of delicate electronics calls for a tool with precision and subtlety. + if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer)) { + final CoverInfo info = getCoverInfoAtSide(coverSide); + if (info != CoverInfo.EMPTY_INFO) { + final GT_CoverBehaviorBase<?> behavior = info.getCoverBehavior(); + if (behavior.allowsTickRateAddition()) { + info.onCoverJackhammer(aPlayer); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.IC2_TOOLS_DRILL_DRILL_SOFT, + 1.0F, + 1, + xCoord, + yCoord, + zCoord); + + } else { + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("gt.cover.info.chat.tick_rate_not_allowed")); + } + return true; + } + } + } + } + // End item != null + } else if (aPlayer.isSneaking()) { // Sneak click, no tool -> open cover config if possible. + side = (getCoverIDAtSide(side) == 0) ? GT_Utility.determineWrenchingSide(side, aX, aY, aZ) : side; + return getCoverIDAtSide(side) > 0 && getCoverBehaviorAtSideNew(side).onCoverShiftRightClick( + side, + getCoverIDAtSide(side), + getComplexCoverDataAtSide(side), + this, + aPlayer); + } + + if (getCoverBehaviorAtSideNew(side).onCoverRightClick( + side, + getCoverIDAtSide(side), + getComplexCoverDataAtSide(side), + this, + aPlayer, + aX, + aY, + aZ)) return true; + + if (!getCoverInfoAtSide(side).isGUIClickable()) return false; + + if (isUpgradable() && tCurrentItem != null) { + if (ItemList.Upgrade_Muffler.isStackEqual(aPlayer.inventory.getCurrentItem())) { + if (addMufflerUpgrade()) { + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.RANDOM_CLICK, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + if (!aPlayer.capabilities.isCreativeMode) aPlayer.inventory.getCurrentItem().stackSize--; + } + return true; + } + if (ItemList.Upgrade_Lock.isStackEqual(aPlayer.inventory.getCurrentItem())) { + if (isUpgradable() && !mLockUpgrade) { + mLockUpgrade = true; + setOwnerName(aPlayer.getDisplayName()); + setOwnerUuid(aPlayer.getUniqueID()); + GT_Utility.sendSoundToPlayers( + worldObj, + SoundResource.RANDOM_CLICK, + 1.0F, + -1, + xCoord, + yCoord, + zCoord); + if (!aPlayer.capabilities.isCreativeMode) aPlayer.inventory.getCurrentItem().stackSize--; + } + return true; + } + } + } + } + + try { + if (!aPlayer.isSneaking() && hasValidMetaTileEntity()) + return mMetaTileEntity.onRightclick(this, aPlayer, side, aX, aY, aZ); + } catch (Throwable e) { + GT_Log.err.println( + "Encountered Exception while rightclicking TileEntity, the Game should've crashed now, but I prevented that. Please report immediately to GregTech Intergalactical!!!"); + e.printStackTrace(GT_Log.err); + e.printStackTrace(); + } + + return false; + } + + @Override + public void onLeftclick(EntityPlayer aPlayer) { + try { + if (aPlayer != null && hasValidMetaTileEntity()) mMetaTileEntity.onLeftclick(this, aPlayer); + } catch (Throwable e) { + GT_Log.err.println( + "Encountered Exception while leftclicking TileEntity, the Game should've crashed now, but I prevented that. Please report immediately to GregTech Intergalactical!!!"); + e.printStackTrace(GT_Log.err); + } + } + + @Override + public boolean isDigitalChest() { + if (canAccessData()) return mMetaTileEntity.isDigitalChest(); + return false; + } + + @Override + public ItemStack[] getStoredItemData() { + if (canAccessData()) return mMetaTileEntity.getStoredItemData(); + return null; + } + + @Override + public void setItemCount(int aCount) { + if (canAccessData()) mMetaTileEntity.setItemCount(aCount); + } + + @Override + public int getMaxItemCount() { + if (canAccessData()) return mMetaTileEntity.getMaxItemCount(); + return 0; + } + + /** + * Can put aStack into Slot + */ + @Override + public boolean isItemValidForSlot(int aIndex, ItemStack aStack) { + return canAccessData() && mMetaTileEntity.isItemValidForSlot(aIndex, aStack); + } + + /** + * returns all valid Inventory Slots, no matter which Side (Unless it's covered). The Side Stuff is done in the + * following two Functions. + */ + @Override + public int[] getAccessibleSlotsFromSide(int ordinalSide) { + final CoverInfo coverInfo = getCoverInfoAtSide(ForgeDirection.getOrientation(ordinalSide)); + if (canAccessData() && (coverInfo.letsItemsOut(-1) || coverInfo.letsItemsIn(-1))) + return mMetaTileEntity.getAccessibleSlotsFromSide(ordinalSide); + return GT_Values.emptyIntArray; + } + + /** + * Can put aStack into Slot at Side + */ + @Override + public boolean canInsertItem(int slotIndex, ItemStack stack, int ordinalSide) { + return canAccessData() && (mRunningThroughTick || !mInputDisabled) + && getCoverInfoAtSide(ForgeDirection.getOrientation(ordinalSide)).letsItemsIn(slotIndex) + && mMetaTileEntity.canInsertItem(slotIndex, stack, ordinalSide); + } + + /** + * Can pull stack out of Slot from Side + */ + @Override + public boolean canExtractItem(int slotIndex, ItemStack stack, int ordinalSide) { + final ForgeDirection side = ForgeDirection.getOrientation(ordinalSide); + return canAccessData() && (mRunningThroughTick || !mOutputDisabled) + && getCoverBehaviorAtSideNew(side) + .letsItemsOut(side, getCoverIDAtSide(side), getComplexCoverDataAtSide(side), slotIndex, this) + && mMetaTileEntity.canExtractItem(slotIndex, stack, ordinalSide); + } + + @Override + public boolean isUpgradable() { + return canAccessData() && getUpgradeCount() < 8; + } + + @Override + public byte getGeneralRS(ForgeDirection side) { + if (mMetaTileEntity == null) return 0; + return mMetaTileEntity.allowGeneralRedstoneOutput() ? mSidedRedstone[side.ordinal()] : 0; + } + + @Override + public boolean isSteamEngineUpgradable() { + return isUpgradable() && !hasSteamEngineUpgrade() && getSteamCapacity() > 0; + } + + @Override + public boolean addSteamEngineUpgrade() { + if (isSteamEngineUpgradable()) { + issueBlockUpdate(); + mSteamConverter = true; + return true; + } + return false; + } + + @Override + public boolean hasSteamEngineUpgrade() { + if (canAccessData() && mMetaTileEntity.isSteampowered()) return true; + return mSteamConverter; + } + + @Override + public boolean hasMufflerUpgrade() { + return mMuffler; + } + + @Override + public boolean isMufflerUpgradable() { + return isUpgradable() && !hasMufflerUpgrade(); + } + + @Override + public boolean addMufflerUpgrade() { + if (isMufflerUpgradable()) return mMuffler = true; + return false; + } + + @Override + public void markInventoryBeenModified() { + mInventoryChanged = true; + } + + @Override + public int getErrorDisplayID() { + return mDisplayErrorCode; + } + + @Override + public void setErrorDisplayID(int aErrorID) { + mDisplayErrorCode = aErrorID; + } + + @Override + public IMetaTileEntity getMetaTileEntity() { + return hasValidMetaTileEntity() ? mMetaTileEntity : null; + } + + @Override + public void setMetaTileEntity(IMetaTileEntity aMetaTileEntity) { + if (aMetaTileEntity instanceof MetaTileEntity || aMetaTileEntity == null) + mMetaTileEntity = (MetaTileEntity) aMetaTileEntity; + else { + GT_FML_LOGGER.error( + "Unknown meta tile entity set! Class {}, inventory name {}.", + aMetaTileEntity.getClass(), + aMetaTileEntity.getInventoryName()); + } + } + + public byte getLightValue() { + return mLightValue; + } + + @Override + public void setLightValue(byte aLightValue) { + mLightValue = (byte) (aLightValue & 15); + } + + @Override + public long getAverageElectricInput() { + long rEU = 0; + for (int i = 0; i < mAverageEUInput.length; ++i) if (i != mAverageEUInputIndex) rEU += mAverageEUInput[i]; + return rEU / (mAverageEUInput.length - 1); + } + + @Override + public long getAverageElectricOutput() { + long rEU = 0; + for (int i = 0; i < mAverageEUOutput.length; ++i) if (i != mAverageEUOutputIndex) rEU += mAverageEUOutput[i]; + return rEU / (mAverageEUOutput.length - 1); + } + + @Override + protected void updateOutputRedstoneSignal(ForgeDirection side) { + if (mMetaTileEntity.hasSidedRedstoneOutputBehavior()) { + setOutputRedstoneSignal(side, (byte) 0); + } else { + setOutputRedstoneSignal(side, (byte) 15); + } + } + + @Override + public String getOwnerName() { + if (GT_Utility.isStringInvalid(mOwnerName)) return "Player"; + return mOwnerName; + } + + @Override + public String setOwnerName(String aName) { + if (GT_Utility.isStringInvalid(aName)) return mOwnerName = "Player"; + return mOwnerName = aName; + } + + @Override + public UUID getOwnerUuid() { + return mOwnerUuid; + } + + @Override + public void setOwnerUuid(UUID uuid) { + mOwnerUuid = uuid; + } + + @Override + public byte getComparatorValue(ForgeDirection side) { + return canAccessData() ? mMetaTileEntity.getComparatorValue(side) : 0; + } + + @Override + public ItemStack decrStackSize(int aIndex, int aAmount) { + if (canAccessData()) { + mInventoryChanged = true; + return mMetaTileEntity.decrStackSize(aIndex, aAmount); + } + return null; + } + + @Override + public long injectEnergyUnits(ForgeDirection side, long aVoltage, long aAmperage) { + if (!canAccessData() || !mMetaTileEntity.isElectric() + || !inputEnergyFrom(side) + || aAmperage <= 0 + || aVoltage <= 0 + || getStoredEU() >= getEUCapacity() + || mMetaTileEntity.maxAmperesIn() <= mAcceptedAmperes) return 0; + if (aVoltage > getInputVoltage()) { + GT_Log.exp + .println("Energy Explosion, injected " + aVoltage + "EU/t in a " + getInputVoltage() + "EU/t Machine!"); + doExplosion(aVoltage); + return 0; + } + if (increaseStoredEnergyUnits( + aVoltage * (aAmperage = Math.min( + aAmperage, + Math.min( + mMetaTileEntity.maxAmperesIn() - mAcceptedAmperes, + 1 + ((getEUCapacity() - getStoredEU()) / aVoltage)))), + true)) { + mAverageEUInput[mAverageEUInputIndex] += aVoltage * aAmperage; + mAcceptedAmperes += aAmperage; + return aAmperage; + } + return 0; + } + + @Override + public boolean drainEnergyUnits(ForgeDirection side, long aVoltage, long aAmperage) { + if (!canAccessData() || !mMetaTileEntity.isElectric() + || !outputsEnergyTo(side) + || getStoredEU() - (aVoltage * aAmperage) < mMetaTileEntity.getMinimumStoredEU()) return false; + if (decreaseStoredEU(aVoltage * aAmperage, false)) { + mAverageEUOutput[mAverageEUOutputIndex] += aVoltage * aAmperage; + return true; + } + return false; + } + + @Override + public boolean acceptsRotationalEnergy(ForgeDirection side) { + if (!canAccessData() || getCoverIDAtSide(side) != 0) return false; + return mMetaTileEntity.acceptsRotationalEnergy(side); + } + + @Override + public boolean injectRotationalEnergy(ForgeDirection side, long aSpeed, long aEnergy) { + if (!canAccessData() || getCoverIDAtSide(side) != 0) return false; + return mMetaTileEntity.injectRotationalEnergy(side, aSpeed, aEnergy); + } + + @Override + public int fill(ForgeDirection side, FluidStack aFluid, boolean doFill) { + if (mTickTimer > 5 && canAccessData() + && (mRunningThroughTick || !mInputDisabled) + && (side == ForgeDirection.UNKNOWN || (mMetaTileEntity.isLiquidInput(side) + && getCoverInfoAtSide(side).letsFluidIn(aFluid == null ? null : aFluid.getFluid())))) + return mMetaTileEntity.fill(side, aFluid, doFill); + return 0; + } + + @Override + public FluidStack drain(ForgeDirection side, int maxDrain, boolean doDrain) { + if (mTickTimer > 5 && canAccessData() + && (mRunningThroughTick || !mOutputDisabled) + && (side == ForgeDirection.UNKNOWN + || (mMetaTileEntity.isLiquidOutput(side) && getCoverInfoAtSide(side).letsFluidOut( + mMetaTileEntity.getFluid() == null ? null + : mMetaTileEntity.getFluid() + .getFluid())))) + return mMetaTileEntity.drain(side, maxDrain, doDrain); + return null; + } + + @Override + public FluidStack drain(ForgeDirection side, FluidStack aFluid, boolean doDrain) { + if (mTickTimer > 5 && canAccessData() + && (mRunningThroughTick || !mOutputDisabled) + && (side == ForgeDirection.UNKNOWN || (mMetaTileEntity.isLiquidOutput(side) + && getCoverInfoAtSide(side).letsFluidOut(aFluid == null ? null : aFluid.getFluid())))) + return mMetaTileEntity.drain(side, aFluid, doDrain); + return null; + } + + @Override + public boolean canFill(ForgeDirection side, Fluid aFluid) { + if (mTickTimer > 5 && canAccessData() + && (mRunningThroughTick || !mInputDisabled) + && (side == ForgeDirection.UNKNOWN + || (mMetaTileEntity.isLiquidInput(side) && getCoverInfoAtSide(side).letsFluidIn(aFluid)))) + return mMetaTileEntity.canFill(side, aFluid); + return false; + } + + @Override + public boolean canDrain(ForgeDirection side, Fluid aFluid) { + if (mTickTimer > 5 && canAccessData() + && (mRunningThroughTick || !mOutputDisabled) + && (side == ForgeDirection.UNKNOWN + || (mMetaTileEntity.isLiquidOutput(side) && getCoverInfoAtSide(side).letsFluidOut(aFluid)))) + return mMetaTileEntity.canDrain(side, aFluid); + return false; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection side) { + if (canAccessData() && (side == ForgeDirection.UNKNOWN + || (mMetaTileEntity.isLiquidInput(side) && getCoverInfoAtSide(side).letsFluidIn(null)) + || (mMetaTileEntity.isLiquidOutput(side) && getCoverInfoAtSide(side).letsFluidOut(null)))) + return mMetaTileEntity.getTankInfo(side); + return new FluidTankInfo[] {}; + } + + public double getOutputEnergyUnitsPerTick() { + return oOutput; + } + + public boolean isTeleporterCompatible(ForgeDirection side) { + return canAccessData() && mMetaTileEntity.isTeleporterCompatible(); + } + + public double demandedEnergyUnits() { + if (mReleaseEnergy || !canAccessData() || !mMetaTileEntity.isEnetInput()) return 0; + return getEUCapacity() - getStoredEU(); + } + + public double injectEnergyUnits(ForgeDirection aDirection, double aAmount) { + return injectEnergyUnits(aDirection, (int) aAmount, 1) > 0 ? 0 : aAmount; + } + + public boolean acceptsEnergyFrom(TileEntity aEmitter, ForgeDirection aDirection) { + return inputEnergyFrom(aDirection); + } + + public boolean emitsEnergyTo(TileEntity aReceiver, ForgeDirection aDirection) { + return outputsEnergyTo(aDirection); + } + + public double getOfferedEnergy() { + return (canAccessData() && getStoredEU() - mMetaTileEntity.getMinimumStoredEU() >= oOutput) + ? Math.max(0, oOutput) + : 0; + } + + public void drawEnergy(double amount) { + mAverageEUOutput[mAverageEUOutputIndex] += amount; + decreaseStoredEU((int) amount, true); + } + + public int injectEnergy(ForgeDirection aForgeDirection, int aAmount) { + return injectEnergyUnits(aForgeDirection, aAmount, 1) > 0 ? 0 : aAmount; + } + + public int addEnergy(int aEnergy) { + if (!canAccessData()) return 0; + if (aEnergy > 0) increaseStoredEnergyUnits(aEnergy, true); + else decreaseStoredEU(-aEnergy, true); + return (int) Math.min(Integer.MAX_VALUE, mMetaTileEntity.getEUVar()); + } + + public boolean isAddedToEnergyNet() { + return false; + } + + public int demandsEnergy() { + if (mReleaseEnergy || !canAccessData() || !mMetaTileEntity.isEnetInput()) return 0; + return getCapacity() - getStored(); + } + + public int getCapacity() { + return (int) Math.min(Integer.MAX_VALUE, getEUCapacity()); + } + + public int getStored() { + return (int) Math.min(Integer.MAX_VALUE, Math.min(getStoredEU(), getCapacity())); + } + + public void setStored(int aEU) { + if (canAccessData()) setStoredEU(aEU); + } + + public int getMaxSafeInput() { + return (int) Math.min(Integer.MAX_VALUE, getInputVoltage()); + } + + public int getMaxEnergyOutput() { + if (mReleaseEnergy) return Integer.MAX_VALUE; + return getOutput(); + } + + public int getOutput() { + return (int) Math.min(Integer.MAX_VALUE, oOutput); + } + + public int injectEnergy(Direction aDirection, int aAmount) { + return injectEnergyUnits(aDirection.toForgeDirection(), aAmount, 1) > 0 ? 0 : aAmount; + } + + public boolean isTeleporterCompatible(Direction ignoredDirection) { + return canAccessData() && mMetaTileEntity.isTeleporterCompatible(); + } + + public boolean acceptsEnergyFrom(TileEntity ignoredTileEntity, Direction aDirection) { + return inputEnergyFrom(aDirection.toForgeDirection()); + } + + public boolean emitsEnergyTo(TileEntity ignoredTileEntity, Direction aDirection) { + return outputsEnergyTo(aDirection.toForgeDirection()); + } + + @Override + public boolean addStackToSlot(int slotIndex, ItemStack stack) { + if (GT_Utility.isStackInvalid(stack)) return true; + if (slotIndex < 0 || slotIndex >= getSizeInventory()) return false; + final ItemStack toStack = getStackInSlot(slotIndex); + if (GT_Utility.isStackInvalid(toStack)) { + setInventorySlotContents(slotIndex, stack); + return true; + } + final ItemStack fromStack = GT_OreDictUnificator.get(stack); + if (GT_Utility.areStacksEqual(toStack, fromStack) && toStack.stackSize + fromStack.stackSize + <= Math.min(fromStack.getMaxStackSize(), getInventoryStackLimit())) { + toStack.stackSize += fromStack.stackSize; + markDirty(); + return true; + } + return false; + } + + @Override + public boolean addStackToSlot(int aIndex, ItemStack aStack, int aAmount) { + return addStackToSlot(aIndex, GT_Utility.copyAmount(aAmount, aStack)); + } + + @Override + public byte getColorization() { + return (byte) (mColor - 1); + } + + @Override + public byte setColorization(byte aColor) { + if (aColor > 15 || aColor < -1) aColor = -1; + mColor = (byte) (aColor + 1); + if (canAccessData()) mMetaTileEntity.onColorChangeServer(aColor); + return mColor; + } + + @Override + public float getBlastResistance(ForgeDirection side) { + return canAccessData() ? Math.max(0, getMetaTileEntity().getExplosionResistance(side)) : 10.0F; + } + + @Override + public void onBlockDestroyed() { + if (canAccessData()) getMetaTileEntity().onBlockDestroyed(); + } + + @Override + public boolean isUniversalEnergyStored(long aEnergyAmount) { + if (getUniversalEnergyStored() >= aEnergyAmount) return true; + mHasEnoughEnergy = false; + return false; + } + + @Override + public String[] getInfoData() { + { + if (canAccessData()) return getMetaTileEntity().getInfoData(); + return new String[] {}; + } + } + + @Override + public int getLightOpacity() { + return mMetaTileEntity == null ? getLightValue() > 0 ? 0 : 255 : mMetaTileEntity.getLightOpacity(); + } + + @Override + public void addCollisionBoxesToList(World aWorld, int aX, int aY, int aZ, AxisAlignedBB inputAABB, + List<AxisAlignedBB> outputAABB, Entity collider) { + mMetaTileEntity.addCollisionBoxesToList(aWorld, aX, aY, aZ, inputAABB, outputAABB, collider); + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + return mMetaTileEntity.getCollisionBoundingBoxFromPool(aWorld, aX, aY, aZ); + } + + @Override + public void onEntityCollidedWithBlock(World aWorld, int aX, int aY, int aZ, Entity collider) { + mMetaTileEntity.onEntityCollidedWithBlock(aWorld, aX, aY, aZ, collider); + } + + /** + * Shifts the machine Inventory index according to the change in Input/Output Slots. This is NOT done automatically. + * If you want to change slot count for a machine this method needs to be adapted. Currently this method only works + * for GT_MetaTileEntity_BasicMachine + * + * @param slotIndex The original Inventory index + * @param nbtVersion The GregTech version in which the original Inventory Index was saved. + * @return The corrected Inventory index + */ + @Override + protected int migrateInventoryIndex(int slotIndex, int nbtVersion) { + final int oldInputSize; + final int newInputSize; + final int oldOutputSize; + final int newOutputSize; + final int chemistryUpdateVersion = GT_Mod.calculateTotalGTVersion(509, 31); + final int configCircuitAdditionVersion = GT_Mod.calculateTotalGTVersion(509, 40); + final int wireAdditionVersion = GT_Mod.calculateTotalGTVersion(509, 41); + final int disassemblerRemoveVersion = GT_Mod.calculateTotalGTVersion(509, 42, 44); + if (nbtVersion < 1000000) nbtVersion *= 1000; + // 4 is old GT_MetaTileEntity_BasicMachine.OTHER_SLOT_COUNT + if (nbtVersion < configCircuitAdditionVersion && getMetaTileEntity() instanceof GT_MetaTileEntity_BasicMachine + && slotIndex >= 4) slotIndex += 1; + if (mID >= 211 && mID <= 218) { // Assembler + if (nbtVersion < chemistryUpdateVersion) { + oldInputSize = 2; + oldOutputSize = 1; + } else { + return slotIndex; + } + newInputSize = 6; + newOutputSize = 1; + + } else if (mID >= 421 && mID <= 428) { // Chemical Reactor + if (nbtVersion < chemistryUpdateVersion) { + oldInputSize = 2; + oldOutputSize = 1; + } else { + return slotIndex; + } + newInputSize = 2; + newOutputSize = 2; + + } else if (mID >= 531 && mID <= 538) { // Distillery + if (nbtVersion < chemistryUpdateVersion) { + oldInputSize = 1; + oldOutputSize = 0; + } else { + return slotIndex; + } + newInputSize = 1; + newOutputSize = 1; + } else if (mID >= 581 && mID <= 588) { // Mixer + if (nbtVersion < chemistryUpdateVersion) { + oldInputSize = 4; + oldOutputSize = 1; + } else { + return slotIndex; + } + newInputSize = 6; + newOutputSize = 1; + + } else if (mID >= 351 && mID <= 355 || mID >= 11050 && mID <= 11056) { // wire mill + if (nbtVersion < wireAdditionVersion) { + oldInputSize = 1; + oldOutputSize = 1; + } else { + return slotIndex; + } + newInputSize = 2; + newOutputSize = 1; + + } else if (mID >= 654 && mID <= 655 || mID >= 11070 && mID <= 11076) { // arc furnace + if (nbtVersion < disassemblerRemoveVersion) { + oldInputSize = 1; + oldOutputSize = 4; + } else { + return slotIndex; + } + newInputSize = 1; + newOutputSize = 9; + + } else { + return slotIndex; + } + + int indexShift = 0; + if (slotIndex >= GT_MetaTileEntity_BasicMachine.OTHER_SLOT_COUNT + oldInputSize) { + indexShift += newInputSize - oldInputSize; + } + if (slotIndex >= GT_MetaTileEntity_BasicMachine.OTHER_SLOT_COUNT + oldInputSize + oldOutputSize) { + indexShift += newOutputSize - oldOutputSize; + } + return slotIndex + indexShift; + } + + @Override + public IGridNode getGridNode(ForgeDirection forgeDirection) { + final AENetworkProxy gp = getProxy(); + return gp != null ? gp.getNode() : null; + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return mMetaTileEntity == null ? AECableType.NONE : mMetaTileEntity.getCableConnectionType(forgeDirection); + } + + @Override + public void securityBreak() {} + + @Override + public IGridNode getActionableNode() { + final AENetworkProxy gp = getProxy(); + return gp != null ? gp.getNode() : null; + } + + @Override + public AENetworkProxy getProxy() { + return mMetaTileEntity == null ? null : mMetaTileEntity.getProxy(); + } + + @Override + public DimensionalCoord getLocation() { + return new DimensionalCoord(this); + } + + @Override + public void gridChanged() { + if (mMetaTileEntity != null) mMetaTileEntity.gridChanged(); + } + + @TileEvent(TileEventType.WORLD_NBT_READ) + public void readFromNBT_AENetwork(final NBTTagCompound data) { + final AENetworkProxy gp = getProxy(); + if (gp != null) getProxy().readFromNBT(data); + } + + @TileEvent(TileEventType.WORLD_NBT_WRITE) + public void writeToNBT_AENetwork(final NBTTagCompound data) { + final AENetworkProxy gp = getProxy(); + if (gp != null) gp.writeToNBT(data); + } + + void onChunkUnloadAE() { + final AENetworkProxy gp = getProxy(); + if (gp != null) gp.onChunkUnload(); + } + + void invalidateAE() { + final AENetworkProxy gp = getProxy(); + if (gp != null) gp.invalidate(); + } + + @Override + public boolean wasShutdown() { + return mWasShutdown; + } + + @Override + public void setShutdownStatus(boolean newStatus) { + mWasShutdown = newStatus; + } + + @Override + public void setShutDownReason(@NotNull ShutDownReason reason) { + lastShutDownReason = reason; + } + + @Override + public @NotNull ShutDownReason getLastShutDownReason() { + return lastShutDownReason; + } + + @Override + public IAlignment getAlignment() { + return getMetaTileEntity() instanceof IAlignmentProvider + ? ((IAlignmentProvider) getMetaTileEntity()).getAlignment() + : getMetaTileEntity() instanceof IAlignment ? (IAlignment) getMetaTileEntity() : null; + } + + @Nullable + @Override + public IConstructable getConstructable() { + return getMetaTileEntity() instanceof IConstructable ? (IConstructable) getMetaTileEntity() : null; + } + + @Override + public int[] getTimeStatistics() { + return mTimeStatistics; + } + + @Override + public void startTimeStatistics() { + hasTimeStatisticsStarted = true; + } + + @Nullable + @Override + public List<ItemStack> getItemsForHoloGlasses() { + if (canAccessData()) { + return mMetaTileEntity.getItemsForHoloGlasses(); + } + return null; + } + + @Override + public String getCustomName() { + return getMetaTileEntity() instanceof ICustomNameObject customNameObject ? customNameObject.getCustomName() + : null; + } + + @Override + public boolean hasCustomName() { + return getMetaTileEntity() instanceof ICustomNameObject customNameObject && customNameObject.hasCustomName(); + } + + @Override + public void setCustomName(String name) { + if (getMetaTileEntity() instanceof ICustomNameObject customNameObject) customNameObject.setCustomName(name); + } +} |