aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/multitileentity/base
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gregtech/api/multitileentity/base')
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java1385
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/NonTickableMultiTileEntity.java62
-rw-r--r--src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java172
3 files changed, 1619 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java
new file mode 100644
index 0000000000..eeadfe7602
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java
@@ -0,0 +1,1385 @@
+package gregtech.api.multitileentity.base;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+import static gregtech.api.enums.GT_Values.VALID_SIDES;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+
+import net.minecraft.block.Block;
+import net.minecraft.client.Minecraft;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemBlock;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.network.Packet;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.Explosion;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.Fluid;
+
+import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils;
+
+import cpw.mods.fml.common.registry.GameRegistry;
+import gregtech.api.GregTech_API;
+import gregtech.api.enums.GT_Values;
+import gregtech.api.enums.GT_Values.NBT;
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.Mods;
+import gregtech.api.enums.SoundResource;
+import gregtech.api.enums.Textures;
+import gregtech.api.enums.Textures.BlockIcons.CustomIcon;
+import gregtech.api.gui.modularui.GT_UIInfos;
+import gregtech.api.interfaces.ITexture;
+import gregtech.api.metatileentity.CoverableTileEntity;
+import gregtech.api.metatileentity.GregTechTileClientEvents;
+import gregtech.api.multitileentity.MultiTileEntityBlock;
+import gregtech.api.multitileentity.MultiTileEntityClassContainer;
+import gregtech.api.multitileentity.MultiTileEntityRegistry;
+import gregtech.api.multitileentity.interfaces.IMultiTileEntity;
+import gregtech.api.multitileentity.interfaces.SyncedMultiTileEntity;
+import gregtech.api.net.GT_Packet_MultiTileEntity;
+import gregtech.api.net.GT_Packet_New;
+import gregtech.api.net.data.CommonData;
+import gregtech.api.net.data.CoordinateData;
+import gregtech.api.net.data.MultiTileEntityData;
+import gregtech.api.objects.GT_ItemStack;
+import gregtech.api.objects.XSTR;
+import gregtech.api.render.TextureFactory;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_ModHandler;
+import gregtech.api.util.GT_Util;
+import gregtech.api.util.GT_Utility;
+import gregtech.common.render.MultiTileBasicRender;
+import mcp.mobius.waila.api.IWailaConfigHandler;
+import mcp.mobius.waila.api.IWailaDataAccessor;
+
+public abstract class MultiTileEntity extends CoverableTileEntity
+ implements IMultiTileEntity, MultiTileBasicRender, SyncedMultiTileEntity {
+
+ private ITexture baseTexture = null;
+ private ITexture topOverlayTexture = null;
+ private ITexture bottomOverlayTexture = null;
+ private ITexture leftOverlayTexture = null;
+ private ITexture rightOverlayTexture = null;
+ private ITexture backOverlayTexture = null;
+ private ITexture frontOverlayTexture = null;
+
+ // A Bounding Box without having to constantly specify the Offset Coordinates.
+ protected static final float[] PX_BOX = { 0, 0, 0, 1, 1, 1 };
+
+ public Materials material = Materials._NULL;
+ protected final boolean isTicking; // If this TileEntity is ticking at all
+
+ // Checks if this TileEntity should refresh when the Block is being set.
+ // This way you can toggle this check at any time.
+ protected boolean shouldRefresh = true;
+
+ protected boolean needsBlockUpdate = false; // This Variable is for a buffered Block Update.
+ protected boolean forceFullSelectionBox = false; // This Variable is for forcing the Selection Box to be full.
+ protected boolean needsUpdate = false;
+ protected boolean hasInventoryChanged = false;
+ protected boolean isPainted = false;
+ @Nonnull
+ protected ForgeDirection facing = ForgeDirection.WEST; // Default to WEST, so it renders facing Left in the
+ // inventory
+ protected byte color;
+ protected int rgba = GT_Values.UNCOLORED;
+ private short mteID = GT_Values.W, mteRegistry = GT_Values.W;
+ private String customName = null;
+ private String ownerName = "";
+ private UUID ownerUUID = GT_Utility.defaultUuid;
+ private boolean lockUpgrade = false;
+
+ private final GT_Packet_MultiTileEntity fullPacket = new GT_Packet_MultiTileEntity(false);
+ private final GT_Packet_MultiTileEntity timedPacket = new GT_Packet_MultiTileEntity(false);
+ private final GT_Packet_MultiTileEntity graphicPacket = new GT_Packet_MultiTileEntity(false);
+
+ public MultiTileEntity(boolean isTicking) {
+ this.isTicking = isTicking;
+ }
+
+ @Override
+ public short getMultiTileEntityID() {
+ return mteID;
+ }
+
+ @Override
+ public short getMultiTileEntityRegistryID() {
+ return mteRegistry;
+ }
+
+ @Override
+ public void onRegistrationFirst(MultiTileEntityRegistry registry, short id) {
+ GameRegistry.registerTileEntity(getClass(), getTileEntityName());
+ }
+
+ @Override
+ public void initFromNBT(NBTTagCompound nbt, short muteID, short muteRegistry) {
+ if (this.mteID == muteID && this.mteRegistry == muteRegistry) {
+ return;
+ }
+ // Set ID and Registry ID.
+ this.mteID = muteID;
+ this.mteRegistry = muteRegistry;
+ // Read the Default Parameters from NBT.
+ if (nbt != null) readFromNBT(nbt);
+ }
+
+ @Override
+ public void loadTextures(String folder) {
+ // Loading the registry
+ for (SidedTextureNames textureName : SidedTextureNames.TEXTURES) {
+ ITexture texture;
+ try {
+ Minecraft.getMinecraft()
+ .getResourceManager()
+ .getResource(
+ new ResourceLocation(
+ Mods.GregTech.ID,
+ "textures/blocks/multitileentity/" + folder + "/" + textureName.getName() + ".png"));
+ texture = TextureFactory.of(new CustomIcon("multitileentity/" + folder + "/" + textureName.getName()));
+ } catch (IOException ignored) {
+ texture = TextureFactory.of(Textures.BlockIcons.VOID);
+ }
+ switch (textureName) {
+ case Top -> topOverlayTexture = texture;
+ case Bottom -> bottomOverlayTexture = texture;
+ case Back -> backOverlayTexture = texture;
+ case Front -> frontOverlayTexture = texture;
+ case Left -> leftOverlayTexture = texture;
+ case Right -> rightOverlayTexture = texture;
+ case Base -> baseTexture = texture;
+ }
+ }
+ }
+
+ @Override
+ public void copyTextures() {
+ // Loading an instance
+ final TileEntity referenceTileEntity = MultiTileEntityRegistry
+ .getReferenceTileEntity(getMultiTileEntityRegistryID(), getMultiTileEntityID());
+ if (!(referenceTileEntity instanceof MultiTileEntity canonicalEntity)) {
+ return;
+ }
+ baseTexture = canonicalEntity.baseTexture;
+ topOverlayTexture = canonicalEntity.topOverlayTexture;
+ bottomOverlayTexture = canonicalEntity.bottomOverlayTexture;
+ leftOverlayTexture = canonicalEntity.leftOverlayTexture;
+ rightOverlayTexture = canonicalEntity.rightOverlayTexture;
+ backOverlayTexture = canonicalEntity.backOverlayTexture;
+ frontOverlayTexture = canonicalEntity.frontOverlayTexture;
+ }
+
+ @Override
+ public ITexture getTexture(ForgeDirection side) {
+ if (facing == side) {
+ return TextureFactory.of(baseTexture, frontOverlayTexture);
+ }
+
+ if (facing.getOpposite() == side) {
+ return TextureFactory.of(baseTexture, backOverlayTexture);
+ }
+
+ if (side == ForgeDirection.UP) {
+ return TextureFactory.of(baseTexture, topOverlayTexture);
+ }
+
+ if (side == ForgeDirection.DOWN) {
+ return TextureFactory.of(baseTexture, bottomOverlayTexture);
+ }
+
+ if (facing.getRotation(ForgeDirection.DOWN) == side) {
+ return TextureFactory.of(baseTexture, rightOverlayTexture);
+ } else {
+ return TextureFactory.of(baseTexture, leftOverlayTexture);
+ }
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound nbt) {
+ // Check if it is a World/Chunk-Loading Process calling readFromNBT
+ if (mteID == GT_Values.W || mteRegistry == GT_Values.W) {
+ // Read the ID Tags first
+ mteID = nbt.getShort(NBT.MTE_ID);
+ mteRegistry = nbt.getShort(NBT.MTE_REG);
+ // Add additional Default Parameters in case the Mod updated with new ones
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(mteRegistry);
+ if (tRegistry != null) {
+ final MultiTileEntityClassContainer tClass = tRegistry.getClassContainer(mteID);
+ if (tClass != null) {
+ // Add the Default Parameters. Useful for things that differ between different tiers/types of the
+ // same machine
+ nbt = GT_Util.fuseNBT(nbt, tClass.getParameters());
+ }
+ }
+ }
+ // read the Coords if it has them.
+ if (nbt.hasKey("x")) xCoord = nbt.getInteger("x");
+ if (nbt.hasKey("y")) yCoord = nbt.getInteger("y");
+ if (nbt.hasKey("z")) zCoord = nbt.getInteger("z");
+ // read the custom Name.
+ if (nbt.hasKey(NBT.DISPLAY)) customName = nbt.getCompoundTag(NBT.DISPLAY)
+ .getString(NBT.CUSTOM_NAME);
+
+ // And now everything else.
+ try {
+ if (nbt.hasKey(NBT.MATERIAL)) material = Materials.get(nbt.getString(NBT.MATERIAL));
+ if (nbt.hasKey(NBT.COLOR)) rgba = nbt.getInteger(NBT.COLOR);
+
+ ownerName = nbt.getString(NBT.OWNER);
+ try {
+ ownerUUID = UUID.fromString(nbt.getString(NBT.OWNER_UUID));
+ } catch (IllegalArgumentException e) {
+ ownerUUID = null;
+ }
+ if (nbt.hasKey(NBT.LOCK_UPGRADE)) lockUpgrade = nbt.getBoolean(NBT.LOCK_UPGRADE);
+ if (nbt.hasKey(NBT.FACING)) facing = ForgeDirection.getOrientation(nbt.getInteger(NBT.FACING));
+
+ readCoverNBT(nbt);
+ readTasksNBT(nbt);
+ readMultiTileNBT(nbt);
+
+ if (NetworkUtils.isDedicatedClient()) {
+ if (GregTech_API.sBlockIcons == null && nbt.hasKey(NBT.TEXTURE_FOLDER)) {
+ loadTextures(nbt.getString(NBT.TEXTURE_FOLDER));
+ } else {
+ copyTextures();
+ }
+ }
+
+ if (mSidedRedstone.length != 6) mSidedRedstone = new byte[] { 15, 15, 15, 15, 15, 15 };
+
+ updateCoverBehavior();
+
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("readFromNBT", e);
+ }
+ }
+
+ public void readMultiTileNBT(NBTTagCompound aNBT) {
+ /* Do Nothing */
+ }
+
+ protected void readTasksNBT(NBTTagCompound nbt) {}
+
+ @Override
+ public final void writeToNBT(NBTTagCompound nbt) {
+ super.writeToNBT(nbt);
+ // write the IDs
+ nbt.setShort(NBT.MTE_ID, mteID);
+ nbt.setShort(NBT.MTE_REG, mteRegistry);
+ // write the Custom Name
+ if (GT_Utility.isStringValid(customName)) {
+ final NBTTagCompound displayNBT;
+ if (nbt.hasKey(NBT.DISPLAY)) {
+ displayNBT = nbt.getCompoundTag(NBT.DISPLAY);
+ } else {
+ displayNBT = new NBTTagCompound();
+ nbt.setTag(NBT.DISPLAY, displayNBT);
+ }
+ displayNBT.setString(NBT.CUSTOM_NAME, customName);
+ }
+
+ // write the rest
+ try {
+ nbt.setString(NBT.OWNER, ownerName);
+ nbt.setString(NBT.OWNER_UUID, ownerUUID == null ? "" : ownerUUID.toString());
+ nbt.setBoolean(NBT.LOCK_UPGRADE, lockUpgrade);
+ nbt.setInteger(NBT.FACING, facing.ordinal());
+
+ writeCoverNBT(nbt, false);
+ writeTasksNBT(nbt);
+ writeMultiTileNBT(nbt);
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("writeToNBT", e);
+ }
+ }
+
+ public void writeMultiTileNBT(NBTTagCompound aNBT) {
+ /* Do Nothing */
+ }
+
+ protected void writeTasksNBT(NBTTagCompound aNBT) {}
+
+ @Override
+ public NBTTagCompound writeItemNBT(NBTTagCompound aNBT) {
+ writeCoverNBT(aNBT, true);
+ if (shouldSaveNBTToItemStack()) {
+ writeTasksNBT(aNBT);
+ writeMultiTileNBT(aNBT);
+ }
+ return aNBT;
+ }
+
+ protected boolean shouldSaveNBTToItemStack() {
+ return false;
+ }
+
+ @Override
+ public boolean useModularUI() {
+ return false;
+ }
+
+ @Override
+ public long getTimer() {
+ return 0;
+ }
+
+ @Override
+ public int getRandomNumber(int aRange) {
+ return XSTR.XSTR_INSTANCE.nextInt(aRange);
+ }
+
+ @Override
+ public TileEntity getTileEntity(int aX, int aY, int aZ) {
+ if (worldObj == null
+ || (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ))) return null;
+ return GT_Util.getTileEntity(worldObj, aX, aY, aZ, true);
+ }
+
+ @Override
+ public boolean canUpdate() {
+ return isTicking && shouldRefresh;
+ }
+
+ @Override
+ public boolean shouldRefresh(Block aOldBlock, Block aNewBlock, int aOldMeta, int aNewMeta, World aWorld, int aX,
+ int aY, int aZ) {
+ return shouldRefresh || aOldBlock != aNewBlock;
+ }
+
+ @Override
+ public void updateEntity() {
+ super.updateEntity();
+ if (needsBlockUpdate) doBlockUpdate();
+ }
+
+ public void doBlockUpdate() {
+ final Block tBlock = getBlock(getCoords());
+ worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, tBlock);
+ if (this.providesStrongPower()) {
+ for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
+ if (getBlockAtSide(side)
+ .isNormalCube(worldObj, xCoord + side.offsetX, yCoord + side.offsetY, zCoord + side.offsetZ)) {
+ worldObj.notifyBlocksOfNeighborChange(
+ xCoord + side.offsetX,
+ yCoord + side.offsetY,
+ zCoord + side.offsetZ,
+ tBlock,
+ side.getOpposite()
+ .ordinal());
+ }
+ }
+ }
+ needsBlockUpdate = false;
+ }
+
+ @Override
+ public boolean shouldSideBeRendered(ForgeDirection side) {
+ final TileEntity tTileEntity = getTileEntityAtSideAndDistance(side, 1);
+ // TODO: check to an interface
+ // if (getBlockAtSide(aSide) == Blocks.glass) return false;
+ return tTileEntity instanceof IMultiTileEntity mte ? !mte.isSurfaceOpaque(side.getOpposite())
+ : !getBlockAtSide(side).isOpaqueCube();
+ }
+
+ @Override
+ public boolean isSurfaceOpaque(ForgeDirection side) {
+ return true;
+ }
+
+ @Override
+ public void setCustomName(String aName) {
+ customName = aName;
+ }
+
+ @Override
+ public String getCustomName() {
+ return GT_Utility.isStringValid(customName) ? customName : null;
+ }
+
+ @Override
+ public byte getColorization() {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public boolean unpaint() {
+ return false;
+ }
+
+ @Override
+ public byte setColorization(byte aColor) {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public boolean isPainted() {
+ return false;
+ }
+
+ @Override
+ public boolean paint(int aRGB) {
+ return false;
+ }
+
+ @Override
+ public boolean isFacingValid(ForgeDirection facing) {
+ return false;
+ }
+
+ @Override
+ public ForgeDirection getFrontFacing() {
+ return facing;
+ }
+
+ /**
+ * Sets the main facing to {aSide} and update as appropriately
+ *
+ * @return Whether the facing was changed
+ */
+ @Override
+ public boolean setMainFacing(ForgeDirection side) {
+ if (!isValidFacing(side)) return false;
+ facing = side;
+
+ issueClientUpdate();
+ issueBlockUpdate();
+ onFacingChange();
+ checkDropCover();
+ doEnetUpdate();
+
+ if (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();
+ }
+ return true;
+ }
+
+ @Override
+ public int getPaint() {
+ return this.rgba;
+ }
+
+ @Override
+ public ForgeDirection getBackFacing() {
+ return facing.getOpposite();
+ }
+
+ @Override
+ public boolean isValidFacing(ForgeDirection side) {
+ return side != ForgeDirection.UNKNOWN && getValidFacings()[side.ordinal()];
+ }
+
+ @Override
+ public boolean[] getValidFacings() {
+ return VALID_SIDES;
+ }
+
+ @Override
+ public void issueCoverUpdate(ForgeDirection side) {
+ super.issueCoverUpdate(side);
+ issueClientUpdate();
+ }
+
+ public AxisAlignedBB box(double[] aBox) {
+ return AxisAlignedBB.getBoundingBox(
+ xCoord + aBox[0],
+ yCoord + aBox[1],
+ zCoord + aBox[2],
+ xCoord + aBox[3],
+ yCoord + aBox[4],
+ zCoord + aBox[5]);
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, double aMinX, double aMinY, double aMinZ,
+ double aMaxX, double aMaxY, double aMaxZ) {
+ final AxisAlignedBB tBox = box(aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ @Override
+ public void onFacingChange() {
+ /* Do nothing */
+ }
+
+ public AxisAlignedBB box(double aMinX, double aMinY, double aMinZ, double aMaxX, double aMaxY, double aMaxZ) {
+ return AxisAlignedBB.getBoundingBox(
+ xCoord + aMinX,
+ yCoord + aMinY,
+ zCoord + aMinZ,
+ xCoord + aMaxX,
+ yCoord + aMaxY,
+ zCoord + aMaxZ);
+ }
+
+ @Override
+ public boolean shouldTriggerBlockUpdate() {
+ return false;
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, double[] aBox) {
+ final AxisAlignedBB tBox = box(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ @Override
+ public void onMachineBlockUpdate() {
+ /* Do nothing */
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, float[] aBox) {
+ final AxisAlignedBB tBox = box(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ public boolean box(AxisAlignedBB aAABB, List<AxisAlignedBB> aList) {
+ final AxisAlignedBB tBox = box(PX_BOX);
+ return tBox.intersectsWith(aAABB) && aList.add(tBox);
+ }
+
+ public AxisAlignedBB box(float[] aBox) {
+ return AxisAlignedBB.getBoundingBox(
+ xCoord + aBox[0],
+ yCoord + aBox[1],
+ zCoord + aBox[2],
+ xCoord + aBox[3],
+ yCoord + aBox[4],
+ zCoord + aBox[5]);
+ }
+
+ public boolean box(Block aBlock) {
+ aBlock.setBlockBounds(0, 0, 0, 1, 1, 1);
+ return true;
+ }
+
+ /**
+ * Causes a general Texture update.
+ * <p/>
+ * Only used Client Side to mark Blocks dirty.
+ */
+ @Override
+ public void issueTextureUpdate() {
+ if (!isTicking) {
+ markBlockForUpdate();
+ } else {
+ needsUpdate = true;
+ }
+ }
+
+ public boolean box(Block aBlock, double[] aBox) {
+ aBlock.setBlockBounds(
+ (float) aBox[0],
+ (float) aBox[1],
+ (float) aBox[2],
+ (float) aBox[3],
+ (float) aBox[4],
+ (float) aBox[5]);
+ return true;
+ }
+
+ protected void markBlockForUpdate() {
+ worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
+ // worldObj.func_147479_m(xCoord, yCoord, zCoord);
+ needsUpdate = false;
+ }
+
+ public boolean box(Block aBlock, float[] aBox) {
+ aBlock.setBlockBounds(aBox[0], aBox[1], aBox[2], aBox[3], aBox[4], aBox[5]);
+ return true;
+ }
+
+ @Override
+ public void onTileEntityPlaced() {
+ /* empty */
+ }
+
+ public boolean box(Block aBlock, double aMinX, double aMinY, double aMinZ, double aMaxX, double aMaxY,
+ double aMaxZ) {
+ aBlock.setBlockBounds((float) aMinX, (float) aMinY, (float) aMinZ, (float) aMaxX, (float) aMaxY, (float) aMaxZ);
+ return true;
+ }
+
+ @Override
+ public void setShouldRefresh(boolean aShouldRefresh) {
+ shouldRefresh = aShouldRefresh;
+ }
+
+ /**
+ * shouldJoinIc2Enet - defaults to false, override to change
+ */
+ @Override
+ public boolean shouldJoinIc2Enet() {
+ return false;
+ }
+
+ @Override
+ public final void addCollisionBoxesToList(AxisAlignedBB aAABB, List<AxisAlignedBB> aList, Entity aEntity) {
+ box(getCollisionBoundingBoxFromPool(), aAABB, aList);
+ }
+
+ /**
+ * Simple Function to prevent Block Updates from happening multiple times within the same Tick.
+ */
+ @Override
+ public final void issueBlockUpdate() {
+ if (isTicking) needsBlockUpdate = true;
+ else doBlockUpdate();
+ }
+
+ @Override
+ public boolean isStillValid() {
+ return !isInvalid();
+ }
+
+ @Override
+ public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) {
+ return true;
+ }
+
+ public AxisAlignedBB box() {
+ return AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 1, zCoord + 1);
+ }
+
+ public boolean box(AxisAlignedBB aBox, AxisAlignedBB aAABB, List<AxisAlignedBB> aList) {
+ return aBox != null && aBox.intersectsWith(aAABB) && aList.add(aBox);
+ }
+
+ public float[] shrunkBox() {
+ return PX_BOX;
+ }
+
+ @Override
+ public void setBlockBoundsBasedOnState(Block aBlock) {
+ box(aBlock);
+ }
+
+ @Override
+ public AxisAlignedBB getCollisionBoundingBoxFromPool() {
+ return box();
+ }
+
+ @Override
+ public AxisAlignedBB getSelectedBoundingBoxFromPool() {
+ if (forceFullSelectionBox) return box();
+ return box(shrunkBox());
+ }
+
+ @Override
+ public ItemStack getPickBlock(MovingObjectPosition aTarget) {
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(mteRegistry);
+ return tRegistry == null ? null : tRegistry.getItem(mteID, writeItemNBT(new NBTTagCompound()));
+ }
+
+ @Override
+ public void onBlockAdded() {}
+
+ @Override
+ public String getOwnerName() {
+ if (GT_Utility.isStringInvalid(ownerName)) return "Player";
+ return ownerName;
+ }
+
+ @Override
+ public String setOwnerName(String aName) {
+ if (GT_Utility.isStringInvalid(aName)) return ownerName = "Player";
+ return ownerName = aName;
+ }
+
+ @Override
+ public UUID getOwnerUuid() {
+ return ownerUUID;
+ }
+
+ @Override
+ public void setOwnerUuid(UUID uuid) {
+ ownerUUID = uuid;
+ }
+
+ @Override
+ public boolean onPlaced(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ,
+ ForgeDirection side, float aHitX, float aHitY, float aHitZ) {
+ facing = getSideForPlayerPlacing(aPlayer, facing, getValidFacings());
+ setOwnerUuid(aPlayer.getUniqueID());
+ setOwnerName(aPlayer.getDisplayName());
+ onFacingChange();
+ return true;
+ }
+
+ @Override
+ public boolean allowInteraction(Entity aEntity) {
+ return true;
+ }
+
+ public boolean allowRightclick(Entity aEntity) {
+ return allowInteraction(aEntity);
+ }
+
+ @Override
+ public boolean onBlockActivated(EntityPlayer aPlayer, ForgeDirection side, float aX, float aY, float aZ) {
+ try {
+ return allowRightclick(aPlayer) && onRightClick(aPlayer, side, aX, aY, aZ);
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("onBlockActivated Failed", e);
+ e.printStackTrace(GT_Log.err);
+ return true;
+ }
+ }
+
+ @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;
+ } else { // server side
+ if (!privateAccess() || aPlayer.getDisplayName()
+ .equalsIgnoreCase(getOwnerName())) {
+ final ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem();
+ final ForgeDirection wrenchSide = GT_Utility.determineWrenchingSide(side, aX, aY, aZ);
+
+ if (tCurrentItem != null) {
+ if (getColorization() >= 0
+ && GT_Utility.areStacksEqual(new ItemStack(Items.water_bucket, 1), tCurrentItem)) {
+ // TODO (Colorization)
+ }
+
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWrenchList))
+ return onWrenchRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sScrewdriverList))
+ return onScrewdriverRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sHardHammerList))
+ return onHammerRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSoftHammerList))
+ return onMalletRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSolderingToolList))
+ return onSolderingRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sWireCutterList))
+ return onWireCutterRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ, tCurrentItem);
+
+ final ForgeDirection coverSide = getCoverIDAtSide(side) == 0 ? wrenchSide : side;
+
+ if (getCoverIDAtSide(coverSide) == 0) {
+ if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sCovers.keySet())) {
+ if (GregTech_API.getCoverBehaviorNew(tCurrentItem)
+ .isCoverPlaceable(coverSide, tCurrentItem, this)
+ && allowCoverOnSide(coverSide, new GT_ItemStack(tCurrentItem))) {
+ setCoverItemAtSide(coverSide, tCurrentItem);
+ if (!aPlayer.capabilities.isCreativeMode) tCurrentItem.stackSize--;
+ GT_Utility.sendSoundToPlayers(
+ worldObj,
+ SoundResource.IC2_TOOLS_WRENCH,
+ 1.0F,
+ -1,
+ xCoord,
+ yCoord,
+ zCoord);
+ issueClientUpdate();
+ }
+ sendCoverDataIfNeeded();
+ 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);
+ }
+ sendCoverDataIfNeeded();
+ return true;
+ }
+ }
+ } 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 (aPlayer.getHeldItem() != null && aPlayer.getHeldItem()
+ .getItem() instanceof ItemBlock) {
+ return false;
+ }
+
+ return openModularUi(aPlayer, side);
+ }
+ }
+ return false;
+ }
+
+ public boolean hasGui(ForgeDirection side) {
+ return false;
+ }
+
+ boolean openModularUi(EntityPlayer aPlayer, ForgeDirection side) {
+ if (!hasGui(side) || !isServerSide()) {
+ System.out.println("No GUI or Not Serverside");
+ return false;
+ }
+
+ GT_UIInfos.openGTTileEntityUI(this, aPlayer);
+ System.out.println("Trying to open a UI");
+ return true;
+ }
+
+ public boolean onWrenchRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ, ItemStack aTool) {
+ if (setMainFacing(wrenchSide)) {
+ GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 1000, aPlayer);
+ GT_Utility.sendSoundToPlayers(worldObj, SoundResource.IC2_TOOLS_WRENCH, 1.0F, -1, xCoord, yCoord, zCoord);
+ }
+ return onWrenchRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ public boolean onScrewdriverRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ, ItemStack aTool) {
+ if (GT_ModHandler.damageOrDechargeItem(tCurrentItem, 1, 200, aPlayer)) {
+ setCoverDataAtSide(
+ wrenchSide,
+ getCoverBehaviorAtSideNew(wrenchSide).onCoverScrewdriverClick(
+ wrenchSide,
+ getCoverIDAtSide(wrenchSide),
+ getComplexCoverDataAtSide(wrenchSide),
+ this,
+ aPlayer,
+ aX,
+ aY,
+ aZ));
+ // TODO: Update connections!
+ GT_Utility.sendSoundToPlayers(worldObj, SoundResource.IC2_TOOLS_WRENCH, 1.0F, -1, xCoord, yCoord, zCoord);
+ }
+ return onScrewdriverRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ public boolean onHammerRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ, ItemStack aTool) {
+
+ return onHammerRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ public boolean onMalletRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ, ItemStack aTool) {
+
+ return onMalletRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ public boolean onSolderingRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ, ItemStack aTool) {
+
+ return onSolderingRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ public boolean onWireCutterRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ, ItemStack aTool) {
+
+ return onWireCutterRightClick(aPlayer, tCurrentItem, wrenchSide, aX, aY, aZ);
+ }
+
+ @Deprecated
+ public boolean onHammerRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ) {
+ return true;
+ }
+
+ @Deprecated
+ public boolean onSolderingRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ) {
+ return true;
+ }
+
+ @Deprecated
+ public boolean onMalletRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ) {
+ return true;
+ }
+
+ @Deprecated
+ public boolean onWireCutterRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ) {
+ return true;
+ }
+
+ @Deprecated
+ public boolean onWrenchRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX,
+ float aY, float aZ) {
+ return true;
+ }
+
+ @Deprecated
+ public boolean onScrewdriverRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide,
+ float aX, float aY, float aZ) {
+ return true;
+ }
+
+ @Override
+ public float getExplosionResistance(Entity aExploder, double aExplosionX, double aExplosionY, double aExplosionZ) {
+ return getExplosionResistance();
+ }
+
+ @Override
+ public float getExplosionResistance() {
+ return 10.0F;
+ }
+
+ @Override
+ public void onExploded(Explosion aExplosion) {}
+
+ @Override
+ public boolean isSideSolid(ForgeDirection side) {
+ return true;
+ }
+
+ @Override
+ public ArrayList<ItemStack> getDrops(int aFortune, boolean aSilkTouch) {
+ final ArrayList<ItemStack> rList = new ArrayList<>();
+ final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID());
+ if (tRegistry != null) rList.add(tRegistry.getItem(getMultiTileEntityID(), writeItemNBT(new NBTTagCompound())));
+ return rList;
+ }
+
+ @Override
+ public boolean onBlockBroken() {
+ isDead = true;
+ onBaseTEDestroyed();
+ return false;
+ }
+
+ @Override
+ public boolean getSubItems(MultiTileEntityBlock block, Item item, CreativeTabs tab, List<ItemStack> list,
+ short aID) {
+ return true;
+ }
+
+ @Override
+ public boolean recolourBlock(ForgeDirection side, byte aColor) {
+ // if (aColor > 15 || aColor < -1) aColor = -1;
+ // if(paint((byte) (aColor + 1))) {
+ //// updateClientData();
+ //// causeBlockUpdate();
+ // return true;
+ // }
+ // if (unpaint()) {updateClientData(); causeBlockUpdate(); return T;}
+ // mColor = (byte) (aColor + 1);
+ //// if (canAccessData()) mMetaTileEntity.onColorChangeServer(aColor);
+ return false;
+ }
+
+ @Override
+ public boolean playerOwnsThis(EntityPlayer aPlayer, boolean aCheckPrecicely) {
+ if (aCheckPrecicely || privateAccess() || (ownerName.length() == 0))
+ if ((ownerName.length() == 0) && isServerSide()) {
+ setOwnerName(aPlayer.getDisplayName());
+ setOwnerUuid(aPlayer.getUniqueID());
+ } else return !privateAccess() || aPlayer.getDisplayName()
+ .equals("Player") || ownerName.equals("Player") || ownerName.equals(aPlayer.getDisplayName());
+ return true;
+ }
+
+ @Override
+ public boolean privateAccess() {
+ return lockUpgrade;
+ }
+
+ /**
+ * @return a Packet containing all Data which has to be synchronised to the Client - Override as needed
+ */
+ public GT_Packet_MultiTileEntity getClientDataPacket() {
+
+ final GT_Packet_MultiTileEntity packet = new GT_Packet_MultiTileEntity(false);
+ return packet;
+ }
+
+ @Override
+ public void sendClientData(EntityPlayerMP aPlayer) {
+ if (worldObj == null || worldObj.isRemote) return;
+ final GT_Packet_New tPacket = getClientDataPacket();
+ if (aPlayer == null) {
+ GT_Values.NW.sendPacketToAllPlayersInRange(worldObj, tPacket, getXCoord(), getZCoord());
+ } else {
+ GT_Values.NW.sendToPlayer(tPacket, aPlayer);
+ }
+ sendCoverDataIfNeeded();
+ }
+
+ @Override
+ public boolean receiveClientData(int aEventID, int aValue) {
+ super.receiveClientEvent(aEventID, aValue);
+ if (isClientSide()) {
+ issueTextureUpdate();
+ switch (aEventID) {
+ case GregTechTileClientEvents.CHANGE_COMMON_DATA:
+ facing = ForgeDirection.getOrientation(aValue & 7);
+ // mActive = ((aValue & 8) != 0);
+ mRedstone = ((aValue & 16) != 0);
+ // mLockUpgrade = ((aValue&32) != 0);
+ // mWorks = ((aValue & 64) != 0);
+ break;
+ case GregTechTileClientEvents.CHANGE_CUSTOM_DATA:
+ // Nothing here, currently
+ break;
+ case GregTechTileClientEvents.CHANGE_COLOR:
+ if (aValue > 16 || aValue < 0) aValue = 0;
+ color = (byte) aValue;
+ break;
+ 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);
+ break;
+ // case GregTechTileClientEvents.DO_SOUND:
+ // if (mTickTimer > 20)
+ // doSound((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+ // break;
+ // case GregTechTileClientEvents.START_SOUND_LOOP:
+ // if (mTickTimer > 20)
+ // startSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+ // break;
+ // case GregTechTileClientEvents.STOP_SOUND_LOOP:
+ // if (mTickTimer > 20)
+ // stopSoundLoop((byte) aValue, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
+ // break;
+ // case GregTechTileClientEvents.CHANGE_LIGHT:
+ // mLightValue = (byte) aValue;
+ // break;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Packet getDescriptionPacket() {
+ issueClientUpdate();
+ return null;
+ }
+
+ @Override
+ public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor,
+ IWailaConfigHandler config) {
+ super.getWailaBody(itemStack, currentTip, accessor, config);
+ currentTip.add(String.format("Facing: %s", getFrontFacing().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);
+ }
+
+ @Override
+ public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aLogLevel) {
+ final ArrayList<String> tList = new ArrayList<>();
+ if (aLogLevel > 2) {
+ tList.add(
+ "MultiTileRegistry-ID: " + EnumChatFormatting.BLUE
+ + mteRegistry
+ + EnumChatFormatting.RESET
+ + " MultiTile-ID: "
+ + EnumChatFormatting.BLUE
+ + mteID
+ + EnumChatFormatting.RESET);
+ }
+
+ addDebugInfo(aPlayer, aLogLevel, tList);
+
+ return tList;
+ }
+
+ protected void addDebugInfo(EntityPlayer aPlayer, int aLogLevel, ArrayList<String> tList) {
+ /* Do nothing */
+ }
+
+ /**
+ * Energy - Do nothing by Default
+ */
+ @Override
+ public boolean isUniversalEnergyStored(long aEnergyAmount) {
+ return false;
+ }
+
+ @Override
+ public long getUniversalEnergyStored() {
+ return 0;
+ }
+
+ @Override
+ public long getUniversalEnergyCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long getOutputAmperage() {
+ return 0;
+ }
+
+ @Override
+ public long getOutputVoltage() {
+ return 0;
+ }
+
+ @Override
+ public long getInputAmperage() {
+ return 0;
+ }
+
+ @Override
+ public long getInputVoltage() {
+ return 0;
+ }
+
+ @Override
+ public boolean decreaseStoredEnergyUnits(long energy, boolean ignoreTooLittleEnergy) {
+ return false;
+ }
+
+ @Override
+ public boolean increaseStoredEnergyUnits(long energy, boolean ignoreTooMuchEnergy) {
+ return false;
+ }
+
+ @Override
+ public boolean drainEnergyUnits(ForgeDirection side, long aVoltage, long aAmperage) {
+ return false;
+ }
+
+ @Override
+ public long getAverageElectricInput() {
+ return 0;
+ }
+
+ @Override
+ public long getAverageElectricOutput() {
+ return 0;
+ }
+
+ @Override
+ public long getStoredEU() {
+ return 0;
+ }
+
+ @Override
+ public long getEUCapacity() {
+ return 0;
+ }
+
+ @Override
+ public long injectEnergyUnits(ForgeDirection side, long aVoltage, long aAmperage) {
+ return 0;
+ }
+
+ @Override
+ public boolean inputEnergyFrom(ForgeDirection side) {
+ return false;
+ }
+
+ @Override
+ public boolean outputsEnergyTo(ForgeDirection side) {
+ return false;
+ }
+
+ /**
+ * Inventory - Do nothing by default
+ */
+
+ @Override
+ public boolean hasInventoryBeenModified() {
+ return false;
+ }
+
+ @Override
+ public boolean isValidSlot(int aIndex) {
+ return false;
+ }
+
+ @Override
+ public boolean addStackToSlot(int aIndex, ItemStack aStack) {
+ return false;
+ }
+
+ @Override
+ public boolean addStackToSlot(int aIndex, ItemStack aStack, int aAmount) {
+ return false;
+ }
+
+ @Override
+ public void markInventoryBeenModified() {
+ hasInventoryChanged = true;
+ }
+
+ /*
+ * Cover Helpers
+ */
+
+ public boolean coverLetsFluidIn(ForgeDirection side, Fluid aFluid) {
+ return getCoverInfoAtSide(side).letsFluidIn(aFluid);
+ }
+
+ public boolean coverLetsFluidOut(ForgeDirection side, Fluid aFluid) {
+ return getCoverInfoAtSide(side).letsFluidOut(aFluid);
+ }
+
+ public boolean coverLetsEnergyIn(ForgeDirection side) {
+ return getCoverInfoAtSide(side).letsEnergyIn();
+ }
+
+ public boolean coverLetsEnergyOut(ForgeDirection side) {
+ return getCoverInfoAtSide(side).letsEnergyOut();
+ }
+
+ public boolean coverLetsItemsIn(ForgeDirection side, int aSlot) {
+ return getCoverInfoAtSide(side).letsItemsIn(aSlot);
+ }
+
+ public boolean coverLetsItemsOut(ForgeDirection side, int aSlot) {
+ return getCoverInfoAtSide(side).letsItemsOut(aSlot);
+ }
+
+ @Override
+ public ItemStack getStackForm(long aAmount) {
+ return new ItemStack(Item.getItemById(getMultiTileEntityRegistryID()), (int) aAmount, getMultiTileEntityID());
+ }
+
+ protected enum SidedTextureNames {
+
+ Base("base"),
+ Left("left"),
+ Right("right"),
+ Top("top"),
+ Bottom("bottom"),
+ Back("back"),
+ Front("front");
+
+ private final String name;
+ public static final SidedTextureNames[] TEXTURES = { Base, Left, Right, Top, Bottom, Back, Front };
+
+ SidedTextureNames(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ protected enum StatusTextures {
+
+ Active("active", false),
+ ActiveWithGlow("active_glow", true),
+ Inactive("inactive", false),
+ InactiveWithGlow("inactive_glow", true);
+
+ private final String name;
+ private final boolean hasGlow;
+ public static final StatusTextures[] TEXTURES = { Active, ActiveWithGlow, Inactive, InactiveWithGlow };
+
+ StatusTextures(String name, boolean hasGlow) {
+ this.name = name;
+ this.hasGlow = hasGlow;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean hasGlow() {
+ return hasGlow;
+ }
+ }
+
+ @Override
+ public void getFullPacketData(GT_Packet_MultiTileEntity packet) {
+ packet.addData(new CoordinateData(getCoords()));
+ packet.addData(new CommonData(mStrongRedstone, color, (byte) 0));
+ packet.addData(new MultiTileEntityData(mteRegistry, mteID));
+ }
+
+ @Override
+ public void getGraphicPacketData(GT_Packet_MultiTileEntity packet) {
+ packet.addData(new CoordinateData(getCoords()));
+ packet.addData(new MultiTileEntityData(mteRegistry, mteID));
+ }
+
+ @Override
+ public void getTimedPacketData(GT_Packet_MultiTileEntity packet) {
+ packet.addData(new CoordinateData(getCoords()));
+ packet.addData(new MultiTileEntityData(mteRegistry, mteID));
+ }
+
+ @Override
+ public void sendFullPacket(@Nonnull EntityPlayerMP player) {
+ fullPacket.clearData();
+ getFullPacketData(fullPacket);
+ GT_Values.NW.sendToPlayer(fullPacket, player);
+ }
+
+ @Override
+ public void sendGraphicPacket() {
+ graphicPacket.clearData();
+ getGraphicPacketData(graphicPacket);
+ GT_Values.NW.sendPacketToAllPlayersInRange(worldObj, graphicPacket, getXCoord(), getZCoord());
+ }
+
+ @Override
+ public void sendTimedPacket() {
+ timedPacket.clearData();
+ getTimedPacketData(timedPacket);
+ GT_Values.NW.sendPacketToAllPlayersInRange(worldObj, timedPacket, getXCoord(), getZCoord());
+ }
+
+ @Override
+ public void onChunkUnload() {
+ super.onChunkUnload();
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/base/NonTickableMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/NonTickableMultiTileEntity.java
new file mode 100644
index 0000000000..2837a88180
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/NonTickableMultiTileEntity.java
@@ -0,0 +1,62 @@
+package gregtech.api.multitileentity.base;
+
+import static gregtech.api.enums.GT_Values.NW;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.Packet;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.net.GT_Packet_SendCoverData;
+import gregtech.api.util.ISerializableObject;
+import gregtech.common.covers.CoverInfo;
+
+public abstract class NonTickableMultiTileEntity extends MultiTileEntity {
+
+ boolean mConstructed = false; // Keeps track of whether this TE has been constructed and placed in the world
+
+ public NonTickableMultiTileEntity() {
+ super(false);
+ }
+
+ @Override
+ public void issueClientUpdate() {
+ if (worldObj != null && !worldObj.isRemote) {
+ sendClientData(null);
+ sendGraphicPacket();
+ }
+ }
+
+ @Override
+ public Packet getDescriptionPacket() {
+ // We should have a world object and have been constructed by this point
+ mConstructed = true;
+
+ super.getDescriptionPacket();
+ // We don't get ticked, so if we have any cover data that needs to be sent, send it now
+ sendCoverDataIfNeeded();
+ return null;
+ }
+
+ @Override
+ public void issueCoverUpdate(ForgeDirection side) {
+ if (!mConstructed) {
+ // Queue these up and send them with the description packet
+ super.issueCoverUpdate(side);
+ } else {
+ // Otherwise, send the data right away
+ final CoverInfo coverInfo = getCoverInfoAtSide(side);
+ NW.sendPacketToAllPlayersInRange(worldObj, new GT_Packet_SendCoverData(coverInfo, this), xCoord, zCoord);
+
+ // Just in case
+ coverInfo.setNeedsUpdate(false);
+ }
+ }
+
+ @Override
+ public void receiveCoverData(ForgeDirection coverSide, int aCoverID, ISerializableObject aCoverData,
+ EntityPlayerMP aPlayer) {
+ super.receiveCoverData(coverSide, aCoverID, aCoverData, aPlayer);
+ // We don't get ticked so issue the texture update right away
+ issueTextureUpdate();
+ }
+}
diff --git a/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java
new file mode 100644
index 0000000000..987a4c18b3
--- /dev/null
+++ b/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java
@@ -0,0 +1,172 @@
+package gregtech.api.multitileentity.base;
+
+import static gregtech.GT_Mod.GT_FML_LOGGER;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import gregtech.api.enums.GT_Values;
+import gregtech.api.task.TaskHost;
+import gregtech.api.task.TickableTask;
+import gregtech.api.util.GT_Log;
+import gregtech.api.util.GT_Util;
+
+public abstract class TickableMultiTileEntity extends MultiTileEntity implements TaskHost {
+
+ /** Variable for seeing if the Tick Function is called right now. */
+ public boolean isRunningTick = false;
+ /** Gets set to true when the Block received a Block Update. */
+ public boolean blockUpdated = false;
+ /** Timer Value */
+ protected long timer = 0;
+ /** Variable for updating Data to the Client */
+ private boolean sendClientData = false;
+
+ private final Map<String, TickableTask<?>> tasks = new HashMap<>();
+
+ public TickableMultiTileEntity() {
+ super(true);
+ }
+
+ @Override
+ public final void registerTask(@Nonnull TickableTask<?> task) {
+ if (tasks.containsKey(task.getName())) {
+ throw new IllegalStateException(String.format("Task with name %s is already registered", task.getName()));
+ }
+ tasks.put(task.getName(), task);
+ }
+
+ @Nullable
+ public TickableTask<?> getTask(@Nonnull String name) {
+ return tasks.get(name);
+ }
+
+ @Override
+ public final void updateEntity() {
+ isRunningTick = true;
+ final boolean isServerSide = isServerSide();
+ try {
+ if (timer++ == 0) {
+ markDirty();
+ GT_Util.markChunkDirty(this);
+ onFirstTick(isServerSide);
+ }
+ if (isDead()) {
+ return;
+ }
+ onPreTick(timer, isServerSide);
+ super.updateEntity();
+ if (!isServerSide && needsUpdate) {
+ worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
+ needsUpdate = false;
+ }
+ onTick(timer, isServerSide);
+ for (TickableTask<?> task : tasks.values()) {
+ task.update(timer, isServerSide);
+ }
+ if (isServerSide && timer > 2 && sendClientData) {
+ sendClientData(null);
+ }
+ onPostTick(timer, isServerSide);
+
+ } catch (Throwable e) {
+ GT_FML_LOGGER.error("UpdateEntity Failed", e);
+ e.printStackTrace(GT_Log.err);
+ try {
+ onTickFailed(timer, isServerSide);
+ } catch (Throwable e2) {
+ GT_FML_LOGGER.error("UpdateEntity:onTickFailed Failed", e);
+ }
+ }
+
+ isRunningTick = false;
+ }
+
+ @Override
+ public void sendClientData(EntityPlayerMP aPlayer) {
+ if (sendClientData) {
+ // GT_FML_LOGGER.info("Sending client data");
+ super.sendClientData(aPlayer);
+ sendClientData = false;
+ }
+ }
+
+ /**
+ * The very first Tick happening to this TileEntity.
+ */
+ public void onFirstTick(boolean isServerSide) {
+ if (isServerSide) {
+ checkDropCover();
+ } else {
+ requestCoverDataIfNeeded();
+ }
+ }
+
+ /**
+ * The first part of the Tick, before block update.
+ */
+ public void onPreTick(long tick, boolean isServerSide) {}
+
+ /**
+ * The regular Tick. After block update, before sending data to client.
+ */
+ public void onTick(long tick, boolean isServerSide) {}
+
+ /**
+ * The absolute last part of the Tick, after sending data to client.
+ */
+ public void onPostTick(long tick, boolean isServerSide) {}
+
+ /**
+ * Gets called when there is an Exception/Error happening during one of the Tick methods.
+ */
+ public void onTickFailed(long tick, boolean isServerSide) {}
+
+ @Override
+ protected final void readTasksNBT(NBTTagCompound nbt) {
+ if (nbt.hasKey(GT_Values.NBT.TASKS)) {
+ NBTTagCompound tasksTag = nbt.getCompoundTag(GT_Values.NBT.TASKS);
+ for (TickableTask<?> task : tasks.values()) {
+ if (tasksTag.hasKey(task.getName())) {
+ task.readFromNBT(tasksTag.getCompoundTag(task.getName()));
+ }
+ }
+ }
+ }
+
+ @Override
+ protected final void writeTasksNBT(NBTTagCompound aNBT) {
+ NBTTagCompound tasksTag = new NBTTagCompound();
+ for (TickableTask<?> task : tasks.values()) {
+ NBTTagCompound tag = new NBTTagCompound();
+ task.writeToNBT(tag);
+ tasksTag.setTag(task.getName(), tag);
+ }
+ aNBT.setTag(GT_Values.NBT.TASKS, tasksTag);
+ }
+
+ @Override
+ public void onNeighborBlockChange(World aWorld, Block aBlock) {
+ blockUpdated = true;
+ }
+
+ @Override
+ public void issueClientUpdate() {
+ sendClientData = true;
+ sendGraphicPacket();
+ }
+
+ @Override
+ public byte getComparatorValue(ForgeDirection side) {
+ return 0;
+ }
+}