diff options
Diffstat (limited to 'src/main/java/gregtech/api/metatileentity/BaseTileEntity.java')
-rw-r--r-- | src/main/java/gregtech/api/metatileentity/BaseTileEntity.java | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java new file mode 100644 index 0000000000..d8b0086f0f --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java @@ -0,0 +1,979 @@ +package gregtech.api.metatileentity; + +import static gregtech.api.enums.GT_Values.COMPASS_DIRECTIONS; +import static gregtech.api.enums.GT_Values.GT; +import static gregtech.api.enums.GT_Values.NW; +import static gregtech.api.enums.GT_Values.SIDE_DOWN; +import static gregtech.api.enums.GT_Values.SIDE_UP; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MathHelper; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.IFluidHandler; + +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.ItemDrawable; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.screen.ITileWithModularUI; +import com.gtnewhorizons.modularui.api.screen.ModularUIContext; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import gregtech.GT_Mod; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.GT_Values; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddInventorySlots; +import gregtech.api.interfaces.modularui.IGetGUITextureSet; +import gregtech.api.interfaces.tileentity.IGTEnet; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; +import gregtech.api.interfaces.tileentity.IIC2Enet; +import gregtech.api.net.GT_Packet_Block_Event; +import gregtech.api.net.GT_Packet_SetConfigurationCircuit; +import gregtech.api.util.GT_TooltipDataCache; +import gregtech.api.util.GT_Util; +import gregtech.api.util.GT_Utility; +import gregtech.common.gui.modularui.uifactory.SelectItemUIFactory; +import ic2.api.energy.event.EnergyTileLoadEvent; +import ic2.api.energy.event.EnergyTileUnloadEvent; + +/** + * The Functions my old TileEntities and my BaseMetaTileEntities have in common. + * <p/> + * Basically everything a TileEntity should have. + */ +public abstract class BaseTileEntity extends TileEntity implements IHasWorldObjectAndCoords, IIC2Enet, IGTEnet, + ITileWithModularUI, IAddGregtechLogo, IGetGUITextureSet, IAddInventorySlots { + + protected boolean mInventoryChanged = false; + + /** + * Buffers adjacent TileEntities for faster access + * <p/> + * "this" means that there is no TileEntity, while "null" means that it doesn't know if there is even a TileEntity + * and still needs to check that if needed. + */ + private final TileEntity[] mBufferedTileEntities = new TileEntity[6]; + /** + * If this TileEntity checks for the Chunk to be loaded before returning World based values. The AdvPump hacks this + * to false to ensure everything runs properly even when far Chunks are not actively loaded. But anything else + * should not cause worfin' Chunks, uhh I mean orphan Chunks. + */ + public boolean ignoreUnloadedChunks = true; + /** + * This Variable checks if this TileEntity is dead, because Minecraft is too stupid to have proper TileEntity + * unloading. + */ + public boolean isDead = false; + + private final ChunkCoordinates mReturnedCoordinates = new ChunkCoordinates(); + + public static ForgeDirection getSideForPlayerPlacing(Entity aPlayer, ForgeDirection defaultFacing, + boolean[] aAllowedFacings) { + if (aPlayer != null) { + if (aPlayer.rotationPitch >= 65 && aAllowedFacings[SIDE_UP]) return ForgeDirection.UP; + if (aPlayer.rotationPitch <= -65 && aAllowedFacings[SIDE_DOWN]) return ForgeDirection.DOWN; + final byte rFacing = COMPASS_DIRECTIONS[MathHelper.floor_double(0.5D + 4.0F * aPlayer.rotationYaw / 360.0F) + & 0x3]; + if (aAllowedFacings[rFacing]) return ForgeDirection.getOrientation(rFacing); + } + for (final ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) if (aAllowedFacings[dir.ordinal()]) return dir; + return defaultFacing; + } + + private void clearNullMarkersFromTileEntityBuffer() { + for (int i = 0; i < mBufferedTileEntities.length; i++) + if (mBufferedTileEntities[i] == this) mBufferedTileEntities[i] = null; + } + + /** + * Called automatically when the Coordinates of this TileEntity have been changed + */ + protected final void clearTileEntityBuffer() { + Arrays.fill(mBufferedTileEntities, null); + } + + @Override + public final World getWorld() { + return worldObj; + } + + @Override + public final int getXCoord() { + return xCoord; + } + + @Override + public final short getYCoord() { + return (short) yCoord; + } + + @Override + public final int getZCoord() { + return zCoord; + } + + @Override + public ChunkCoordinates getCoords() { + mReturnedCoordinates.posX = xCoord; + mReturnedCoordinates.posY = yCoord; + mReturnedCoordinates.posZ = zCoord; + return mReturnedCoordinates; + } + + @Override + public final int getOffsetX(ForgeDirection side, int aMultiplier) { + return xCoord + side.offsetX * aMultiplier; + } + + @Override + public final short getOffsetY(ForgeDirection side, int aMultiplier) { + return (short) (yCoord + side.offsetY * aMultiplier); + } + + @Override + public final int getOffsetZ(ForgeDirection side, int aMultiplier) { + return zCoord + side.offsetZ * aMultiplier; + } + + @Override + public final boolean isServerSide() { + if (worldObj == null) { + return FMLCommonHandler.instance() + .getEffectiveSide() == Side.SERVER; + } + return !worldObj.isRemote; + } + + @Override + public final boolean isClientSide() { + if (worldObj == null) { + return FMLCommonHandler.instance() + .getEffectiveSide() == Side.CLIENT; + } + return worldObj.isRemote; + } + + @Override + @Deprecated + public final boolean openGUI(EntityPlayer aPlayer) { + return openGUI(aPlayer, 0); + } + + @Override + @Deprecated + public final boolean openGUI(EntityPlayer aPlayer, int aID) { + if (aPlayer == null) return false; + aPlayer.openGui(GT, aID, worldObj, xCoord, yCoord, zCoord); + return true; + } + + @Override + public boolean isInvalidTileEntity() { + return isInvalid(); + } + + @Override + public int getRandomNumber(int aRange) { + return ThreadLocalRandom.current() + .nextInt(aRange); + } + + @Override + public final BiomeGenBase getBiome(int aX, int aZ) { + return worldObj.getBiomeGenForCoords(aX, aZ); + } + + @Override + public final BiomeGenBase getBiome() { + return getBiome(xCoord, zCoord); + } + + @Override + public final Block getBlockOffset(int aX, int aY, int aZ) { + return getBlock(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final Block getBlockAtSide(ForgeDirection side) { + return getBlockAtSideAndDistance(side, 1); + } + + @Override + public final Block getBlockAtSideAndDistance(ForgeDirection side, int aDistance) { + return getBlock(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final byte getMetaIDOffset(int aX, int aY, int aZ) { + return getMetaID(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final byte getMetaIDAtSide(ForgeDirection side) { + return getMetaIDAtSideAndDistance(side, 1); + } + + @Override + public final byte getMetaIDAtSideAndDistance(ForgeDirection side, int aDistance) { + return getMetaID(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final byte getLightLevelOffset(int aX, int aY, int aZ) { + return getLightLevel(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final byte getLightLevelAtSide(ForgeDirection side) { + return getLightLevelAtSideAndDistance(side, 1); + } + + @Override + public final byte getLightLevelAtSideAndDistance(ForgeDirection side, int aDistance) { + return getLightLevel(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final boolean getOpacityOffset(int aX, int aY, int aZ) { + return getOpacity(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final boolean getOpacityAtSide(ForgeDirection side) { + return getOpacityAtSideAndDistance(side, 1); + } + + @Override + public final boolean getOpacityAtSideAndDistance(ForgeDirection side, int aDistance) { + return getOpacity(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final boolean getSkyOffset(int aX, int aY, int aZ) { + return getSky(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final boolean getSkyAtSide(ForgeDirection side) { + return getSkyAtSideAndDistance(side, 1); + } + + @Override + public final boolean getSkyAtSideAndDistance(ForgeDirection side, int aDistance) { + return getSky(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final boolean getAirOffset(int aX, int aY, int aZ) { + return getAir(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final boolean getAirAtSide(ForgeDirection side) { + return getAirAtSideAndDistance(side, 1); + } + + @Override + public final boolean getAirAtSideAndDistance(ForgeDirection side, int aDistance) { + return getAir(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final TileEntity getTileEntityOffset(int aX, int aY, int aZ) { + return getTileEntity(xCoord + aX, yCoord + aY, zCoord + aZ); + } + + @Override + public final TileEntity getTileEntityAtSideAndDistance(ForgeDirection side, int aDistance) { + if (aDistance == 1) return getTileEntityAtSide(side); + return getTileEntity(getOffsetX(side, aDistance), getOffsetY(side, aDistance), getOffsetZ(side, aDistance)); + } + + @Override + public final IInventory getIInventory(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntity(aX, aY, aZ); + if (tTileEntity instanceof IInventory) return (IInventory) tTileEntity; + return null; + } + + @Override + public final IInventory getIInventoryOffset(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntityOffset(aX, aY, aZ); + if (tTileEntity instanceof IInventory) return (IInventory) tTileEntity; + return null; + } + + @Override + public final IInventory getIInventoryAtSide(ForgeDirection side) { + final TileEntity tTileEntity = getTileEntityAtSide(side); + if (tTileEntity instanceof IInventory) return (IInventory) tTileEntity; + return null; + } + + @Override + public final IInventory getIInventoryAtSideAndDistance(ForgeDirection side, int aDistance) { + final TileEntity tTileEntity = getTileEntityAtSideAndDistance(side, aDistance); + if (tTileEntity instanceof IInventory) return (IInventory) tTileEntity; + return null; + } + + @Override + public final IFluidHandler getITankContainer(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntity(aX, aY, aZ); + if (tTileEntity instanceof IFluidHandler) return (IFluidHandler) tTileEntity; + return null; + } + + @Override + public final IFluidHandler getITankContainerOffset(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntityOffset(aX, aY, aZ); + if (tTileEntity instanceof IFluidHandler) return (IFluidHandler) tTileEntity; + return null; + } + + @Override + public final IFluidHandler getITankContainerAtSide(ForgeDirection side) { + final TileEntity tTileEntity = getTileEntityAtSide(side); + if (tTileEntity instanceof IFluidHandler) return (IFluidHandler) tTileEntity; + return null; + } + + @Override + public final IFluidHandler getITankContainerAtSideAndDistance(ForgeDirection side, int aDistance) { + final TileEntity tTileEntity = getTileEntityAtSideAndDistance(side, aDistance); + if (tTileEntity instanceof IFluidHandler) return (IFluidHandler) tTileEntity; + return null; + } + + @Override + public final IGregTechTileEntity getIGregTechTileEntity(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntity(aX, aY, aZ); + if (tTileEntity instanceof IGregTechTileEntity) return (IGregTechTileEntity) tTileEntity; + return null; + } + + @Override + public final IGregTechTileEntity getIGregTechTileEntityOffset(int aX, int aY, int aZ) { + final TileEntity tTileEntity = getTileEntityOffset(aX, aY, aZ); + if (tTileEntity instanceof IGregTechTileEntity) return (IGregTechTileEntity) tTileEntity; + return null; + } + + @Override + public final IGregTechTileEntity getIGregTechTileEntityAtSide(ForgeDirection side) { + final TileEntity tTileEntity = getTileEntityAtSide(side); + if (tTileEntity instanceof IGregTechTileEntity) return (IGregTechTileEntity) tTileEntity; + return null; + } + + @Override + public final IGregTechTileEntity getIGregTechTileEntityAtSideAndDistance(ForgeDirection side, int aDistance) { + final TileEntity tTileEntity = getTileEntityAtSideAndDistance(side, aDistance); + if (tTileEntity instanceof IGregTechTileEntity) return (IGregTechTileEntity) tTileEntity; + return null; + } + + @Override + public final Block getBlock(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return Blocks.air; + return worldObj.getBlock(aX, aY, aZ); + } + + public Block getBlock(ChunkCoordinates aCoords) { + if (worldObj == null) return Blocks.air; + if (ignoreUnloadedChunks && crossedChunkBorder(aCoords) + && !worldObj.blockExists(aCoords.posX, aCoords.posY, aCoords.posZ)) return Blocks.air; + return worldObj.getBlock(aCoords.posX, aCoords.posY, aCoords.posZ); + } + + @Override + public final byte getMetaID(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return 0; + return (byte) worldObj.getBlockMetadata(aX, aY, aZ); + } + + @Override + public final byte getLightLevel(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return 0; + return (byte) (worldObj.getLightBrightness(aX, aY, aZ) * 15); + } + + @Override + public final boolean getSky(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return true; + return worldObj.canBlockSeeTheSky(aX, aY, aZ); + } + + @Override + public final boolean getOpacity(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return false; + return GT_Utility.isOpaqueBlock(worldObj, aX, aY, aZ); + } + + @Override + public final boolean getAir(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return true; + return GT_Utility.isBlockAir(worldObj, aX, aY, aZ); + } + + @Override + public TileEntity getTileEntity(int aX, int aY, int aZ) { + if (ignoreUnloadedChunks && crossedChunkBorder(aX, aZ) && !worldObj.blockExists(aX, aY, aZ)) return null; + return worldObj.getTileEntity(aX, aY, aZ); + } + + @Override + public final TileEntity getTileEntityAtSide(ForgeDirection side) { + final int ordinalSide = side.ordinal(); + if (side == ForgeDirection.UNKNOWN || mBufferedTileEntities[ordinalSide] == this) return null; + final int tX = getOffsetX(side, 1); + final int tY = getOffsetY(side, 1); + final int tZ = getOffsetZ(side, 1); + if (crossedChunkBorder(tX, tZ)) { + mBufferedTileEntities[ordinalSide] = null; + if (ignoreUnloadedChunks && !worldObj.blockExists(tX, tY, tZ)) return null; + } + if (mBufferedTileEntities[ordinalSide] == null) { + mBufferedTileEntities[ordinalSide] = worldObj.getTileEntity(tX, tY, tZ); + if (mBufferedTileEntities[ordinalSide] == null) { + mBufferedTileEntities[ordinalSide] = this; + return null; + } + return mBufferedTileEntities[ordinalSide]; + } + if (mBufferedTileEntities[ordinalSide].isInvalid()) { + mBufferedTileEntities[ordinalSide] = null; + return getTileEntityAtSide(side); + } + if (mBufferedTileEntities[ordinalSide].xCoord == tX && mBufferedTileEntities[ordinalSide].yCoord == tY + && mBufferedTileEntities[ordinalSide].zCoord == tZ) { + return mBufferedTileEntities[ordinalSide]; + } + return null; + } + + @Override + public void writeToNBT(NBTTagCompound aNBT) { + super.writeToNBT(aNBT); + } + + @Override + public boolean isDead() { + return isDead || isInvalidTileEntity(); + } + + @Override + public void validate() { + clearNullMarkersFromTileEntityBuffer(); + super.validate(); + } + + @Override + public void invalidate() { + leaveEnet(); + clearNullMarkersFromTileEntityBuffer(); + super.invalidate(); + } + + @Override + public void onChunkUnload() { + leaveEnet(); + clearNullMarkersFromTileEntityBuffer(); + super.onChunkUnload(); + isDead = true; + } + + @Override + public void updateEntity() { + // Well if the TileEntity gets ticked it is alive. + isDead = false; + } + + public final void onAdjacentBlockChange(int ignoredAX, int ignoredAY, int ignoredAZ) { + clearNullMarkersFromTileEntityBuffer(); + } + + public void updateNeighbours(int mStrongRedstone, int oStrongRedstone) { + final Block thisBlock = getBlockOffset(0, 0, 0); + for (final ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + final int x1 = xCoord + dir.offsetX, y1 = yCoord + dir.offsetY, z1 = zCoord + dir.offsetZ; + + if (worldObj.blockExists(x1, y1, z1)) { + worldObj.notifyBlockOfNeighborChange(x1, y1, z1, thisBlock); + + // update if it was / is strong powered. + if (((((mStrongRedstone | oStrongRedstone) >>> dir.ordinal()) & 1) != 0) + && getBlock(x1, y1, z1).isNormalCube()) { + final int skipUpdateSide = dir.getOpposite() + .ordinal(); // Don't update this block. Still updates + // diagonal blocks twice if conditions + // meet. + + for (final ForgeDirection dir2 : ForgeDirection.VALID_DIRECTIONS) { + final int x2 = x1 + dir2.offsetX, y2 = y1 + dir2.offsetY, z2 = z1 + dir2.offsetZ; + if (dir2.ordinal() != skipUpdateSide && worldObj.blockExists(x2, y2, z2)) + worldObj.notifyBlockOfNeighborChange(x2, y2, z2, thisBlock); + } + } + } + } + } + + @Override + public final void sendBlockEvent(byte aID, byte aValue) { + NW.sendPacketToAllPlayersInRange( + worldObj, + new GT_Packet_Block_Event(xCoord, (short) yCoord, zCoord, aID, aValue), + xCoord, + zCoord); + } + + protected boolean crossedChunkBorder(int aX, int aZ) { + return aX >> 4 != xCoord >> 4 || aZ >> 4 != zCoord >> 4; + } + + public final boolean crossedChunkBorder(ChunkCoordinates aCoords) { + return aCoords.posX >> 4 != xCoord >> 4 || aCoords.posZ >> 4 != zCoord >> 4; + } + + public final void setOnFire() { + GT_Utility.setCoordsOnFire(worldObj, xCoord, yCoord, zCoord, false); + } + + public final void setToFire() { + worldObj.setBlock(xCoord, yCoord, zCoord, Blocks.fire); + } + + @Override + public void markDirty() { + // Avoid sending neighbor updates, just mark the chunk as dirty to make sure it gets saved + final Chunk chunk = worldObj.getChunkFromBlockCoords(xCoord, zCoord); + if (chunk != null) { + chunk.setChunkModified(); + } + } + + /** + * Gets items to be displayed for HoloInventory mod. + * + * @return null if default implementation should be used, i.e. {@link IInventory#getStackInSlot}. + * Otherwise, a list of items to be displayed. Null element may be contained. + */ + @Nullable + public List<ItemStack> getItemsForHoloGlasses() { + return null; + } + + @Deprecated + public String trans(String aKey, String aEnglish) { + return GT_Utility.trans(aKey, aEnglish); + } + + protected Supplier<Boolean> getValidator() { + return () -> !this.isDead(); + } + + public boolean useModularUI() { + return false; + } + + /* + * IC2 Energy Compat + */ + protected TileIC2EnergySink ic2EnergySink = null; + protected boolean joinedIc2Enet = false; + + protected void createIc2Sink() { + if (ic2EnergySink == null && isServerSide() && shouldJoinIc2Enet()) { + ic2EnergySink = new TileIC2EnergySink((IGregTechTileEntity) this); + } + } + + @Override + public void doEnetUpdate() { + leaveEnet(); + joinEnet(); + } + + protected void joinEnet() { + if (joinedIc2Enet || !shouldJoinIc2Enet()) return; + + if (ic2EnergySink == null) createIc2Sink(); + + if (ic2EnergySink != null) { + MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(ic2EnergySink)); + joinedIc2Enet = true; + } + } + + protected void leaveEnet() { + if (joinedIc2Enet && ic2EnergySink != null && isServerSide()) { + joinedIc2Enet = false; + MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(ic2EnergySink)); + } + } + + // === GUI stuff === + + public ItemStackHandler getInventoryHandler() { + return null; + } + + protected GT_TooltipDataCache mTooltipCache = new GT_TooltipDataCache(); + + // Tooltip localization keys + public static final String BATTERY_SLOT_TOOLTIP = "GT5U.machines.battery_slot.tooltip", + BATTERY_SLOT_TOOLTIP_ALT = "GT5U.machines.battery_slot.tooltip.alternative", + UNUSED_SLOT_TOOLTIP = "GT5U.machines.unused_slot.tooltip", + SPECIAL_SLOT_TOOLTIP = "GT5U.machines.special_slot.tooltip", + STALLED_STUTTERING_TOOLTIP = "GT5U.machines.stalled_stuttering.tooltip", + STALLED_VENT_TOOLTIP = "GT5U.machines.stalled_vent.tooltip", + FLUID_TRANSFER_TOOLTIP = "GT5U.machines.fluid_transfer.tooltip", + ITEM_TRANSFER_TOOLTIP = "GT5U.machines.item_transfer.tooltip", POWER_SOURCE_KEY = "GT5U.machines.powersource.", + BUTTON_FORBIDDEN_TOOLTIP = "GT5U.gui.button.forbidden", + NEI_TRANSFER_STEAM_TOOLTIP = "GT5U.machines.nei_transfer.steam.tooltip", + NEI_TRANSFER_VOLTAGE_TOOLTIP = "GT5U.machines.nei_transfer.voltage.tooltip"; + + public static final int TOOLTIP_DELAY = 5; + + /** + * Override this to add {@link com.gtnewhorizons.modularui.api.widget.Widget}s for your UI. + */ + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) {} + + public void bindPlayerInventoryUI(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.bindPlayerInventory(buildContext.getPlayer(), 7, getGUITextureSet().getItemSlot()); + } + + public String getLocalName() { + return "Unknown"; + } + + protected void addTitleToUI(ModularWindow.Builder builder) { + addTitleToUI(builder, getLocalName()); + } + + protected void addTitleToUI(ModularWindow.Builder builder, String title) { + if (GT_Mod.gregtechproxy.mTitleTabStyle == 2) { + addTitleItemIconStyle(builder, title); + } else { + addTitleTextStyle(builder, title); + } + } + + protected void addTitleTextStyle(ModularWindow.Builder builder, String title) { + final int TAB_PADDING = 3; + final int TITLE_PADDING = 2; + int titleWidth = 0, titleHeight = 0; + if (NetworkUtils.isClient()) { + final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + final List<String> titleLines = fontRenderer + .listFormattedStringToWidth(title, getGUIWidth() - (TAB_PADDING + TITLE_PADDING) * 2); + titleWidth = titleLines.size() > 1 ? getGUIWidth() - (TAB_PADDING + TITLE_PADDING) * 2 + : fontRenderer.getStringWidth(title); + // noinspection PointlessArithmeticExpression + titleHeight = titleLines.size() * fontRenderer.FONT_HEIGHT + (titleLines.size() - 1) * 1; + } + + final DrawableWidget tab = new DrawableWidget(); + final TextWidget text = new TextWidget(title).setDefaultColor(getTitleColor()) + .setTextAlignment(Alignment.CenterLeft) + .setMaxWidth(titleWidth); + if (GT_Mod.gregtechproxy.mTitleTabStyle == 1) { + tab.setDrawable(getGUITextureSet().getTitleTabAngular()) + .setPos(0, -(titleHeight + TAB_PADDING) + 1) + .setSize(getGUIWidth(), titleHeight + TAB_PADDING * 2); + text.setPos(TAB_PADDING + TITLE_PADDING, -titleHeight + TAB_PADDING); + } else { + tab.setDrawable(getGUITextureSet().getTitleTabDark()) + .setPos(0, -(titleHeight + TAB_PADDING * 2) + 1) + .setSize(titleWidth + (TAB_PADDING + TITLE_PADDING) * 2, titleHeight + TAB_PADDING * 2 - 1); + text.setPos(TAB_PADDING + TITLE_PADDING, -titleHeight); + } + builder.widget(tab) + .widget(text); + } + + protected void addTitleItemIconStyle(ModularWindow.Builder builder, String title) { + builder.widget( + new MultiChildWidget().addChild( + new DrawableWidget().setDrawable(getGUITextureSet().getTitleTabNormal()) + .setPos(0, 0) + .setSize(24, 24)) + .addChild( + new ItemDrawable(getStackForm(1)).asWidget() + .setPos(4, 4)) + .addTooltip(title) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(0, -24 + 3)); + } + + @Override + public GUITextureSet getGUITextureSet() { + return GUITextureSet.DEFAULT; + } + + protected int getTitleColor() { + return COLOR_TITLE.get(); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(152, 63)); + } + + protected int getGUIWidth() { + return 176; + } + + protected int getGUIHeight() { + return 166; + } + + protected boolean doesBindPlayerInventory() { + return true; + } + + @Override + public void add1by1Slot(ModularWindow.Builder builder, IDrawable... background) { + final ItemStackHandler inventoryHandler = getInventoryHandler(); + if (inventoryHandler == null) return; + + if (background.length == 0) { + background = new IDrawable[] { getGUITextureSet().getItemSlot() }; + } + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 1) + .startFromSlot(0) + .endAtSlot(0) + .background(background) + .build() + .setPos(79, 34)); + } + + @Override + public void add2by2Slots(ModularWindow.Builder builder, IDrawable... background) { + final ItemStackHandler inventoryHandler = getInventoryHandler(); + if (inventoryHandler == null) return; + + if (background.length == 0) { + background = new IDrawable[] { getGUITextureSet().getItemSlot() }; + } + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 2) + .startFromSlot(0) + .endAtSlot(3) + .background(background) + .build() + .setPos(70, 25)); + } + + @Override + public void add3by3Slots(ModularWindow.Builder builder, IDrawable... background) { + final ItemStackHandler inventoryHandler = getInventoryHandler(); + if (inventoryHandler == null) return; + + if (background.length == 0) { + background = new IDrawable[] { getGUITextureSet().getItemSlot() }; + } + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 3) + .startFromSlot(0) + .endAtSlot(8) + .background(background) + .build() + .setPos(61, 16)); + } + + @Override + public void add4by4Slots(ModularWindow.Builder builder, IDrawable... background) { + final ItemStackHandler inventoryHandler = getInventoryHandler(); + if (inventoryHandler == null) return; + + if (background.length == 0) { + background = new IDrawable[] { getGUITextureSet().getItemSlot() }; + } + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 4) + .startFromSlot(0) + .endAtSlot(15) + .background(background) + .build() + .setPos(52, 7)); + } + + public void addCoverTabs(ModularWindow.Builder builder, UIBuildContext buildContext) { + /* Do nothing */ + } + + public IConfigurationCircuitSupport getConfigurationCircuitSupport() { + if (!(this instanceof IConfigurationCircuitSupport)) return null; + return (IConfigurationCircuitSupport) this; + } + + protected void addConfigurationCircuitSlot(ModularWindow.Builder builder) { + final ItemStackHandler inventoryHandler = getInventoryHandler(); + if (inventoryHandler == null) return; + + if (!(this instanceof IInventory inv)) return; + + final IConfigurationCircuitSupport ccs = getConfigurationCircuitSupport(); + if (ccs == null) return; + + final AtomicBoolean dialogOpened = new AtomicBoolean(false); + builder.widget(new SlotWidget(new BaseSlot(inventoryHandler, ccs.getCircuitSlot(), true)) { + + @Override + protected void phantomClick(ClickData clickData, ItemStack cursorStack) { + final ItemStack newCircuit; + if (clickData.shift) { + if (clickData.mouseButton == 0) { + if (NetworkUtils.isClient() && !dialogOpened.get()) { + openSelectCircuitDialog(getContext(), dialogOpened); + } + return; + } else { + newCircuit = null; + } + } else { + final List<ItemStack> tCircuits = ccs.getConfigurationCircuits(); + final int index = GT_Utility.findMatchingStackInList(tCircuits, cursorStack); + if (index < 0) { + int curIndex = GT_Utility + .findMatchingStackInList(tCircuits, inv.getStackInSlot(ccs.getCircuitSlot())) + 1; + if (clickData.mouseButton == 0) { + curIndex += 1; + } else { + curIndex -= 1; + } + curIndex = Math.floorMod(curIndex, tCircuits.size() + 1) - 1; + newCircuit = curIndex < 0 ? null : tCircuits.get(curIndex); + } else { + // set to whatever it is + newCircuit = tCircuits.get(index); + } + } + inv.setInventorySlotContents(ccs.getCircuitSlot(), newCircuit); + } + + @Override + protected void phantomScroll(int direction) { + phantomClick(new ClickData(direction > 0 ? 1 : 0, false, false, false)); + } + + @Override + public List<String> getExtraTooltip() { + return Arrays.asList( + EnumChatFormatting.DARK_GRAY + EnumChatFormatting.getTextWithoutFormattingCodes( + StatCollector.translateToLocal("GT5U.machines.select_circuit.tooltip.1")), + EnumChatFormatting.DARK_GRAY + EnumChatFormatting.getTextWithoutFormattingCodes( + StatCollector.translateToLocal("GT5U.machines.select_circuit.tooltip.2")), + EnumChatFormatting.DARK_GRAY + EnumChatFormatting.getTextWithoutFormattingCodes( + StatCollector.translateToLocal("GT5U.machines.select_circuit.tooltip.3"))); + } + }.setOverwriteItemStackTooltip(list -> { + list.removeIf( + line -> line.contains(StatCollector.translateToLocal("gt.integrated_circuit.tooltip.0")) + || line.contains(StatCollector.translateToLocal("gt.integrated_circuit.tooltip.1"))); + return list; + }) + .disableShiftInsert() + .setHandlePhantomActionClient(true) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_INT_CIRCUIT) + .setGTTooltip(() -> mTooltipCache.getData("GT5U.machines.select_circuit.tooltip")) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(ccs.getCircuitSlotX() - 1, ccs.getCircuitSlotY() - 1)); + } + + protected void openSelectCircuitDialog(ModularUIContext uiContext, AtomicBoolean dialogOpened) { + final IConfigurationCircuitSupport ccs = getConfigurationCircuitSupport(); + if (ccs == null) return; + + if (!(this instanceof IInventory inv)) return; + + final List<ItemStack> circuits = ccs.getConfigurationCircuits(); + uiContext.openClientWindow( + player -> new SelectItemUIFactory( + StatCollector.translateToLocal("GT5U.machines.select_circuit"), + getStackForm(0), + this::onCircuitSelected, + circuits, + GT_Utility.findMatchingStackInList(circuits, inv.getStackInSlot(ccs.getCircuitSlot()))) + .setAnotherWindow(true, dialogOpened) + .setGuiTint(getGUIColorization()) + .setCurrentGetter(() -> inv.getStackInSlot(ccs.getCircuitSlot())) + .createWindow(new UIBuildContext(player))); + } + + protected void onCircuitSelected(ItemStack selected) { + final IConfigurationCircuitSupport ccs = getConfigurationCircuitSupport(); + if (ccs == null) return; + + if (!(this instanceof IInventory inv)) return; + + GT_Values.NW.sendToServer(new GT_Packet_SetConfigurationCircuit(this, selected)); + // we will not do any validation on client side + // it doesn't get to actually decide what inventory contains anyway + inv.setInventorySlotContents(ccs.getCircuitSlot(), selected); + } + + protected int getTextColorOrDefault(String textType, int defaultColor) { + return defaultColor; + } + + protected Supplier<Integer> COLOR_TITLE = () -> getTextColorOrDefault("title", 0x404040); + protected Supplier<Integer> COLOR_TITLE_WHITE = () -> getTextColorOrDefault("title_white", 0xfafaff); + protected Supplier<Integer> COLOR_TEXT_WHITE = () -> getTextColorOrDefault("text_white", 0xfafaff); + protected Supplier<Integer> COLOR_TEXT_GRAY = () -> getTextColorOrDefault("text_gray", 0x404040); + protected Supplier<Integer> COLOR_TEXT_RED = () -> getTextColorOrDefault("text_red", 0xff0000); + + public int getGUIColorization() { + return GT_Util.getRGBaInt(Dyes.dyeWhite.getRGBA()); + } + + public ItemStack getStackForm(long aAmount) { + return null; + } +} |