com.bluepowermod.part.tube.PneumaticTube.java Source code

Java tutorial

Introduction

Here is the source code for com.bluepowermod.part.tube.PneumaticTube.java

Source

/*
 * This file is part of Blue Power. Blue Power is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Blue Power is
 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along
 * with Blue Power. If not, see <http://www.gnu.org/licenses/>
 */
package com.bluepowermod.part.tube;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.I18n;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemDye;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.common.util.ForgeDirection;

import org.lwjgl.opengl.GL11;

import uk.co.qmunity.lib.client.render.RenderHelper;
import uk.co.qmunity.lib.part.IPartThruHole;
import uk.co.qmunity.lib.part.IPartTicking;
import uk.co.qmunity.lib.part.MicroblockShape;
import uk.co.qmunity.lib.part.compat.OcclusionHelper;
import uk.co.qmunity.lib.raytrace.QMovingObjectPosition;
import uk.co.qmunity.lib.raytrace.RayTracer;
import uk.co.qmunity.lib.transform.Rotation;
import uk.co.qmunity.lib.vec.Vec3d;
import uk.co.qmunity.lib.vec.Vec3dCube;
import uk.co.qmunity.lib.vec.Vec3i;

import com.bluepowermod.BluePower;
import com.bluepowermod.api.misc.IScrewdriver;
import com.bluepowermod.api.misc.MinecraftColor;
import com.bluepowermod.api.tube.IPneumaticTube.TubeColor;
import com.bluepowermod.api.tube.ITubeConnection;
import com.bluepowermod.api.wire.redstone.IRedwire;
import com.bluepowermod.api.wire.redstone.RedwireType;
import com.bluepowermod.client.render.IconSupplier;
import com.bluepowermod.helper.IOHelper;
import com.bluepowermod.helper.PartCache;
import com.bluepowermod.helper.TileEntityCache;
import com.bluepowermod.init.BPCreativeTabs;
import com.bluepowermod.init.BPItems;
import com.bluepowermod.init.Config;
import com.bluepowermod.item.ItemDamageableColorableOverlay;
import com.bluepowermod.item.ItemPart;
import com.bluepowermod.part.BPPart;
import com.bluepowermod.part.PartManager;
import com.bluepowermod.part.wire.PartWireFreestanding;
import com.bluepowermod.part.wire.redstone.PartRedwireFace.PartRedwireFaceUninsulated;
import com.bluepowermod.part.wire.redstone.WireHelper;
import com.bluepowermod.redstone.RedstoneApi;
import com.bluepowermod.util.Color;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

/**
 *
 * @author MineMaarten
 */

public class PneumaticTube extends PartWireFreestanding implements IPartTicking, IPartThruHole {

    public final boolean[] connections = new boolean[6];
    public final boolean[] redstoneConnections = new boolean[6];
    /**
     * true when != 2 connections, when this is true the logic doesn't have to 'think' which way an item should go.
     */
    public boolean isCrossOver;
    protected final Vec3dCube sideBB = new Vec3dCube(AxisAlignedBB.getBoundingBox(0.25, 0, 0.25, 0.75, 0.25, 0.75));
    private TileEntityCache tileCache;
    private PartCache<PneumaticTube> partCache;
    protected final TubeColor[] color = { TubeColor.NONE, TubeColor.NONE, TubeColor.NONE, TubeColor.NONE,
            TubeColor.NONE, TubeColor.NONE };
    private final TubeLogic logic = new TubeLogic(this);
    public boolean initialized; // workaround to the connections not properly initialized, but being tried to be used.
    private int tick;

    private RedwireType redwireType = null;

    @Override
    public String getType() {

        return "pneumaticTube";
    }

    @Override
    public String getUnlocalizedName() {

        return "pneumaticTube";
    }

    @Override
    public void addCollisionBoxesToList(List<Vec3dCube> boxes, Entity entity) {

        boxes.addAll(getSelectionBoxes());
    }

    /**
     * Gets all the selection boxes for this block
     *
     * @return A list with the selection boxes
     */
    @Override
    public List<Vec3dCube> getSelectionBoxes() {

        return getTubeBoxes();
    }

    protected List<Vec3dCube> getTubeBoxes() {

        List<Vec3dCube> aabbs = getOcclusionBoxes();
        for (int i = 0; i < 6; i++) {
            ForgeDirection d = ForgeDirection.getOrientation(i);
            if (connections[i] || redstoneConnections[i]
                    || RedstoneConductorTube.getDevice(this).getDeviceOnSide(d) != null) {
                Vec3dCube c = sideBB.clone().rotate(d, Vec3d.center);
                aabbs.add(c);
            }
        }
        return aabbs;
    }

    /**
     * Gets all the occlusion boxes for this block
     *
     * @return A list with the occlusion boxes
     */
    @Override
    public List<Vec3dCube> getOcclusionBoxes() {

        List<Vec3dCube> aabbs = new ArrayList<Vec3dCube>();
        aabbs.add(new Vec3dCube(0.25, 0.25, 0.25, 0.75, 0.75, 0.75));
        return aabbs;
    }

    @Override
    public void update() {

        if (initialized)
            logic.update();
        if (tick++ == 3) {
            clearCache();
            updateConnections();
        } else if (tick == 40) {
            sendUpdatePacket();
        }
        if (getWorld().isRemote && tick % 40 == 0)
            clearCache();// reset on the client, as it doesn't get update on neighbor block updates (as the
        // method isn't called on the client)
    }

    /**
     * Event called whenever a nearby block updates
     */
    @Override
    public void onUpdate() {

        if (getParent() != null && getWorld() != null) {
            // Redstone update
            RedstoneConductorTube device = RedstoneConductorTube.getDevice(this);
            device.getRedstoneConnectionCache().recalculateConnections();

            ForgeDirection d = ForgeDirection.UNKNOWN;
            for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
                if (device.getDeviceOnSide(dir) != null)
                    d = dir;

            RedstoneApi.getInstance().getRedstonePropagator(device, d).propagate();

            sendUpdatePacket();

            // Cache and connection refresh
            clearCache();
            updateConnections();
        }
    }

    public TileEntity getTileCache(ForgeDirection d) {

        if (tileCache == null) {
            tileCache = new TileEntityCache(getWorld(), getX(), getY(), getZ());
        }
        return tileCache.getValue(d);
    }

    public PneumaticTube getPartCache(ForgeDirection d) {

        if (partCache == null) {
            partCache = new PartCache<PneumaticTube>(getWorld(), getX(), getY(), getZ(), PneumaticTube.class);
        }
        return partCache.getValue(d);
    }

    public void clearCache() {

        tileCache = null;
        partCache = null;
    }

    public TubeLogic getLogic() {

        return logic;
    }

    protected boolean canConnectToInventories() {

        return true;
    }

    private void updateConnections() {

        if (getWorld() != null && !getWorld().isRemote) {
            int connectionCount = 0;
            boolean clearedCache = false;
            clearCache();
            for (int i = 0; i < 6; i++) {
                boolean oldState = connections[i];
                ForgeDirection d = ForgeDirection.getOrientation(i);
                TileEntity neighbor = getTileCache(d);
                connections[i] = IOHelper.canInterfaceWith(neighbor, d.getOpposite(), this,
                        canConnectToInventories());

                if (!connections[i])
                    connections[i] = neighbor instanceof ITubeConnection
                            && ((ITubeConnection) neighbor).isConnectedTo(d.getOpposite());
                if (connections[i]) {
                    connections[i] = isConnected(d, null);
                }
                if (connections[i])
                    connectionCount++;
                if (!clearedCache && oldState != connections[i]) {
                    if (Config.enableTubeCaching)
                        getLogic().clearNodeCaches();
                    clearedCache = true;
                }
            }
            isCrossOver = connectionCount != 2;
            sendUpdatePacket();
        }
        initialized = true;
    }

    public boolean isConnected(ForgeDirection dir, PneumaticTube otherTube) {

        if (otherTube != null) {
            if (!(this instanceof Accelerator) && this instanceof MagTube != otherTube instanceof MagTube
                    && !(otherTube instanceof Accelerator))
                return false;
            TubeColor otherTubeColor = otherTube.getColor(dir.getOpposite());
            if (otherTubeColor != TubeColor.NONE && getColor(dir) != TubeColor.NONE
                    && getColor(dir) != otherTubeColor)
                return false;
        }
        return getWorld() == null
                || !OcclusionHelper.microblockOcclusionTest(getParent(), MicroblockShape.FACE_HOLLOW, 8, dir);
    }

    @Override
    public void writeToNBT(NBTTagCompound tag) {

        super.writeToNBT(tag);

        for (int i = 0; i < 6; i++) {
            tag.setBoolean("connections" + i, connections[i]);
            tag.setBoolean("redstoneConnections" + i, RedstoneConductorTube.getDevice(this)
                    .getDeviceOnSide(ForgeDirection.getOrientation(i)) != null);
        }
        for (int i = 0; i < color.length; i++)
            tag.setByte("tubeColor" + i, (byte) color[i].ordinal());

        if (redwireType != null)
            tag.setInteger("wireType", redwireType.ordinal());
        tag.setByte("power", RedstoneConductorTube.getDevice(this).getPower());

        NBTTagCompound logicTag = new NBTTagCompound();
        logic.writeToNBT(logicTag);
        tag.setTag("logic", logicTag);
    }

    @Override
    public void readFromNBT(NBTTagCompound tag) {

        super.readFromNBT(tag);

        int connectionCount = 0;
        for (int i = 0; i < 6; i++) {
            connections[i] = tag.getBoolean("connections" + i);
            redstoneConnections[i] = tag.getBoolean("redstoneConnections" + i);
            if (connections[i])
                connectionCount++;
        }
        isCrossOver = connectionCount != 2;
        for (int i = 0; i < color.length; i++)
            color[i] = TubeColor.values()[tag.getByte("tubeColor" + i)];

        if (tag.hasKey("wireType"))
            redwireType = RedwireType.values()[tag.getInteger("wireType")];
        else
            redwireType = null;
        RedstoneConductorTube.getDevice(this).setRedstonePower(null, tag.getByte("power"));

        if (getParent() != null && getWorld() != null)
            getWorld().markBlockRangeForRenderUpdate(getX(), getY(), getZ(), getX(), getY(), getZ());

        NBTTagCompound logicTag = tag.getCompoundTag("logic");
        logic.readFromNBT(logicTag);
    }

    @Override
    public void writeUpdateData(DataOutput buffer) throws IOException {

        super.writeUpdateData(buffer);

        // Connections
        for (int i = 0; i < 6; i++)
            buffer.writeBoolean(connections[i]);
        for (int i = 0; i < 6; i++)
            buffer.writeBoolean(RedstoneConductorTube.getDevice(this)
                    .getDeviceOnSide(ForgeDirection.getOrientation(i)) != null);

        // Colors
        for (int i = 0; i < color.length; i++)
            buffer.writeInt(color[i].ordinal());

        // Redwire
        if (redwireType != null) {
            buffer.writeBoolean(true);
            buffer.writeInt(redwireType.ordinal());
            buffer.writeByte(RedstoneConductorTube.getDevice(this).getPower());
        } else {
            buffer.writeBoolean(false);
        }

        // Logic
        logic.writeData(buffer);
    }

    @Override
    public void readUpdateData(DataInput buffer) throws IOException {

        super.readUpdateData(buffer);

        // Connections
        for (int i = 0; i < 6; i++)
            connections[i] = buffer.readBoolean();
        for (int i = 0; i < 6; i++)
            redstoneConnections[i] = buffer.readBoolean();

        int connectionCount = 0;
        for (int i = 0; i < 6; i++)
            if (connections[i] || redstoneConnections[i])
                connectionCount++;
        isCrossOver = connectionCount != 2;

        // Colors
        for (int i = 0; i < color.length; i++)
            color[i] = TubeColor.values()[buffer.readInt()];

        // Redwire
        if (buffer.readBoolean()) {
            redwireType = RedwireType.values()[buffer.readInt()];
            RedstoneConductorTube.getDevice(this).setRedstonePower(null, buffer.readByte());
        } else {
            redwireType = null;
        }

        // Logic
        logic.readData(buffer);

        // Render update
        if (getParent() != null && getWorld() != null)
            getWorld().markBlockRangeForRenderUpdate(getX(), getY(), getZ(), getX(), getY(), getZ());
    }

    /**
     * Event called when the part is activated (right clicked)
     *
     * @param player
     *            Player that right clicked the part
     * @param item
     *            Item that was used to click it
     * @return Whether or not an action occurred
     */
    @Override
    public boolean onActivated(EntityPlayer player, QMovingObjectPosition mop, ItemStack item) {

        if (getWorld() == null)
            return false;

        if (item != null) {
            TubeColor newColor = null;
            if (item.getItem() == BPItems.paint_brush
                    && ((ItemDamageableColorableOverlay) BPItems.paint_brush).tryUseItem(item)) {
                newColor = TubeColor.values()[item.getItemDamage()];
            } else if (item.getItem() == Items.water_bucket
                    || (item.getItem() == BPItems.paint_brush && item.getItemDamage() == 16)) {
                newColor = TubeColor.NONE;
            }
            if (newColor != null) {
                if (!getWorld().isRemote) {
                    List<Vec3dCube> boxes = getTubeBoxes();
                    Vec3dCube box = mop.getCube();
                    int face = -1;
                    if (box.equals(boxes.get(0))) {
                        face = mop.sideHit;
                    } else {
                        face = getSideFromAABBIndex(boxes.indexOf(box));
                    }
                    color[face] = newColor;
                    updateConnections();
                    getLogic().clearNodeCaches();
                    notifyUpdate();
                }
                return true;
            }

            if (item.getItem() instanceof ItemPart) {
                BPPart part = PartManager.getExample(item);
                if (redwireType == null && part instanceof PartRedwireFaceUninsulated) {
                    if (!getWorld().isRemote) {
                        redwireType = ((IRedwire) part).getRedwireType();
                        if (!player.capabilities.isCreativeMode)
                            item.stackSize--;

                        // Redstone update
                        RedstoneConductorTube device = RedstoneConductorTube.getDevice(this);
                        device.getRedstoneConnectionCache().recalculateConnections();
                        RedstoneApi.getInstance().getRedstonePropagator(device, ForgeDirection.DOWN).propagate();

                        updateConnections();
                        getLogic().clearNodeCaches();
                        notifyUpdate();
                        sendUpdatePacket();
                    }
                    return true;
                }
            }
            // Removing redwire
            if (redwireType != null && item.getItem() instanceof IScrewdriver && player.isSneaking()) {
                if (!getWorld().isRemote) {
                    IOHelper.spawnItemInWorld(getWorld(),
                            PartManager.getPartInfo("wire." + redwireType.getName()).getStack(), getX() + 0.5,
                            getY() + 0.5, getZ() + 0.5);
                    redwireType = null;

                    // Redstone update
                    RedstoneConductorTube device = RedstoneConductorTube.getDevice(this);
                    device.getRedstoneConnectionCache().recalculateConnections();
                    RedstoneApi.getInstance().getRedstonePropagator(device, ForgeDirection.DOWN).propagate();

                    ((IScrewdriver) item.getItem()).damage(item, 1, player, false);

                    updateConnections();
                    getLogic().clearNodeCaches();
                    notifyUpdate();
                    sendUpdatePacket();
                }
                return true;
            }
        }
        return false;
    }

    @Override
    public List<ItemStack> getDrops() {

        List<ItemStack> drops = super.getDrops();
        for (TubeStack stack : logic.tubeStacks) {
            drops.add(stack.stack);
        }
        return drops;
    }

    /**
     * How 'dense' the tube is to the pathfinding algorithm. Is altered in the RestrictionTube
     *
     * @return
     */
    public int getWeight() {

        return 1;
    }

    public TubeColor getColor(ForgeDirection dir) {

        return color[dir.ordinal()];
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void renderDynamic(Vec3d translation, double delta, int pass) {

        if (pass == 0 && !(this instanceof PneumaticTubeOpaque)) {
            logic.renderDynamic(translation, (float) delta);
            if (!shouldRenderNode())
                renderSide();
        }
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void renderItem(ItemRenderType type, ItemStack item, Object... data) {

        GL11.glPushMatrix();
        GL11.glTranslated(0, -0.125D, 0);

        Tessellator t = Tessellator.instance;
        Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture);
        t.startDrawingQuads();

        connections[ForgeDirection.DOWN.ordinal()] = true;
        connections[ForgeDirection.UP.ordinal()] = true;

        RenderHelper renderer = RenderHelper.instance;
        renderer.fullReset();
        RenderBlocks rb = new RenderBlocks();

        renderStatic(new Vec3i(0, 0, 0), renderer, rb, 0);

        t.draw();
        renderSide();
        Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationItemsTexture);

        GL11.glPopMatrix();
    }

    protected boolean shouldRenderNode() {

        boolean shouldRenderNode = false;
        int connectionCount = 0;
        for (int i = 0; i < 6; i += 2) {
            if (connections[i] != connections[i + 1] || redstoneConnections[i] != redstoneConnections[i + 1]) {
                shouldRenderNode = true;
                break;
            }
            if (connections[i] || redstoneConnections[i])
                connectionCount++;
            if (connections[i + 1] || redstoneConnections[i + 1])
                connectionCount++;
        }
        return shouldRenderNode || connectionCount == 0 || connectionCount > 2;
    }

    /**
     * This render method gets called whenever there's a block update in the chunk. You should use this to remove load from the renderer if a part of
     * the rendering code doesn't need to get called too often or just doesn't change at all. To call a render update to re-render this just call
     * {@link BPPart#markPartForRenderUpdate()}
     *
     * @param loc
     *            Distance from the player's position
     * @param pass
     *            Render pass (0 or 1)
     * @return Whether or not it rendered something
     */
    @Override
    @SideOnly(Side.CLIENT)
    public boolean renderStatic(Vec3i loc, RenderHelper renderer, RenderBlocks renderBlocks, int pass) {

        if (pass == 0) {
            boolean renderFully = false;
            int count = 0;

            for (int i = 0; i < 6; i++) {
                if (shouldRenderConnection(ForgeDirection.getOrientation(i)))
                    count++;
                if (i % 2 == 0 && connections[i] != connections[i + 1])
                    renderFully = true;
            }

            renderFully |= count > 2 || count == 0;
            renderFully |= this instanceof RestrictionTube;
            renderFully |= getParent() == null || getWorld() == null;

            if (this instanceof RestrictionTube) {
                IIcon icon = IconSupplier.restrictionTubeSide;
                renderer.renderBox(new Vec3dCube(0.25, 0.25, 0.25, 0.75, 0.75, 0.75), icon);
            }
            double wireSize = getSize() / 16D;
            double frameSeparation = 4 / 16D - (wireSize - 2 / 16D);
            double frameThickness = 1 / 16D;

            if (renderFully) {

                boolean down = shouldRenderConnection(ForgeDirection.DOWN);
                boolean up = shouldRenderConnection(ForgeDirection.UP);
                boolean north = shouldRenderConnection(ForgeDirection.NORTH);
                boolean south = shouldRenderConnection(ForgeDirection.SOUTH);
                boolean west = shouldRenderConnection(ForgeDirection.WEST);
                boolean east = shouldRenderConnection(ForgeDirection.EAST);

                renderer.setColor(getColorMultiplier());

                renderFrame(renderer, wireSize, frameSeparation, frameThickness, true, true, true, true, true, true,
                        down, up, west, east, north, south, true, getFrameIcon(), getFrameColorMultiplier());

                renderer.setColor(0xFFFFFF);
            } else {
                super.renderStatic(loc, renderer, renderBlocks, 0);
            }

            // Tube coloring
            {
                Vec3dCube side = new Vec3dCube(0.25 + 5 / 128D, 0, 0.25 - 1 / 128D, 0.25 + 9 / 128D, 0.25,
                        0.25 + 2 / 128D);
                Vec3dCube side2 = new Vec3dCube(0.25 - 1 / 128D, 0, 0.25 + 5 / 128D, 0.25 + 2 / 128D, 0.25,
                        0.25 + 9 / 128D);
                Vec3dCube side3 = new Vec3dCube(0.25 - 1 / 128D, 0.25 - 1 / 128D, 0.25 + 5 / 128D, 0.25 + 2 / 128D,
                        0.25 + 2 / 128D, 0.25 + 59 / 128D);
                Vec3dCube side4 = new Vec3dCube(0.25 + 5 / 128D, 0.25 - 1 / 128D, 0.25 + 5 / 128D, 0.25 + 9 / 128D,
                        0.25 + 2 / 128D, 0.25 + 56 / 128D);
                Vec3dCube side5 = new Vec3dCube(0.25 + 5 / 128D, 0.25 - 1 / 128D, 0.25 - 1 / 128D, 0.25 + 9 / 128D,
                        0.25 + 2 / 128D, 0.25 + 65 / 128D);
                for (ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
                    TubeColor c = color[d.ordinal()];
                    if (c != TubeColor.NONE) {
                        try {
                            renderer.setColor(MinecraftColor.values()[15 - c.ordinal()].getHex());
                            if (connections[d.ordinal()]) {
                                for (int i = 0; i < 4; i++) {
                                    renderer.renderBox(
                                            side.clone().rotate(0, i * 90, 0, Vec3d.center).rotate(d, Vec3d.center),
                                            IconSupplier.pneumaticTubeColoring);
                                    renderer.renderBox(side2.clone().rotate(0, i * 90, 0, Vec3d.center).rotate(d,
                                            Vec3d.center), IconSupplier.pneumaticTubeColoring);
                                    if (renderFully)
                                        renderer.renderBox(side3.clone().rotate(0, i * 90, 0, Vec3d.center)
                                                .rotate(d, Vec3d.center), IconSupplier.pneumaticTubeColoring);
                                }
                            } else if (renderFully) {
                                for (int i = 0; i < 4; i++)
                                    renderer.renderBox(side4.clone().rotate(0, i * 90, 0, Vec3d.center).rotate(d,
                                            Vec3d.center), IconSupplier.pneumaticTubeColoring);
                            } else {
                                for (int i = 1; i < 4; i += 2)
                                    renderer.renderBox(side5.clone().rotate(0, (i + ((shouldRenderConnection(
                                            ForgeDirection.NORTH)
                                            || (shouldRenderConnection(ForgeDirection.UP)
                                                    && (d == ForgeDirection.NORTH || d == ForgeDirection.SOUTH)))
                                                            ? 1
                                                            : 0))
                                            * 90, 0, Vec3d.center).rotate(d, Vec3d.center),
                                            IconSupplier.pneumaticTubeColoring);
                            }
                            renderer.setColor(0xFFFFFF);
                        } catch (Exception ex) {
                            System.out.println("Err on side " + d + ". Color: " + c);
                        }
                    }
                }
            }

            if (redwireType != null) {
                frameThickness /= 1.5;
                frameSeparation -= 1 / 32D;

                renderFrame(renderer, wireSize, frameSeparation, frameThickness,
                        renderFully || shouldRenderConnection(ForgeDirection.DOWN),
                        renderFully || shouldRenderConnection(ForgeDirection.UP),
                        renderFully || shouldRenderConnection(ForgeDirection.WEST),
                        renderFully || shouldRenderConnection(ForgeDirection.EAST),
                        renderFully || shouldRenderConnection(ForgeDirection.NORTH),
                        renderFully || shouldRenderConnection(ForgeDirection.SOUTH),
                        redstoneConnections[ForgeDirection.DOWN.ordinal()],
                        redstoneConnections[ForgeDirection.UP.ordinal()],
                        redstoneConnections[ForgeDirection.WEST.ordinal()],
                        redstoneConnections[ForgeDirection.EAST.ordinal()],
                        redstoneConnections[ForgeDirection.NORTH.ordinal()],
                        redstoneConnections[ForgeDirection.SOUTH.ordinal()],
                        getParent() != null && getWorld() != null, IconSupplier.wire,
                        WireHelper.getColorForPowerLevel(redwireType,
                                RedstoneConductorTube.getDevice(this).getPower()));

                Vec3dCube c = new Vec3dCube(0.5 - 1 / 56D, 0, 0.2, 0.5 + 1 / 56D, 1 / 32D, 0.8);

                renderer.setColor(WireHelper.getColorForPowerLevel(redwireType,
                        RedstoneConductorTube.getDevice(this).getPower()));
                for (ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
                    if (redstoneConnections[d.ordinal()] && !connections[d.ordinal()]) {
                        renderer.addTransformation(new Rotation(d));
                        for (int i = 0; i < 2; i++) {
                            renderer.addTransformation(new Rotation(0, 45 + 90 * i, 0));
                            renderer.renderBox(c.clone(), IconSupplier.wire);
                            renderer.removeTransformation();
                        }
                        renderer.removeTransformation();
                    }
                }
                renderer.setColor(0xFFFFFF);
            }
        }

        return true;
    }

    @Override
    public boolean shouldRenderOnPass(int pass) {

        return true;
    }

    protected void renderSide() {

    }

    /**
     * Hacky method to get the right side
     *
     * @return
     */
    private int getSideFromAABBIndex(int index) {

        int curIndex = 0;
        for (int side = 0; side < 6; side++) {
            if (connections[side]) {
                curIndex++;
                if (index == curIndex)
                    return side;
            }
        }
        return 0;
    }

    @SideOnly(Side.CLIENT)
    protected IIcon getSideIcon() {

        return IconSupplier.pneumaticTubeSide;
    }

    /**
     * Adds information to the waila tooltip
     *
     * @author amadornes
     *
     * @param info
     */
    @Override
    @SideOnly(Side.CLIENT)
    public void addWAILABody(List<String> info) {

        boolean addTooltip = false;
        for (TubeColor col : color) {
            if (col != TubeColor.NONE) {
                addTooltip = true;
                break;
            }
        }
        if (addTooltip) {
            info.add(Color.YELLOW + I18n.format("waila.pneumaticTube.color"));
            for (int i = 0; i < 6; i++) {
                if (color[i] != TubeColor.NONE) {
                    if (color[i] != TubeColor.NONE)
                        info.add(EnumChatFormatting.DARK_AQUA
                                + I18n.format(
                                        "rotation." + ForgeDirection.getOrientation(i).toString().toLowerCase())
                                + ": " + EnumChatFormatting.WHITE
                                + I18n.format("gui.widget.color." + ItemDye.field_150923_a[color[i].ordinal()]));
                }
            }
        }
    }

    @Override
    public CreativeTabs getCreativeTab() {

        return BPCreativeTabs.machines;
    }

    @Override
    public int getHollowSize(ForgeDirection side) {

        return 8;
    }

    @Override
    protected boolean shouldRenderConnection(ForgeDirection side) {

        return connections[side.ordinal()] || redstoneConnections[side.ordinal()];
    }

    @Override
    protected int getSize() {

        return 0;
    }

    @Override
    protected IIcon getWireIcon(ForgeDirection side) {

        return null;
    }

    @Override
    protected IIcon getFrameIcon() {

        return getSideIcon();
    }

    public RedwireType getRedwireType() {

        return redwireType;
    }

    @Override
    public QMovingObjectPosition rayTrace(Vec3d start, Vec3d end) {

        QMovingObjectPosition mop = super.rayTrace(start, end);
        if (mop == null)
            return null;

        EntityPlayer player = BluePower.proxy.getPlayer();
        if (redwireType != null && player != null && player.isSneaking()) {
            double wireSize = getSize() / 16D;
            double frameSeparation = 4 / 16D - (wireSize - 2 / 16D);
            double frameThickness = 1 / 16D;
            frameThickness /= 1.5;
            frameSeparation -= 1 / 32D;

            QMovingObjectPosition wire = RayTracer.instance().rayTraceCubes(getFrameBoxes(wireSize, frameSeparation,
                    frameThickness, shouldRenderConnection(ForgeDirection.DOWN),
                    shouldRenderConnection(ForgeDirection.UP), shouldRenderConnection(ForgeDirection.WEST),
                    shouldRenderConnection(ForgeDirection.EAST), shouldRenderConnection(ForgeDirection.NORTH),
                    shouldRenderConnection(ForgeDirection.SOUTH),
                    redstoneConnections[ForgeDirection.DOWN.ordinal()],
                    redstoneConnections[ForgeDirection.UP.ordinal()],
                    redstoneConnections[ForgeDirection.WEST.ordinal()],
                    redstoneConnections[ForgeDirection.EAST.ordinal()],
                    redstoneConnections[ForgeDirection.NORTH.ordinal()],
                    redstoneConnections[ForgeDirection.SOUTH.ordinal()], getParent() != null && getWorld() != null),
                    start, end, new Vec3i(this));
            QMovingObjectPosition frame = RayTracer.instance().rayTraceCubes(getFrameBoxes(), start, end,
                    new Vec3i(this));

            if (wire != null) {
                if (frame != null) {
                    if (wire.hitVec.distanceTo(start.toVec3()) < frame.hitVec.distanceTo(start.toVec3()))
                        mop.hitInfo = PartManager.getPartInfo("wire." + redwireType.getName()).getStack();
                } else {
                    mop.hitInfo = PartManager.getPartInfo("wire." + redwireType.getName()).getStack();
                }
            }
        }

        return mop;
    }

    @Override
    public ItemStack getPickedItem(QMovingObjectPosition mop) {

        Object o = mop.hitInfo;
        if (o != null && o instanceof ItemStack)
            return (ItemStack) o;

        return super.getPickedItem(mop);
    }
}