blusunrize.immersiveengineering.client.ClientEventHandler.java Source code

Java tutorial

Introduction

Here is the source code for blusunrize.immersiveengineering.client.ClientEventHandler.java

Source

/*
 * BluSunrize
 * Copyright (c) 2017
 *
 * This code is licensed under "Blu's License of Common Sense"
 * Details can be found in the license file in the root folder of this project
 */

package blusunrize.immersiveengineering.client;

import blusunrize.immersiveengineering.ImmersiveEngineering;
import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.api.crafting.BlastFurnaceRecipe;
import blusunrize.immersiveengineering.api.crafting.BlueprintCraftingRecipe;
import blusunrize.immersiveengineering.api.energy.immersiveflux.IFluxReceiver;
import blusunrize.immersiveengineering.api.energy.wires.IWireCoil;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler.Connection;
import blusunrize.immersiveengineering.api.energy.wires.WireType;
import blusunrize.immersiveengineering.api.shader.CapabilityShader;
import blusunrize.immersiveengineering.api.shader.CapabilityShader.ShaderWrapper;
import blusunrize.immersiveengineering.api.tool.IDrillHead;
import blusunrize.immersiveengineering.api.tool.ZoomHandler;
import blusunrize.immersiveengineering.api.tool.ZoomHandler.IZoomTool;
import blusunrize.immersiveengineering.client.fx.ParticleFractal;
import blusunrize.immersiveengineering.client.gui.GuiBlastFurnace;
import blusunrize.immersiveengineering.client.gui.GuiRevolver;
import blusunrize.immersiveengineering.client.gui.GuiToolbox;
import blusunrize.immersiveengineering.client.render.TileRenderAutoWorkbench;
import blusunrize.immersiveengineering.client.render.TileRenderAutoWorkbench.BlueprintLines;
import blusunrize.immersiveengineering.common.Config;
import blusunrize.immersiveengineering.common.Config.IEConfig;
import blusunrize.immersiveengineering.common.IEContent;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IAdvancedSelectionBounds;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IBlockOverlayText;
import blusunrize.immersiveengineering.common.blocks.metal.BlockTypes_MetalDevice1;
import blusunrize.immersiveengineering.common.blocks.metal.TileEntitySampleDrill;
import blusunrize.immersiveengineering.common.blocks.wooden.TileEntityTurntable;
import blusunrize.immersiveengineering.common.items.IEItemInterfaces.IBulletContainer;
import blusunrize.immersiveengineering.common.items.*;
import blusunrize.immersiveengineering.common.util.EnergyHelper;
import blusunrize.immersiveengineering.common.util.IEPotions;
import blusunrize.immersiveengineering.common.util.ItemNBTHelper;
import blusunrize.immersiveengineering.common.util.Utils;
import blusunrize.immersiveengineering.common.util.chickenbones.Matrix4;
import blusunrize.immersiveengineering.common.util.network.MessageChemthrowerSwitch;
import blusunrize.immersiveengineering.common.util.network.MessageMagnetEquip;
import blusunrize.immersiveengineering.common.util.network.MessageRequestBlockUpdate;
import blusunrize.immersiveengineering.common.util.sound.IEMuffledSound;
import blusunrize.immersiveengineering.common.util.sound.IEMuffledTickableSound;
import com.google.common.collect.ImmutableList;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ITickableSound;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelVillager;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.client.GuiIngameForge;
import net.minecraftforge.client.event.*;
import net.minecraftforge.client.event.sound.PlaySoundEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLContext;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

public class ClientEventHandler implements IResourceManagerReloadListener {
    private boolean shieldToggleButton = false;
    private int shieldToggleTimer = 0;
    private static final String[] BULLET_TOOLTIP = { "\u00A0\u00A0IE\u00A0", "\u00A0\u00A0AMMO\u00A0",
            "\u00A0\u00A0HERE\u00A0", "\u00A0\u00A0--\u00A0" };

    @Override
    public void onResourceManagerReload(IResourceManager resourceManager) {
        TextureMap texturemap = Minecraft.getMinecraft().getTextureMapBlocks();
        for (int i = 0; i < ClientUtils.destroyBlockIcons.length; i++)
            ClientUtils.destroyBlockIcons[i] = texturemap.getAtlasSprite("minecraft:blocks/destroy_stage_" + i);

        ImmersiveEngineering.proxy.clearRenderCaches();
    }

    public static Set<Connection> skyhookGrabableConnections = new HashSet<>();
    public static final Map<Connection, Pair<BlockPos, AtomicInteger>> FAILED_CONNECTIONS = new HashMap<>();

    @SubscribeEvent
    public void onPlayerTick(TickEvent.PlayerTickEvent event) {
        if (event.side.isClient() && event.player != null
                && event.player == ClientUtils.mc().getRenderViewEntity()) {
            //if(event.phase==Phase.START)
            //{
            //   skyhookGrabableConnections.clear();
            //   EntityPlayer player = event.player;
            //   ItemStack stack = player.getActiveItemStack();
            //   if(!stack.isEmpty()&&stack.getItem() instanceof ItemSkyhook)
            //   {
            //      Connection line = ApiUtils.getTargetConnection(player.getEntityWorld(), player, null, 0);
            //      if(line!=null)
            //         skyhookGrabableConnections.add(line);
            //   }
            //}

            if (event.phase == Phase.END) {
                if (this.shieldToggleTimer > 0)
                    this.shieldToggleTimer--;
                if (ClientProxy.keybind_magnetEquip.isKeyDown() && !this.shieldToggleButton)
                    if (this.shieldToggleTimer <= 0)
                        this.shieldToggleTimer = 7;
                    else {
                        EntityPlayer player = event.player;
                        ItemStack held = player.getHeldItem(EnumHand.OFF_HAND);
                        if (!held.isEmpty() && held.getItem() instanceof ItemIEShield) {
                            if (((ItemIEShield) held.getItem()).getUpgrades(held).getBoolean("magnet")
                                    && ((ItemIEShield) held.getItem()).getUpgrades(held).hasKey("prevSlot"))
                                ImmersiveEngineering.packetHandler.sendToServer(new MessageMagnetEquip(-1));
                        } else {
                            for (int i = 0; i < player.inventory.mainInventory.size(); i++) {
                                ItemStack s = player.inventory.mainInventory.get(i);
                                if (!s.isEmpty() && s.getItem() instanceof ItemIEShield
                                        && ((ItemIEShield) s.getItem()).getUpgrades(s).getBoolean("magnet"))
                                    ImmersiveEngineering.packetHandler.sendToServer(new MessageMagnetEquip(i));
                            }
                        }
                    }
                if (this.shieldToggleButton != ClientUtils.mc().gameSettings.keyBindBack.isKeyDown())
                    this.shieldToggleButton = ClientUtils.mc().gameSettings.keyBindBack.isKeyDown();

                if (ClientProxy.keybind_chemthrowerSwitch.isPressed()) {
                    ItemStack held = event.player.getHeldItem(EnumHand.MAIN_HAND);
                    if (held.getItem() instanceof ItemChemthrower
                            && ((ItemChemthrower) held.getItem()).getUpgrades(held).getBoolean("multitank"))
                        ImmersiveEngineering.packetHandler.sendToServer(new MessageChemthrowerSwitch(true));
                }
            }
        }

        //      if(event.side.isClient() && event.phase == Phase.END && event.player!=null)
        //      {
        //         EntityPlayer player = event.player;
        //         ItemStack stack = player.getActiveItemStack();
        //         boolean twohanded = stack!=null && (stack.getItem() instanceof ItemDrill);
        //         if(twohanded && (player!=ClientUtils.mc().getRenderViewEntity()||ClientUtils.mc().gameSettings.thirdPersonView!=0))
        //         {
        //            if(player.getItemInUseCount() <= 0)
        //            {
        //               player.stopActiveHand();
        //               player.setActiveHand(EnumHand.MAIN_HAND);
        //            }
        //         }
        //
        //      }
    }

    @SubscribeEvent
    public void onClientTick(TickEvent.ClientTickEvent event) {
        FAILED_CONNECTIONS.entrySet().removeIf(entry -> entry.getValue().getValue().decrementAndGet() <= 0);
    }

    @SubscribeEvent
    public void onItemTooltip(ItemTooltipEvent event) {
        if (event.getItemStack() == null || event.getItemStack().isEmpty())
            return;
        if (event.getItemStack().hasCapability(CapabilityShader.SHADER_CAPABILITY, null)) {
            ShaderWrapper wrapper = event.getItemStack().getCapability(CapabilityShader.SHADER_CAPABILITY, null);
            ItemStack shader = wrapper != null ? wrapper.getShaderItem() : null;
            if (!shader.isEmpty())
                event.getToolTip().add(TextFormatting.DARK_GRAY + shader.getDisplayName());
        }
        if (ItemNBTHelper.hasKey(event.getItemStack(), Lib.NBT_Earmuffs)) {
            ItemStack earmuffs = ItemNBTHelper.getItemStack(event.getItemStack(), Lib.NBT_Earmuffs);
            if (!earmuffs.isEmpty())
                event.getToolTip().add(TextFormatting.GRAY + earmuffs.getDisplayName());
        }
        if (ItemNBTHelper.hasKey(event.getItemStack(), Lib.NBT_Powerpack)) {
            ItemStack powerpack = ItemNBTHelper.getItemStack(event.getItemStack(), Lib.NBT_Powerpack);
            if (!powerpack.isEmpty()) {
                event.getToolTip().add(TextFormatting.GRAY + powerpack.getDisplayName());
                event.getToolTip().add(TextFormatting.GRAY.toString() + EnergyHelper.getEnergyStored(powerpack)
                        + "/" + EnergyHelper.getMaxEnergyStored(powerpack) + " IF");
            }
        }
        if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT && ClientUtils.mc().currentScreen != null
                && ClientUtils.mc().currentScreen instanceof GuiBlastFurnace
                && BlastFurnaceRecipe.isValidBlastFuel(event.getItemStack()))
            event.getToolTip().add(TextFormatting.GRAY + I18n.format("desc.immersiveengineering.info.blastFuelTime",
                    BlastFurnaceRecipe.getBlastFuelTime(event.getItemStack())));
        if (IEConfig.oreTooltips && event.getFlags().isAdvanced()) {
            for (int oid : OreDictionary.getOreIDs(event.getItemStack()))
                event.getToolTip().add(TextFormatting.GRAY + OreDictionary.getOreName(oid));
            //         FluidStack fs = FluidUtil.getFluidContained(event.getItemStack());
            //         if(fs!=null && fs.getFluid()!=null)
            //            event.getToolTip().add("Fluid: "+ FluidRegistry.getFluidName(fs));
        }

        if (event.getItemStack().getItem() instanceof IBulletContainer)
            for (String s : BULLET_TOOLTIP)
                event.getToolTip().add(s);
    }

    @SubscribeEvent()
    public void onRenderTooltip(RenderTooltipEvent.PostText event) {
        ItemStack stack = event.getStack();
        if (stack.getItem() instanceof IBulletContainer) {
            NonNullList<ItemStack> bullets = ((IBulletContainer) stack.getItem()).getBullets(stack, true);
            if (bullets != null) {
                int bulletAmount = ((IBulletContainer) stack.getItem()).getBulletCount(stack);
                int line = event.getLines().size() - Utils.findSequenceInList(event.getLines(), BULLET_TOOLTIP,
                        (s, s2) -> s.equals(s2.substring(2)));

                int currentX = event.getX();
                int currentY = line > 0 ? event.getY() + (event.getHeight() + 1 - line * 10) : event.getY() - 42;

                GlStateManager.pushMatrix();
                GlStateManager.enableBlend();
                GlStateManager.enableRescaleNormal();
                GlStateManager.translate(currentX, currentY, 700);
                GlStateManager.scale(.5f, .5f, 1);

                GuiRevolver.drawExternalGUI(bullets, bulletAmount);

                GlStateManager.disableRescaleNormal();
                GlStateManager.popMatrix();
            }
        }
    }

    @SubscribeEvent
    public void onPlaySound(PlaySoundEvent event) {
        if (event.getSound() == null || event.getSound().getCategory() == null)
            return;
        if (!ItemEarmuffs.affectedSoundCategories.contains(event.getSound().getCategory().getName()))
            return;
        if (ClientUtils.mc().player != null
                && !ClientUtils.mc().player.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()) {
            ItemStack earmuffs = ClientUtils.mc().player.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
            if (ItemNBTHelper.hasKey(earmuffs, Lib.NBT_Earmuffs))
                earmuffs = ItemNBTHelper.getItemStack(earmuffs, Lib.NBT_Earmuffs);
            if (!earmuffs.isEmpty() && IEContent.itemEarmuffs.equals(earmuffs.getItem()) && !ItemNBTHelper
                    .getBoolean(earmuffs, "IE:Earmuffs:Cat_" + event.getSound().getCategory().getName())) {
                for (String blacklist : IEConfig.Tools.earDefenders_SoundBlacklist)
                    if (blacklist != null
                            && blacklist.equalsIgnoreCase(event.getSound().getSoundLocation().toString()))
                        return;
                if (event.getSound() instanceof ITickableSound)
                    event.setResultSound(new IEMuffledTickableSound((ITickableSound) event.getSound(),
                            ItemEarmuffs.getVolumeMod(earmuffs)));
                else
                    event.setResultSound(new IEMuffledSound(event.getSound(), ItemEarmuffs.getVolumeMod(earmuffs)));

                if (event.getSound() instanceof PositionedSoundRecord) {
                    BlockPos pos = new BlockPos(event.getSound().getXPosF(), event.getSound().getYPosF(),
                            event.getSound().getZPosF());
                    if (ClientUtils.mc().renderGlobal.mapSoundPositions.containsKey(pos))
                        ClientUtils.mc().renderGlobal.mapSoundPositions.put(pos, event.getResultSound());
                }
            }
        }
    }

    private void renderObstructingBlocks(BufferBuilder bb, Tessellator tes, double dx, double dy, double dz) {
        bb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
        for (Map.Entry<Connection, Pair<BlockPos, AtomicInteger>> entry : FAILED_CONNECTIONS.entrySet()) {
            BlockPos obstruction = entry.getValue().getKey();
            bb.setTranslation(obstruction.getX() - dx, obstruction.getY() - dy, obstruction.getZ() - dz);
            final double eps = 1e-3;
            ClientUtils.renderBox(bb, -eps, -eps, -eps, 1 + eps, 1 + eps, 1 + eps);
        }
        bb.setTranslation(0, 0, 0);
        tes.draw();
    }

    /*
    static boolean connectionsRendered = false;
    public static void renderAllIEConnections(float partial)
    {
       if(connectionsRendered)
     return;
       GlStateManager.pushMatrix();
        
       GL11.glDisable(GL11.GL_CULL_FACE);
       //      GL11.glDisable(GL11.GL_TEXTURE_2D);
       GL11.glEnable(GL11.GL_BLEND);
       GL11.glDisable(GL11.GL_ALPHA_TEST);
       OpenGlHelper.glBlendFunc(770, 771, 1, 0);
       GL11.glShadeModel(GL11.GL_SMOOTH);
       RenderHelper.enableStandardItemLighting();
        
       Tessellator.instance.startDrawing(GL11.GL_QUADS);
        
       EntityLivingBase viewer = ClientUtils.mc().renderViewEntity;
       double dx = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * partial;//(double)event.partialTicks;
       double dy = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * partial;//(double)event.partialTicks;
       double dz = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * partial;//(double)event.partialTicks;
        
       for(Object o : ClientUtils.mc().renderGlobal.tileEntities)
     if(o instanceof IImmersiveConnectable)
     {
        TileEntity tile = (TileEntity)o;
        //            int lb = tile.getworld().getLightBrightnessForSkyBlocks(tile.xCoord, tile.yCoord, tile.zCoord, 0);
        //            int lb_j = lb % 65536;
        //            int lb_k = lb / 65536;
        //            OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lb_j / 1.0F, (float)lb_k / 1.0F);
        
        
        Tessellator.instance.setTranslation(tile.xCoord-dx, tile.yCoord-dy, tile.zCoord-dz);
        //            GlStateManager.translate((tile.xCoord+.5-dx), (tile.yCoord+.5-dy), (tile.zCoord+.5-dz));
        ClientUtils.renderAttachedConnections((TileEntity)tile);
        //            GlStateManager.translate(-(tile.xCoord+.5-dx), -(tile.yCoord+.5-dy), -(tile.zCoord+.5-dz));
        
     }
        
       Iterator<ImmersiveNetHandler.Connection> it = skyhookGrabableConnections.iterator();
       World world = viewer.world;
       while(it.hasNext())
       {
     ImmersiveNetHandler.Connection con = it.next();
     Tessellator.instance.setTranslation(con.start.posX-dx, con.start.posY-dy, con.start.posZ-dz);
     double r = con.cableType.getRenderDiameter()/2;
     ClientUtils.drawConnection(con, Utils.toIIC(con.start, world), Utils.toIIC(con.end, world),   0x00ff99,128,r*1.75, con.cableType.getIcon(con));
       }
        
       Tessellator.instance.setTranslation(0,0,0);
       Tessellator.instance.draw();
        
       GL11.glDisable(GL11.GL_BLEND);
       GL11.glEnable(GL11.GL_ALPHA_TEST);
       GL11.glEnable(GL11.GL_TEXTURE_2D);
       GL11.glEnable(GL11.GL_CULL_FACE);
        
       GlStateManager.popMatrix();
       connectionsRendered = true;
    }
     */

    @SubscribeEvent
    public void onRenderItemFrame(RenderItemInFrameEvent event) {
        if (!event.getItem().isEmpty() && event.getItem().getItem() instanceof ItemEngineersBlueprint) {
            double playerDistanceSq = ClientUtils.mc().player
                    .getDistanceSq(event.getEntityItemFrame().getPosition());

            if (playerDistanceSq < 1000) {
                BlueprintCraftingRecipe[] recipes = BlueprintCraftingRecipe
                        .findRecipes(ItemNBTHelper.getString(event.getItem(), "blueprint"));
                if (recipes != null && recipes.length > 0) {
                    int i = event.getEntityItemFrame().getRotation();
                    BlueprintCraftingRecipe recipe = recipes[i % recipes.length];
                    BlueprintLines blueprint = recipe == null ? null
                            : TileRenderAutoWorkbench.getBlueprintDrawable(recipe,
                                    event.getEntityItemFrame().getEntityWorld());
                    if (blueprint != null) {
                        GlStateManager.rotate(-i * 45.0F, 0.0F, 0.0F, 1.0F);
                        ClientUtils.bindTexture("immersiveengineering:textures/models/blueprint_frame.png");
                        GlStateManager.translate(-.5, .5, -.001);
                        ClientUtils.drawTexturedRect(.125f, -.875f, .75f, .75f, 1d, 0d, 1d, 0d);
                        //Width depends on distance
                        float lineWidth = playerDistanceSq < 3 ? 3
                                : playerDistanceSq < 25 ? 2 : playerDistanceSq < 40 ? 1 : .5f;
                        GlStateManager.translate(.75, -.25, -.002);
                        GlStateManager.disableCull();
                        GlStateManager.disableTexture2D();
                        GlStateManager.enableBlend();
                        float scale = .0375f / (blueprint.getTextureScale() / 16f);
                        GlStateManager.scale(-scale, -scale, scale);
                        GlStateManager.color(1, 1, 1, 1);

                        blueprint.draw(lineWidth);

                        GlStateManager.scale(1 / scale, -1 / scale, 1 / scale);
                        GlStateManager.enableAlpha();
                        GlStateManager.enableTexture2D();
                        GlStateManager.enableCull();

                        event.setCanceled(true);
                    }
                }
            }
        }
    }

    @SubscribeEvent
    public void onRenderOverlayPre(RenderGameOverlayEvent.Pre event) {
        if (ZoomHandler.isZooming && event.getType() == RenderGameOverlayEvent.ElementType.CROSSHAIRS) {
            event.setCanceled(true);
            if (ZoomHandler.isZooming) {
                ClientUtils.bindTexture("immersiveengineering:textures/gui/scope.png");
                int width = event.getResolution().getScaledWidth();
                int height = event.getResolution().getScaledHeight();
                int resMin = Math.min(width, height);
                float offsetX = (width - resMin) / 2f;
                float offsetY = (height - resMin) / 2f;

                if (resMin == width) {
                    ClientUtils.drawColouredRect(0, 0, width, (int) offsetY + 1, 0xff000000);
                    ClientUtils.drawColouredRect(0, (int) offsetY + resMin, width, (int) offsetY + 1, 0xff000000);
                } else {
                    ClientUtils.drawColouredRect(0, 0, (int) offsetX + 1, height, 0xff000000);
                    ClientUtils.drawColouredRect((int) offsetX + resMin, 0, (int) offsetX + 1, height, 0xff000000);
                }
                GlStateManager.enableBlend();
                OpenGlHelper.glBlendFunc(770, 771, 1, 0);

                GlStateManager.translate(offsetX, offsetY, 0);
                ClientUtils.drawTexturedRect(0, 0, resMin, resMin, 0f, 1f, 0f, 1f);

                ClientUtils.bindTexture("immersiveengineering:textures/gui/hud_elements.png");
                ClientUtils.drawTexturedRect(218 / 256f * resMin, 64 / 256f * resMin, 24 / 256f * resMin,
                        128 / 256f * resMin, 64 / 256f, 88 / 256f, 96 / 256f, 224 / 256f);
                ItemStack equipped = ClientUtils.mc().player.getHeldItem(EnumHand.MAIN_HAND);
                if (!equipped.isEmpty() && equipped.getItem() instanceof IZoomTool) {
                    IZoomTool tool = (IZoomTool) equipped.getItem();
                    float[] steps = tool.getZoomSteps(equipped, ClientUtils.mc().player);
                    if (steps != null && steps.length > 1) {
                        int curStep = -1;
                        float dist = 0;

                        float totalOffset = 0;
                        float stepLength = 118 / (float) steps.length;
                        float stepOffset = (stepLength - 7) / 2f;
                        GlStateManager.translate(223 / 256f * resMin, 64 / 256f * resMin, 0);
                        GlStateManager.translate(0, (5 + stepOffset) / 256 * resMin, 0);
                        for (int i = 0; i < steps.length; i++) {
                            ClientUtils.drawTexturedRect(0, 0, 8 / 256f * resMin, 7 / 256f * resMin, 88 / 256f,
                                    96 / 256f, 96 / 256f, 103 / 256f);
                            GlStateManager.translate(0, stepLength / 256 * resMin, 0);
                            totalOffset += stepLength;

                            if (curStep == -1 || Math.abs(steps[i] - ZoomHandler.fovZoom) < dist) {
                                curStep = i;
                                dist = Math.abs(steps[i] - ZoomHandler.fovZoom);
                            }
                        }
                        GlStateManager.translate(0, -totalOffset / 256 * resMin, 0);

                        if (curStep >= 0 && curStep < steps.length) {
                            GlStateManager.translate(6 / 256f * resMin, curStep * stepLength / 256 * resMin, 0);
                            ClientUtils.drawTexturedRect(0, 0, 8 / 256f * resMin, 7 / 256f * resMin, 88 / 256f,
                                    98 / 256f, 103 / 256f, 110 / 256f);
                            ClientUtils.font().drawString((1 / steps[curStep]) + "x", (int) (16 / 256f * resMin), 0,
                                    0xffffff);
                            GlStateManager.translate(-6 / 256f * resMin, -curStep * stepLength / 256 * resMin, 0);
                        }
                        GlStateManager.translate(0, -((5 + stepOffset) / 256 * resMin), 0);
                        GlStateManager.translate(-223 / 256f * resMin, -64 / 256f * resMin, 0);
                    }
                }

                GlStateManager.translate(-offsetX, -offsetY, 0);
            }
        }
    }

    @SubscribeEvent()
    public void onRenderOverlayPost(RenderGameOverlayEvent.Post event) {
        if (ClientUtils.mc().player != null && event.getType() == RenderGameOverlayEvent.ElementType.TEXT) {
            EntityPlayer player = ClientUtils.mc().player;

            for (EnumHand hand : EnumHand.values())
                if (!player.getHeldItem(hand).isEmpty()) {
                    ItemStack equipped = player.getHeldItem(hand);
                    if (OreDictionary.itemMatches(new ItemStack(IEContent.itemTool, 1, 2), equipped, false)
                            || equipped.getItem() instanceof IWireCoil) {
                        if (ItemNBTHelper.hasKey(equipped, "linkingPos")) {
                            int[] link = ItemNBTHelper.getIntArray(equipped, "linkingPos");
                            if (link != null && link.length > 3) {
                                String s = I18n.format(Lib.DESC_INFO + "attachedTo", link[1], link[2], link[3]);
                                int col = WireType.ELECTRUM.getColour(null);
                                if (equipped.getItem() instanceof IWireCoil) {
                                    RayTraceResult rtr = ClientUtils.mc().objectMouseOver;
                                    double d = rtr != null && rtr.getBlockPos() != null
                                            ? rtr.getBlockPos().distanceSq(link[1], link[2], link[3])
                                            : player.getDistanceSq(link[1], link[2], link[3]);
                                    int max = ((IWireCoil) equipped.getItem()).getWireType(equipped).getMaxLength();
                                    if (d > max * max)
                                        col = 0xdd3333;
                                }
                                ClientUtils.font().drawString(s,
                                        event.getResolution().getScaledWidth() / 2
                                                - ClientUtils.font().getStringWidth(s) / 2,
                                        event.getResolution().getScaledHeight() - GuiIngameForge.left_height - 20,
                                        col, true);
                            }
                        }
                    } else if (OreDictionary.itemMatches(equipped, new ItemStack(IEContent.itemFluorescentTube),
                            false)) {
                        String s = I18n.format("desc.immersiveengineering.info.colour",
                                "#" + ItemFluorescentTube.hexColorString(equipped));
                        ClientUtils.font().drawString(s,
                                event.getResolution().getScaledWidth() / 2
                                        - ClientUtils.font().getStringWidth(s) / 2,
                                event.getResolution().getScaledHeight() - GuiIngameForge.left_height - 20,
                                ItemFluorescentTube.getRGBInt(equipped, 1), true);
                    } else if (equipped.getItem() instanceof ItemRevolver
                            || equipped.getItem() instanceof ItemSpeedloader) {
                        NonNullList<ItemStack> bullets = ((IBulletContainer) equipped.getItem())
                                .getBullets(equipped, true);
                        if (bullets != null) {
                            int bulletAmount = ((IBulletContainer) equipped.getItem()).getBulletCount(equipped);
                            EnumHandSide side = hand == EnumHand.MAIN_HAND ? player.getPrimaryHand()
                                    : player.getPrimaryHand().opposite();
                            boolean right = side == EnumHandSide.RIGHT;
                            float dx = right ? event.getResolution().getScaledWidth() - 32 - 48 : 48;
                            float dy = event.getResolution().getScaledHeight() - 64;
                            GlStateManager.pushMatrix();
                            GlStateManager.enableRescaleNormal();
                            GlStateManager.enableBlend();
                            GlStateManager.translate(dx, dy, 0);
                            GlStateManager.scale(.5f, .5f, 1);

                            GuiRevolver.drawExternalGUI(bullets, bulletAmount);

                            if (equipped.getItem() instanceof ItemRevolver) {
                                int cd = ((ItemRevolver) equipped.getItem()).getShootCooldown(equipped);
                                float cdMax = ((ItemRevolver) equipped.getItem()).getMaxShootCooldown(equipped);
                                float cooldown = 1 - cd / cdMax;
                                if (cooldown > 0) {
                                    GlStateManager.scale(2, 2, 1);
                                    GlStateManager.translate(-dx, -dy, 0);
                                    GlStateManager.translate(
                                            event.getResolution().getScaledWidth() / 2 + (right ? 1 : -6),
                                            event.getResolution().getScaledHeight() / 2 - 7, 0);

                                    float h1 = cooldown > .33 ? .5f : cooldown * 1.5f;
                                    float h2 = cooldown;
                                    float x2 = cooldown < .75 ? 1 : 4 * (1 - cooldown);

                                    float uMin = (88 + (right ? 0 : 7 * x2)) / 256f;
                                    float uMax = (88 + (right ? 7 * x2 : 0)) / 256f;
                                    float vMin1 = (112 + (right ? h1 : h2) * 15) / 256f;
                                    float vMin2 = (112 + (right ? h2 : h1) * 15) / 256f;

                                    ClientUtils.bindTexture("immersiveengineering:textures/gui/hud_elements.png");
                                    Tessellator tessellator = Tessellator.getInstance();
                                    BufferBuilder worldrenderer = tessellator.getBuffer();
                                    worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
                                    worldrenderer.pos((right ? 0 : 1 - x2) * 7, 15, 0).tex(uMin, 127 / 256f)
                                            .endVertex();
                                    worldrenderer.pos((right ? x2 : 1) * 7, 15, 0).tex(uMax, 127 / 256f)
                                            .endVertex();
                                    worldrenderer.pos((right ? x2 : 1) * 7, (right ? h2 : h1) * 15, 0)
                                            .tex(uMax, vMin2).endVertex();
                                    worldrenderer.pos((right ? 0 : 1 - x2) * 7, (right ? h1 : h2) * 15, 0)
                                            .tex(uMin, vMin1).endVertex();
                                    tessellator.draw();
                                }
                            }
                            RenderHelper.disableStandardItemLighting();
                            GlStateManager.disableBlend();
                            GlStateManager.popMatrix();
                        }

                    } else if (equipped.getItem() instanceof ItemRailgun) {
                        int duration = 72000 - (player.isHandActive() && player.getActiveHand() == hand
                                ? player.getItemInUseCount()
                                : 0);
                        int chargeTime = ((ItemRailgun) equipped.getItem()).getChargeTime(equipped);
                        int chargeLevel = duration < 72000
                                ? Math.min(99, (int) (duration / (float) chargeTime * 100))
                                : 0;
                        float scale = 2f;
                        GlStateManager.pushMatrix();
                        GlStateManager.translate(event.getResolution().getScaledWidth() - 80,
                                event.getResolution().getScaledHeight() - 30, 0);
                        GlStateManager.scale(scale, scale, 1);
                        ClientProxy.nixieFont.drawString((chargeLevel < 10 ? "0" : "") + chargeLevel, 0, 0,
                                Lib.colour_nixieTubeText, false);
                        GlStateManager.scale(1 / scale, 1 / scale, 1);
                        GlStateManager.popMatrix();
                    } else if ((equipped.getItem() instanceof ItemDrill && equipped.getItemDamage() == 0)
                            || equipped.getItem() instanceof ItemChemthrower) {
                        boolean drill = equipped.getItem() instanceof ItemDrill;
                        ClientUtils.bindTexture("immersiveengineering:textures/gui/hud_elements.png");
                        GlStateManager.color(1, 1, 1, 1);
                        float dx = event.getResolution().getScaledWidth() - 16;
                        float dy = event.getResolution().getScaledHeight();
                        GlStateManager.pushMatrix();
                        GlStateManager.translate(dx, dy, 0);
                        int w = 31;
                        int h = 62;
                        double uMin = 179 / 256f;
                        double uMax = 210 / 256f;
                        double vMin = 9 / 256f;
                        double vMax = 71 / 256f;
                        ClientUtils.drawTexturedRect(-24, -68, w, h, uMin, uMax, vMin, vMax);

                        GlStateManager.translate(-23, -37, 0);
                        IFluidHandler handler = FluidUtil.getFluidHandler(equipped);
                        int capacity = -1;
                        if (handler != null) {
                            IFluidTankProperties[] props = handler.getTankProperties();
                            if (props != null && props.length > 0)
                                capacity = props[0].getCapacity();
                        }
                        if (capacity > -1) {
                            FluidStack fuel = FluidUtil.getFluidContained(equipped);
                            int amount = fuel != null ? fuel.amount : 0;
                            if (!drill && player.isHandActive() && player.getActiveHand() == hand) {
                                int use = player.getItemInUseMaxCount();
                                amount -= use * IEConfig.Tools.chemthrower_consumption;
                            }
                            float cap = (float) capacity;
                            float angle = 83 - (166 * amount / cap);
                            GlStateManager.rotate(angle, 0, 0, 1);
                            ClientUtils.drawTexturedRect(6, -2, 24, 4, 91 / 256f, 123 / 256f, 80 / 256f, 87 / 256f);
                            GlStateManager.rotate(-angle, 0, 0, 1);
                            //               for(int i=0; i<=8; i++)
                            //               {
                            //                  float angle = 83-(166/8f)*i;
                            //                  GL11.glRotatef(angle, 0, 0, 1);
                            //                  ClientUtils.drawTexturedRect(6,-2, 24,4, 91/256f,123/256f, 80/96f,87/96f);
                            //                  GL11.glRotatef(-angle, 0, 0, 1);
                            //               }
                            GlStateManager.translate(23, 37, 0);
                            if (drill) {
                                ClientUtils.drawTexturedRect(-54, -73, 66, 72, 108 / 256f, 174 / 256f, 4 / 256f,
                                        76 / 256f);
                                RenderItem ir = ClientUtils.mc().getRenderItem();
                                ItemStack head = ((ItemDrill) equipped.getItem()).getHead(equipped);
                                if (!head.isEmpty()) {
                                    ir.renderItemIntoGUI(head, -51, -45);
                                    ir.renderItemOverlayIntoGUI(head.getItem().getFontRenderer(head), head, -51,
                                            -45, null);
                                    RenderHelper.disableStandardItemLighting();
                                }
                            } else {
                                ClientUtils.drawTexturedRect(-41, -73, 53, 72, 8 / 256f, 61 / 256f, 4 / 256f,
                                        76 / 256f);
                                boolean ignite = ItemNBTHelper.getBoolean(equipped, "ignite");
                                ClientUtils.drawTexturedRect(-32, -43, 12, 12, 66 / 256f, 78 / 256f,
                                        (ignite ? 21 : 9) / 256f, (ignite ? 33 : 21) / 256f);

                                ClientUtils.drawTexturedRect(-100, -20, 64, 16, 0 / 256f, 64 / 256f, 76 / 256f,
                                        92 / 256f);
                                if (fuel != null) {
                                    String name = ClientUtils.font().trimStringToWidth(fuel.getLocalizedName(), 50)
                                            .trim();
                                    ClientUtils.font().drawString(name,
                                            -68 - ClientUtils.font().getStringWidth(name) / 2, -15, 0);
                                }
                            }
                        }
                        GlStateManager.popMatrix();
                    } else if (equipped.getItem() instanceof ItemIEShield) {
                        NBTTagCompound upgrades = ((ItemIEShield) equipped.getItem()).getUpgrades(equipped);
                        if (!upgrades.isEmpty()) {
                            ClientUtils.bindTexture("immersiveengineering:textures/gui/hud_elements.png");
                            GlStateManager.color(1, 1, 1, 1);
                            boolean boundLeft = (player
                                    .getPrimaryHand() == EnumHandSide.RIGHT) == (hand == EnumHand.OFF_HAND);
                            float dx = boundLeft ? 16 : (event.getResolution().getScaledWidth() - 16 - 64);
                            float dy = event.getResolution().getScaledHeight();
                            GlStateManager.pushMatrix();
                            GlStateManager.enableBlend();
                            GlStateManager.translate(dx, dy, 0);
                            ClientUtils.drawTexturedRect(0, -22, 64, 22, 0, 64 / 256f, 176 / 256f, 198 / 256f);

                            if (upgrades.getBoolean("flash")) {
                                ClientUtils.drawTexturedRect(11, -38, 16, 16, 11 / 256f, 27 / 256f, 160 / 256f,
                                        176 / 256f);
                                if (upgrades.hasKey("flash_cooldown")) {
                                    float h = upgrades.getInteger("flash_cooldown") / 40f * 16;
                                    ClientUtils.drawTexturedRect(11, -22 - h, 16, h, 11 / 256f, 27 / 256f,
                                            (214 - h) / 256f, 214 / 256f);
                                }
                            }
                            if (upgrades.getBoolean("shock")) {
                                ClientUtils.drawTexturedRect(40, -38, 12, 16, 40 / 256f, 52 / 256f, 160 / 256f,
                                        176 / 256f);
                                if (upgrades.hasKey("shock_cooldown")) {
                                    float h = upgrades.getInteger("shock_cooldown") / 40f * 16;
                                    ClientUtils.drawTexturedRect(40, -22 - h, 12, h, 40 / 256f, 52 / 256f,
                                            (214 - h) / 256f, 214 / 256f);
                                }
                            }
                            GlStateManager.disableBlend();
                            GlStateManager.popMatrix();
                        }
                    }
                    //            else if(equipped.getItem() instanceof ItemRailgun)
                    //            {
                    //               float dx = event.getResolution().getScaledWidth()-32-48;
                    //               float dy = event.getResolution().getScaledHeight()-40;
                    //               ClientUtils.bindTexture("immersiveengineering:textures/gui/hud_elements.png");
                    //               GlStateManager.color(1, 1, 1, 1);
                    //               GlStateManager.pushMatrix();
                    //               GL11.glEnable(GL11.GL_BLEND);
                    //               GlStateManager.translate(dx, dy, 0);
                    //
                    //               int duration = player.getItemInUseDuration();
                    //               int chargeTime = ((ItemRailgun)equipped.getItem()).getChargeTime(equipped);
                    //               int chargeLevel = Math.min(99, (int)(duration/(float)chargeTime*100));
                    //               //               ClientUtils.drawTexturedRect(0,0, 64,32, 0/256f,64/256f, 96/256f,128/256f);
                    //
                    //               GlStateManager.scale(1.5f,1.5f,1.5f);
                    //               int col = Config.getBoolean("nixietubeFont")?Lib.colour_nixieTubeText:0xffffff;
                    //               ClientProxy.nixieFont.setDrawTubeFlag(false);
                    //               //               ClientProxy.nixieFont.drawString((chargeLevel<10?"0"+chargeLevel:""+chargeLevel), 19,3, col);
                    //               ClientProxy.nixieFont.setDrawTubeFlag(true);
                    //
                    //               GlStateManager.popMatrix();
                    //            }

                    RayTraceResult mop = ClientUtils.mc().objectMouseOver;
                    if (mop != null && mop.getBlockPos() != null) {
                        TileEntity tileEntity = player.world.getTileEntity(mop.getBlockPos());
                        if (OreDictionary.itemMatches(new ItemStack(IEContent.itemTool, 1, 2), equipped, true)) {
                            int col = IEConfig.nixietubeFont ? Lib.colour_nixieTubeText : 0xffffff;
                            String[] text = null;
                            if (tileEntity instanceof IFluxReceiver) {
                                int maxStorage = ((IFluxReceiver) tileEntity).getMaxEnergyStored(mop.sideHit);
                                int storage = ((IFluxReceiver) tileEntity).getEnergyStored(mop.sideHit);
                                if (maxStorage > 0)
                                    text = I18n.format(Lib.DESC_INFO + "energyStored",
                                            "<br>" + Utils.toScientificNotation(storage, "0##", 100000) + " / "
                                                    + Utils.toScientificNotation(maxStorage, "0##", 100000))
                                            .split("<br>");
                            }
                            //                  else if(Lib.GREG && GregTechHelper.gregtech_isValidEnergyOutput(tileEntity))
                            //                  {
                            //                     String gregStored = GregTechHelper.gregtech_getEnergyStored(tileEntity);
                            //                     if(gregStored!=null)
                            //                        text = StatCollector.translateToLocalFormatted(Lib.DESC_INFO+"energyStored","<br>"+gregStored).split("<br>");
                            //                  }
                            else if (mop.entityHit instanceof IFluxReceiver) {
                                int maxStorage = ((IFluxReceiver) mop.entityHit).getMaxEnergyStored(null);
                                int storage = ((IFluxReceiver) mop.entityHit).getEnergyStored(null);
                                if (maxStorage > 0)
                                    text = I18n.format(Lib.DESC_INFO + "energyStored",
                                            "<br>" + Utils.toScientificNotation(storage, "0##", 100000) + " / "
                                                    + Utils.toScientificNotation(maxStorage, "0##", 100000))
                                            .split("<br>");
                            }
                            if (text != null) {
                                if (player.world.getTotalWorldTime() % 20 == 0) {
                                    ImmersiveEngineering.packetHandler
                                            .sendToServer(new MessageRequestBlockUpdate(mop.getBlockPos()));
                                }
                                int i = 0;
                                for (String s : text)
                                    if (s != null) {
                                        int w = ClientProxy.nixieFontOptional.getStringWidth(s);
                                        ClientProxy.nixieFontOptional.drawString(s,
                                                event.getResolution().getScaledWidth() / 2 - w / 2,
                                                event.getResolution().getScaledHeight() / 2 - 4
                                                        - text.length
                                                                * (ClientProxy.nixieFontOptional.FONT_HEIGHT + 2)
                                                        + (i++) * (ClientProxy.nixieFontOptional.FONT_HEIGHT + 2),
                                                col, true);
                                    }
                            }
                        }
                    }
                }
            if (ClientUtils.mc().objectMouseOver != null) {
                boolean hammer = !player.getHeldItem(EnumHand.MAIN_HAND).isEmpty()
                        && Utils.isHammer(player.getHeldItem(EnumHand.MAIN_HAND));
                RayTraceResult mop = ClientUtils.mc().objectMouseOver;
                if (mop != null && mop.getBlockPos() != null) {
                    TileEntity tileEntity = player.world.getTileEntity(mop.getBlockPos());
                    if (tileEntity instanceof IBlockOverlayText) {
                        IBlockOverlayText overlayBlock = (IBlockOverlayText) tileEntity;
                        String[] text = overlayBlock.getOverlayText(ClientUtils.mc().player, mop, hammer);
                        boolean useNixie = overlayBlock.useNixieFont(ClientUtils.mc().player, mop);
                        if (text != null && text.length > 0) {
                            FontRenderer font = useNixie ? ClientProxy.nixieFontOptional : ClientUtils.font();
                            int col = (useNixie && IEConfig.nixietubeFont) ? Lib.colour_nixieTubeText : 0xffffff;
                            int i = 0;
                            for (String s : text)
                                if (s != null)
                                    font.drawString(s, event.getResolution().getScaledWidth() / 2 + 8,
                                            event.getResolution().getScaledHeight() / 2 + 8
                                                    + (i++) * font.FONT_HEIGHT,
                                            col, true);
                        }
                    }
                }
            }
        }
    }

    @SubscribeEvent()
    public void onFogUpdate(EntityViewRenderEvent.RenderFogEvent event) {
        if (event.getEntity() instanceof EntityLivingBase
                && ((EntityLivingBase) event.getEntity()).getActivePotionEffect(IEPotions.flashed) != null) {
            PotionEffect effect = ((EntityLivingBase) event.getEntity()).getActivePotionEffect(IEPotions.flashed);
            int timeLeft = effect.getDuration();
            float saturation = 1 - timeLeft / (float) (80 + 40 * effect.getAmplifier());//Total Time =  4s + 2s per amplifier

            float f1 = -2.5f + 15.0F * saturation;
            if (timeLeft < 20)
                f1 += (event.getFarPlaneDistance() / 4) * (1 - timeLeft / 20f);

            GlStateManager.setFog(GlStateManager.FogMode.LINEAR);
            GlStateManager.setFogStart(f1 * 0.25F);
            GlStateManager.setFogEnd(f1);
            GlStateManager.setFogDensity(.125f);

            if (GLContext.getCapabilities().GL_NV_fog_distance)
                GlStateManager.glFogi(34138, 34139);
        }
    }

    @SubscribeEvent()
    public void onFogColourUpdate(EntityViewRenderEvent.FogColors event) {
        if (event.getEntity() instanceof EntityLivingBase
                && ((EntityLivingBase) event.getEntity()).getActivePotionEffect(IEPotions.flashed) != null) {
            event.setRed(1);
            event.setGreen(1);
            event.setBlue(1);
        }
    }

    @SubscribeEvent()
    public void onFOVUpdate(FOVUpdateEvent event) {
        EntityPlayer player = ClientUtils.mc().player;
        if (!player.getHeldItem(EnumHand.MAIN_HAND).isEmpty()
                && player.getHeldItem(EnumHand.MAIN_HAND).getItem() instanceof IZoomTool) {
            if (player.isSneaking() && player.onGround) {
                ItemStack equipped = player.getHeldItem(EnumHand.MAIN_HAND);
                IZoomTool tool = (IZoomTool) equipped.getItem();
                if (tool.canZoom(equipped, player)) {
                    if (!ZoomHandler.isZooming) {
                        float[] steps = tool.getZoomSteps(equipped, player);
                        if (steps != null && steps.length > 0) {
                            int curStep = -1;
                            float dist = 0;
                            for (int i = 0; i < steps.length; i++)
                                if (curStep == -1 || Math.abs(steps[i] - ZoomHandler.fovZoom) < dist) {
                                    curStep = i;
                                    dist = Math.abs(steps[i] - ZoomHandler.fovZoom);
                                }
                            if (curStep != -1)
                                ZoomHandler.fovZoom = steps[curStep];
                            else
                                ZoomHandler.fovZoom = event.getFov();
                        }
                        ZoomHandler.isZooming = true;
                    }
                    event.setNewfov(ZoomHandler.fovZoom);
                } else if (ZoomHandler.isZooming)
                    ZoomHandler.isZooming = false;
            } else if (ZoomHandler.isZooming)
                ZoomHandler.isZooming = false;
        } else if (ZoomHandler.isZooming)
            ZoomHandler.isZooming = false;
        if (player.getActivePotionEffect(IEPotions.concreteFeet) != null)
            event.setNewfov(1);

    }

    @SubscribeEvent
    public void onMouseEvent(MouseEvent event) {
        if (event.getDwheel() != 0) {
            EntityPlayer player = ClientUtils.mc().player;
            if (!player.getHeldItem(EnumHand.MAIN_HAND).isEmpty() && player.isSneaking()) {
                ItemStack equipped = player.getHeldItem(EnumHand.MAIN_HAND);

                if (equipped.getItem() instanceof IZoomTool) {
                    IZoomTool tool = (IZoomTool) equipped.getItem();
                    if (tool.canZoom(equipped, player)) {
                        float[] steps = tool.getZoomSteps(equipped, player);
                        if (steps != null && steps.length > 0) {
                            int curStep = -1;
                            float dist = 0;
                            for (int i = 0; i < steps.length; i++)
                                if (curStep == -1 || Math.abs(steps[i] - ZoomHandler.fovZoom) < dist) {
                                    curStep = i;
                                    dist = Math.abs(steps[i] - ZoomHandler.fovZoom);
                                }
                            if (curStep != -1) {
                                int newStep = curStep + (event.getDwheel() > 0 ? -1 : 1);
                                if (newStep >= 0 && newStep < steps.length)
                                    ZoomHandler.fovZoom = steps[newStep];
                                event.setCanceled(true);
                            }
                        }
                    }
                }
                if (Config.IEConfig.Tools.chemthrower_scroll && equipped.getItem() instanceof ItemChemthrower
                        && ((ItemChemthrower) equipped.getItem()).getUpgrades(equipped).getBoolean("multitank")) {
                    ImmersiveEngineering.packetHandler
                            .sendToServer(new MessageChemthrowerSwitch(event.getDwheel() < 0));
                    event.setCanceled(true);
                }
            }
        }
    }

    @SubscribeEvent(priority = EventPriority.LOW)
    public void onKey(GuiScreenEvent.MouseInputEvent.Pre event) {
        //Stopping cpw's inventory sorter till I can get him to make it better
        if (event.getGui() instanceof GuiToolbox && Mouse.getEventButton() == 2)
            event.setCanceled(true);
    }

    @SubscribeEvent()
    public void renderAdditionalBlockBounds(DrawBlockHighlightEvent event) {
        if (event.getSubID() == 0 && event.getTarget().typeOfHit == Type.BLOCK) {
            float f1 = 0.002F;
            double px = -TileEntityRendererDispatcher.staticPlayerX;
            double py = -TileEntityRendererDispatcher.staticPlayerY;
            double pz = -TileEntityRendererDispatcher.staticPlayerZ;
            TileEntity tile = event.getPlayer().world.getTileEntity(event.getTarget().getBlockPos());
            ItemStack stack = event.getPlayer().getHeldItem(EnumHand.MAIN_HAND);
            //         if(event.getPlayer().world.getBlockState(event.getTarget().getBlockPos()).getBlock() instanceof IEBlockInterfaces.ICustomBoundingboxes)
            if (tile instanceof IAdvancedSelectionBounds) {
                //            IEBlockInterfaces.ICustomBoundingboxes block = (IEBlockInterfaces.ICustomBoundingboxes) event.getPlayer().world.getBlockState(event.getTarget().getBlockPos()).getBlock();
                IAdvancedSelectionBounds iasb = (IAdvancedSelectionBounds) tile;
                List<AxisAlignedBB> boxes = iasb.getAdvancedSelectionBounds();
                if (boxes != null && !boxes.isEmpty()) {
                    GlStateManager.enableBlend();
                    GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA,
                            SourceFactor.ONE, DestFactor.ZERO);
                    GlStateManager.glLineWidth(2.0F);
                    GlStateManager.disableTexture2D();
                    GlStateManager.depthMask(false);
                    ArrayList<AxisAlignedBB> additionalBoxes = new ArrayList<AxisAlignedBB>();
                    AxisAlignedBB overrideBox = null;
                    for (AxisAlignedBB aabb : boxes)
                        if (aabb != null) {
                            if (iasb.isOverrideBox(aabb, event.getPlayer(), event.getTarget(), additionalBoxes))
                                overrideBox = aabb;
                        }

                    if (overrideBox != null)
                        RenderGlobal.drawSelectionBoundingBox(overrideBox.grow(f1).offset(px, py, pz), 0, 0, 0,
                                0.4f);
                    else
                        for (AxisAlignedBB aabb : additionalBoxes.isEmpty() ? boxes : additionalBoxes)
                            RenderGlobal.drawSelectionBoundingBox(aabb.grow(f1).offset(px, py, pz), 0, 0, 0, 0.4f);
                    GlStateManager.depthMask(true);
                    GlStateManager.enableTexture2D();
                    GlStateManager.disableBlend();
                    event.setCanceled(true);
                }
            }

            if (Utils.isHammer(stack) && tile instanceof TileEntityTurntable) {
                BlockPos pos = event.getTarget().getBlockPos();

                GlStateManager.enableBlend();
                GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA,
                        SourceFactor.ONE, DestFactor.ZERO);
                GlStateManager.glLineWidth(2.0F);
                GlStateManager.disableTexture2D();
                GlStateManager.depthMask(false);

                Tessellator tessellator = Tessellator.getInstance();
                BufferBuilder BufferBuilder = tessellator.getBuffer();

                EnumFacing f = ((TileEntityTurntable) tile).getFacing();
                double tx = pos.getX() + .5;
                double ty = pos.getY() + .5;
                double tz = pos.getZ() + .5;
                if (!event.getPlayer().world.isAirBlock(pos.offset(f))) {
                    tx += f.getXOffset();
                    ty += f.getYOffset();
                    tz += f.getZOffset();
                }
                BufferBuilder.setTranslation(tx + px, ty + py, tz + pz);

                double angle = -event.getPlayer().ticksExisted % 80 / 40d * Math.PI;
                drawRotationArrows(tessellator, BufferBuilder, f, angle, ((TileEntityTurntable) tile).invert);

                BufferBuilder.setTranslation(0, 0, 0);

                GlStateManager.depthMask(true);
                GlStateManager.enableTexture2D();
                GlStateManager.disableBlend();
            }

            World world = event.getPlayer().world;
            if (!stack.isEmpty() && IEContent.blockConveyor.equals(Block.getBlockFromItem(stack.getItem()))
                    && event.getTarget().sideHit.getAxis() == Axis.Y) {
                EnumFacing side = event.getTarget().sideHit;
                BlockPos pos = event.getTarget().getBlockPos();
                AxisAlignedBB targetedBB = world.getBlockState(pos).getSelectedBoundingBox(world, pos);
                if (targetedBB != null)
                    targetedBB = targetedBB.offset(-pos.getX(), -pos.getY(), -pos.getZ());
                GlStateManager.enableBlend();
                GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA,
                        SourceFactor.ONE, DestFactor.ZERO);
                GlStateManager.glLineWidth(2.0F);
                GlStateManager.disableTexture2D();
                GlStateManager.depthMask(false);

                Tessellator tessellator = Tessellator.getInstance();
                BufferBuilder BufferBuilder = tessellator.getBuffer();
                BufferBuilder.setTranslation(pos.getX() + px, pos.getY() + py, pos.getZ() + pz);
                double[][] points = new double[4][];

                if (side.getAxis() == Axis.Y) {
                    points[0] = new double[] { 0 - f1,
                            side == EnumFacing.DOWN ? ((targetedBB != null ? targetedBB.minY : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxY : 1) + f1),
                            0 - f1 };
                    points[1] = new double[] { 1 + f1,
                            side == EnumFacing.DOWN ? ((targetedBB != null ? targetedBB.minY : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxY : 1) + f1),
                            1 + f1 };
                    points[2] = new double[] { 0 - f1,
                            side == EnumFacing.DOWN ? ((targetedBB != null ? targetedBB.minY : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxY : 1) + f1),
                            1 + f1 };
                    points[3] = new double[] { 1 + f1,
                            side == EnumFacing.DOWN ? ((targetedBB != null ? targetedBB.minY : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxY : 1) + f1),
                            0 - f1 };
                } else if (side.getAxis() == Axis.Z) {
                    points[0] = new double[] { 1 + f1, 1 + f1,
                            side == EnumFacing.NORTH ? ((targetedBB != null ? targetedBB.minZ : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxZ : 1) + f1) };
                    points[1] = new double[] { 0 - f1, 0 - f1,
                            side == EnumFacing.NORTH ? ((targetedBB != null ? targetedBB.minZ : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxZ : 1) + f1) };
                    points[2] = new double[] { 0 - f1, 1 + f1,
                            side == EnumFacing.NORTH ? ((targetedBB != null ? targetedBB.minZ : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxZ : 1) + f1) };
                    points[3] = new double[] { 1 + f1, 0 - f1,
                            side == EnumFacing.NORTH ? ((targetedBB != null ? targetedBB.minZ : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxZ : 1) + f1) };
                } else {
                    points[0] = new double[] {
                            side == EnumFacing.WEST ? ((targetedBB != null ? targetedBB.minX : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxX : 1) + f1),
                            1 + f1, 1 + f1 };
                    points[1] = new double[] {
                            side == EnumFacing.WEST ? ((targetedBB != null ? targetedBB.minX : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxX : 1) + f1),
                            0 - f1, 0 - f1 };
                    points[2] = new double[] {
                            side == EnumFacing.WEST ? ((targetedBB != null ? targetedBB.minX : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxX : 1) + f1),
                            1 + f1, 0 - f1 };
                    points[3] = new double[] {
                            side == EnumFacing.WEST ? ((targetedBB != null ? targetedBB.minX : 0) - f1)
                                    : ((targetedBB != null ? targetedBB.maxX : 1) + f1),
                            0 - f1, 1 + f1 };
                }
                BufferBuilder.begin(1, DefaultVertexFormats.POSITION_COLOR);
                for (double[] point : points)
                    BufferBuilder.pos(point[0], point[1], point[2]).color(0, 0, 0, 0.4F).endVertex();
                tessellator.draw();

                BufferBuilder.begin(2, DefaultVertexFormats.POSITION_COLOR);
                BufferBuilder.pos(points[0][0], points[0][1], points[0][2]).color(0, 0, 0, 0.4F).endVertex();
                BufferBuilder.pos(points[2][0], points[2][1], points[2][2]).color(0, 0, 0, 0.4F).endVertex();
                BufferBuilder.pos(points[1][0], points[1][1], points[1][2]).color(0, 0, 0, 0.4F).endVertex();
                BufferBuilder.pos(points[3][0], points[3][1], points[3][2]).color(0, 0, 0, 0.4F).endVertex();
                tessellator.draw();

                float xFromMid = side.getAxis() == Axis.X ? 0
                        : (float) event.getTarget().hitVec.x - pos.getX() - .5f;
                float yFromMid = side.getAxis() == Axis.Y ? 0
                        : (float) event.getTarget().hitVec.y - pos.getY() - .5f;
                float zFromMid = side.getAxis() == Axis.Z ? 0
                        : (float) event.getTarget().hitVec.z - pos.getZ() - .5f;
                float max = Math.max(Math.abs(yFromMid), Math.max(Math.abs(xFromMid), Math.abs(zFromMid)));
                Vec3d dir = new Vec3d(max == Math.abs(xFromMid) ? Math.signum(xFromMid) : 0,
                        max == Math.abs(yFromMid) ? Math.signum(yFromMid) : 0,
                        max == Math.abs(zFromMid) ? Math.signum(zFromMid) : 0);
                if (dir != null)
                    drawBlockOverlayArrow(tessellator, BufferBuilder, dir, side, targetedBB);
                BufferBuilder.setTranslation(0, 0, 0);

                GlStateManager.depthMask(true);
                GlStateManager.enableTexture2D();
                GlStateManager.disableBlend();
            }

            if (!stack.isEmpty() && stack.getItem() instanceof ItemDrill && ((ItemDrill) stack.getItem())
                    .isEffective(world.getBlockState(event.getTarget().getBlockPos()).getMaterial())) {
                ItemStack head = ((ItemDrill) stack.getItem()).getHead(stack);
                if (!head.isEmpty()) {
                    ImmutableList<BlockPos> blocks = ((IDrillHead) head.getItem()).getExtraBlocksDug(head, world,
                            event.getPlayer(), event.getTarget());
                    drawAdditionalBlockbreak(event.getContext(), event.getPlayer(), event.getPartialTicks(),
                            blocks);
                }
            }
        }
    }

    private static double[][] rotationArrowCoords = { { .375, 0 }, { .5, -.125 }, { .4375, -.125 }, { .4375, -.25 },
            { .25, -.4375 }, { -.25, -.4375 }, { -.4375, -.25 }, { -.4375, -.0625 }, { -.3125, -.0625 },
            { -.3125, -.1875 }, { -.1875, -.3125 }, { .1875, -.3125 }, { .3125, -.1875 }, { .3125, -.125 },
            { .25, -.125 } };
    private static double[][] rotationArrowQuads = { rotationArrowCoords[7], rotationArrowCoords[8],
            rotationArrowCoords[6], rotationArrowCoords[9], rotationArrowCoords[5], rotationArrowCoords[10],
            rotationArrowCoords[4], rotationArrowCoords[11], rotationArrowCoords[3], rotationArrowCoords[12],
            rotationArrowCoords[2], rotationArrowCoords[13], rotationArrowCoords[1], rotationArrowCoords[14],
            rotationArrowCoords[0], rotationArrowCoords[0] };

    public static void drawRotationArrows(Tessellator tessellator, BufferBuilder BufferBuilder, EnumFacing facing,
            double rotation, boolean flip) {
        double cos = Math.cos(rotation);
        double sin = Math.sin(rotation);
        BufferBuilder.begin(GL11.GL_LINE_LOOP, DefaultVertexFormats.POSITION_COLOR);
        for (double[] p : rotationArrowCoords) {
            double w = (cos * p[0] + sin * p[1]);
            double h = (-sin * p[0] + cos * p[1]);
            double xx = facing.getXOffset() < 0 ? -(.5 + .002)
                    : facing.getXOffset() > 0 ? (.5 + .002)
                            : (facing.getAxis() == Axis.Y ^ flip ? -1 : 1) * facing.getAxisDirection().getOffset()
                                    * h;
            double yy = facing.getYOffset() < 0 ? -(.5 + .002) : facing.getYOffset() > 0 ? (.5 + .002) : w;
            double zz = facing.getZOffset() < 0 ? -(.5 + .002)
                    : facing.getZOffset() > 0 ? (.5 + .002)
                            : facing.getAxis() == Axis.X
                                    ? (flip ? 1 : -1) * facing.getAxisDirection().getOffset() * h
                                    : w;
            BufferBuilder.pos(xx, yy, zz).color(0, 0, 0, 0.4F).endVertex();
        }
        tessellator.draw();
        BufferBuilder.begin(GL11.GL_LINE_LOOP, DefaultVertexFormats.POSITION_COLOR);
        for (double[] p : rotationArrowCoords) {
            double w = (cos * p[0] + sin * p[1]);
            double h = (-sin * p[0] + cos * p[1]);
            double xx = facing.getXOffset() < 0 ? -(.5 + .002)
                    : facing.getXOffset() > 0 ? (.5 + .002)
                            : (facing.getAxis() == Axis.Y ^ flip ? 1 : -1) * facing.getAxisDirection().getOffset()
                                    * h;
            double yy = facing.getYOffset() < 0 ? -(.5 + .002) : facing.getYOffset() > 0 ? (.5 + .002) : -w;
            double zz = facing.getZOffset() < 0 ? -(.5 + .002)
                    : facing.getZOffset() > 0 ? (.5 + .002)
                            : facing.getAxis() == Axis.X
                                    ? (flip ? -1 : 1) * facing.getAxisDirection().getOffset() * h
                                    : -w;
            BufferBuilder.pos(xx, yy, zz).color(0, 0, 0, 0.4F).endVertex();
        }
        tessellator.draw();

        BufferBuilder.begin(GL11.GL_QUAD_STRIP, DefaultVertexFormats.POSITION_COLOR);
        for (double[] p : rotationArrowQuads) {
            double w = (cos * p[0] + sin * p[1]);
            double h = (-sin * p[0] + cos * p[1]);
            double xx = facing.getXOffset() < 0 ? -(.5 + .002)
                    : facing.getXOffset() > 0 ? (.5 + .002)
                            : (facing.getAxis() == Axis.Y ^ flip ? -1 : 1) * facing.getAxisDirection().getOffset()
                                    * h;
            double yy = facing.getYOffset() < 0 ? -(.5 + .002) : facing.getYOffset() > 0 ? (.5 + .002) : w;
            double zz = facing.getZOffset() < 0 ? -(.5 + .002)
                    : facing.getZOffset() > 0 ? (.5 + .002)
                            : facing.getAxis() == Axis.X
                                    ? (flip ? 1 : -1) * facing.getAxisDirection().getOffset() * h
                                    : w;
            BufferBuilder.pos(xx, yy, zz).color(Lib.COLOUR_F_ImmersiveOrange[0], Lib.COLOUR_F_ImmersiveOrange[1],
                    Lib.COLOUR_F_ImmersiveOrange[2], 0.4F).endVertex();
        }
        tessellator.draw();
        BufferBuilder.begin(GL11.GL_QUAD_STRIP, DefaultVertexFormats.POSITION_COLOR);
        for (double[] p : rotationArrowQuads) {
            double w = (cos * p[0] + sin * p[1]);
            double h = (-sin * p[0] + cos * p[1]);
            double xx = facing.getXOffset() < 0 ? -(.5 + .002)
                    : facing.getXOffset() > 0 ? (.5 + .002)
                            : (facing.getAxis() == Axis.Y ^ flip ? 1 : -1) * facing.getAxisDirection().getOffset()
                                    * h;
            double yy = facing.getYOffset() < 0 ? -(.5 + .002) : facing.getYOffset() > 0 ? (.5 + .002) : -w;
            double zz = facing.getZOffset() < 0 ? -(.5 + .002)
                    : facing.getZOffset() > 0 ? (.5 + .002)
                            : facing.getAxis() == Axis.X
                                    ? (flip ? -1 : 1) * facing.getAxisDirection().getOffset() * h
                                    : -w;
            BufferBuilder.pos(xx, yy, zz).color(Lib.COLOUR_F_ImmersiveOrange[0], Lib.COLOUR_F_ImmersiveOrange[1],
                    Lib.COLOUR_F_ImmersiveOrange[2], 0.4F).endVertex();
        }
        tessellator.draw();
    }

    private static float[][] arrowCoords = { { 0, .375f }, { .3125f, .0625f }, { .125f, .0625f }, { .125f, -.375f },
            { -.125f, -.375f }, { -.125f, .0625f }, { -.3125f, .0625f } };

    public static void drawBlockOverlayArrow(Tessellator tessellator, BufferBuilder BufferBuilder,
            Vec3d directionVec, EnumFacing side, AxisAlignedBB targetedBB) {
        Vec3d[] translatedPositions = new Vec3d[arrowCoords.length];
        Matrix4 mat = new Matrix4();
        Vec3d defaultDir = side.getAxis() == Axis.Y ? new Vec3d(0, 0, 1) : new Vec3d(0, 1, 0);
        directionVec = directionVec.normalize();
        double angle = Math.acos(defaultDir.dotProduct(directionVec));
        Vec3d axis = defaultDir.crossProduct(directionVec);
        mat.rotate(angle, axis.x, axis.y, axis.z);
        if (side != null) {
            if (side.getAxis() == Axis.Z)
                mat.rotate(Math.PI / 2, 1, 0, 0).rotate(Math.PI, 0, 1, 0);
            else if (side.getAxis() == Axis.X)
                mat.rotate(Math.PI / 2, 0, 0, 1).rotate(Math.PI / 2, 0, 1, 0);
        }
        for (int i = 0; i < translatedPositions.length; i++) {
            Vec3d vec = mat.apply(new Vec3d(arrowCoords[i][0], 0, arrowCoords[i][1])).add(.5, .5, .5);
            if (side != null && targetedBB != null)
                vec = new Vec3d(
                        side == EnumFacing.WEST ? targetedBB.minX - .002
                                : side == EnumFacing.EAST ? targetedBB.maxX + .002 : vec.x,
                        side == EnumFacing.DOWN ? targetedBB.minY - .002
                                : side == EnumFacing.UP ? targetedBB.maxY + .002 : vec.y,
                        side == EnumFacing.NORTH ? targetedBB.minZ - .002
                                : side == EnumFacing.SOUTH ? targetedBB.maxZ + .002 : vec.z);
            translatedPositions[i] = vec;
        }

        BufferBuilder.begin(6, DefaultVertexFormats.POSITION_COLOR);
        for (Vec3d point : translatedPositions)
            BufferBuilder.pos(point.x, point.y, point.z).color(Lib.COLOUR_F_ImmersiveOrange[0],
                    Lib.COLOUR_F_ImmersiveOrange[1], Lib.COLOUR_F_ImmersiveOrange[2], 0.4F).endVertex();
        tessellator.draw();
        BufferBuilder.begin(2, DefaultVertexFormats.POSITION_COLOR);
        for (Vec3d point : translatedPositions)
            BufferBuilder.pos(point.x, point.y, point.z).color(0, 0, 0, 0.4F).endVertex();
        tessellator.draw();
    }

    public static void drawAdditionalBlockbreak(RenderGlobal context, EntityPlayer player, float partialTicks,
            Collection<BlockPos> blocks) {
        for (BlockPos pos : blocks)
            context.drawSelectionBox(player, new RayTraceResult(new Vec3d(0, 0, 0), null, pos), 0, partialTicks);

        PlayerControllerMP controllerMP = ClientUtils.mc().playerController;
        if (controllerMP.isHittingBlock)
            ClientUtils.drawBlockDamageTexture(ClientUtils.tes(), ClientUtils.tes().getBuffer(), player,
                    partialTicks, player.world, blocks);
    }

    private static ItemStack sampleDrill = ItemStack.EMPTY;

    @SubscribeEvent
    public void onRenderWorldLastEvent(RenderWorldLastEvent event) {
        //Overlay renderer for the sample drill
        boolean chunkBorders = false;
        if (sampleDrill.isEmpty())
            sampleDrill = new ItemStack(IEContent.blockMetalDevice1, 1,
                    BlockTypes_MetalDevice1.SAMPLE_DRILL.getMeta());
        for (EnumHand hand : EnumHand.values())
            if (OreDictionary.itemMatches(sampleDrill, ClientUtils.mc().player.getHeldItem(hand), true)) {
                chunkBorders = true;
                break;
            }
        if (!chunkBorders && ClientUtils.mc().objectMouseOver != null
                && ClientUtils.mc().objectMouseOver.typeOfHit == Type.BLOCK && ClientUtils.mc().world.getTileEntity(
                        ClientUtils.mc().objectMouseOver.getBlockPos()) instanceof TileEntitySampleDrill)
            chunkBorders = true;

        float partial = event.getPartialTicks();
        if (!ParticleFractal.PARTICLE_FRACTAL_DEQUE.isEmpty()) {
            double px = TileEntityRendererDispatcher.staticPlayerX;
            double py = TileEntityRendererDispatcher.staticPlayerY;
            double pz = TileEntityRendererDispatcher.staticPlayerZ;

            Tessellator tessellator = Tessellator.getInstance();

            GlStateManager.disableTexture2D();
            GlStateManager.enableBlend();
            GlStateManager.disableCull();
            GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
            GlStateManager.shadeModel(GL11.GL_SMOOTH);

            tessellator.getBuffer().setTranslation(-px, -py, -pz);
            ParticleFractal part;
            while ((part = ParticleFractal.PARTICLE_FRACTAL_DEQUE.pollFirst()) != null)
                part.render(tessellator, tessellator.getBuffer(), partial);
            tessellator.getBuffer().setTranslation(0, 0, 0);

            GlStateManager.shadeModel(GL11.GL_FLAT);
            GlStateManager.enableCull();
            GlStateManager.disableBlend();
            GlStateManager.enableTexture2D();
        }

        if (chunkBorders) {
            EntityPlayer player = ClientUtils.mc().player;
            double px = TileEntityRendererDispatcher.staticPlayerX;
            double py = TileEntityRendererDispatcher.staticPlayerY;
            double pz = TileEntityRendererDispatcher.staticPlayerZ;
            int chunkX = (int) player.posX >> 4 << 4;
            int chunkZ = (int) player.posZ >> 4 << 4;
            int y = Math.min((int) player.posY - 2,
                    player.getEntityWorld().getChunk(new BlockPos(player.posX, 0, player.posZ)).getLowestHeight());
            float h = (float) Math.max(32, player.posY - y + 4);
            Tessellator tessellator = Tessellator.getInstance();
            BufferBuilder BufferBuilder = tessellator.getBuffer();

            GlStateManager.disableTexture2D();
            GlStateManager.enableBlend();
            GlStateManager.disableCull();
            GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
            GlStateManager.shadeModel(GL11.GL_SMOOTH);
            float r = Lib.COLOUR_F_ImmersiveOrange[0];
            float g = Lib.COLOUR_F_ImmersiveOrange[1];
            float b = Lib.COLOUR_F_ImmersiveOrange[2];
            BufferBuilder.setTranslation(chunkX - px, y + 2 - py, chunkZ - pz);
            GlStateManager.glLineWidth(5f);
            BufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
            BufferBuilder.pos(0, 0, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, h, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 0, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, h, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 0, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, h, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, 0, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, h, 16).color(r, g, b, .375f).endVertex();

            BufferBuilder.pos(0, 2, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 2, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, 2, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, 2, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(0, 2, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 2, 16).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 2, 0).color(r, g, b, .375f).endVertex();
            BufferBuilder.pos(16, 2, 16).color(r, g, b, .375f).endVertex();
            tessellator.draw();
            BufferBuilder.setTranslation(0, 0, 0);
            GlStateManager.shadeModel(GL11.GL_FLAT);
            GlStateManager.enableCull();
            GlStateManager.disableBlend();
            GlStateManager.enableTexture2D();
        }

        if (!FAILED_CONNECTIONS.isEmpty()) {
            Entity viewer = ClientUtils.mc().getRenderViewEntity();
            if (viewer == null)
                viewer = ClientUtils.mc().player;
            double dx = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * partial;
            double dy = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * partial;
            double dz = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * partial;
            Tessellator tes = Tessellator.getInstance();
            BufferBuilder bb = tes.getBuffer();
            float oldLineWidth = GL11.glGetFloat(GL11.GL_LINE_WIDTH);
            GlStateManager.glLineWidth(5);
            GlStateManager.disableTexture2D();
            GlStateManager.enableBlend();
            bb.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
            for (Entry<Connection, Pair<BlockPos, AtomicInteger>> entry : FAILED_CONNECTIONS.entrySet()) {
                Connection conn = entry.getKey();
                bb.setTranslation(conn.start.getX() - dx, conn.start.getY() - dy, conn.start.getZ() - dz);
                Vec3d[] points = conn.getSubVertices(ClientUtils.mc().world);
                int time = entry.getValue().getValue().get();
                float alpha = (float) Math.min((2 + Math.sin(time * Math.PI / 40)) / 3, time / 20F);
                for (int i = 0; i < points.length - 1; i++) {
                    bb.pos(points[i].x, points[i].y, points[i].z).color(1, 0, 0, alpha).endVertex();
                    alpha = (float) Math.min((2 + Math.sin((time + (i + 1) * 8) * Math.PI / 40)) / 3, time / 20F);
                    bb.pos(points[i + 1].x, points[i + 1].y, points[i + 1].z).color(1, 0, 0, alpha).endVertex();
                }
            }
            bb.setTranslation(0, 0, 0);
            tes.draw();
            GlStateManager.glLineWidth(oldLineWidth);
            GlStateManager.enableBlend();
            GlStateManager.color(1, 0, 0, .5F);
            renderObstructingBlocks(bb, tes, dx, dy, dz);

            //Code to render the obstructing block through other blocks
            //GlStateManager.color(1, 0, 0, .25F);
            //GlStateManager.depthFunc(GL11.GL_GREATER);
            //renderObstructingBlocks(bb, tes, dx, dy, dz);
            //GlStateManager.depthFunc(GL11.GL_LEQUAL);

            GlStateManager.disableBlend();
            GlStateManager.enableTexture2D();
        }
    }

    //   static void renderBoundingBox(AxisAlignedBB aabb, double offsetX, double offsetY, double offsetZ, float expand)
    //   {
    //      if(aabb instanceof AdvancedAABB && ((AdvancedAABB)aabb).drawOverride!=null && ((AdvancedAABB)aabb).drawOverride.length>0)
    //      {
    //         double midX = aabb.minX+(aabb.maxX-aabb.minX)/2;
    //         double midY = aabb.minY+(aabb.maxY-aabb.minY)/2;
    //         double midZ = aabb.minZ+(aabb.maxZ-aabb.minZ)/2;
    //         ClientUtils.tes().addTranslation((float)offsetX, (float)offsetY, (float)offsetZ);
    //         for(Vec3[] face : ((AdvancedAABB)aabb).drawOverride)
    //         {
    //            ClientUtils.tes().startDrawing(GL11.GL_LINE_LOOP);
    //            for(Vec3 v : face)
    //               ClientUtils.tes().addVertex(v.xCoord+(v.xCoord<midX?-expand:expand),v.yCoord+(v.yCoord<midY?-expand:expand),v.zCoord+(v.zCoord<midZ?-expand:expand));
    //            ClientUtils.tes().draw();
    //         }
    //         ClientUtils.tes().addTranslation((float)-offsetX, (float)-offsetY, (float)-offsetZ);
    //      }
    //      else
    //         RenderGlobal.drawOutlinedBoundingBox(aabb.getOffsetBoundingBox(offsetX, offsetY, offsetZ).expand((double)expand, (double)expand, (double)expand), -1);
    //   }

    @SubscribeEvent()
    public void onClientDeath(LivingDeathEvent event) {
    }

    @SubscribeEvent()
    public void onRenderLivingPre(RenderLivingEvent.Pre event) {
        if (event.getEntity().getEntityData().hasKey("headshot")) {
            ModelBase model = event.getRenderer().mainModel;
            if (model instanceof ModelBiped)
                ((ModelBiped) model).bipedHead.showModel = false;
            else if (model instanceof ModelVillager)
                ((ModelVillager) model).villagerHead.showModel = false;
        }
    }

    @SubscribeEvent()
    public void onRenderLivingPost(RenderLivingEvent.Post event) {
        if (event.getEntity().getEntityData().hasKey("headshot")) {
            ModelBase model = event.getRenderer().mainModel;
            if (model instanceof ModelBiped)
                ((ModelBiped) model).bipedHead.showModel = true;
            else if (model instanceof ModelVillager)
                ((ModelVillager) model).villagerHead.showModel = true;
        }
    }

    private boolean justLoggedIn = false;

    @SubscribeEvent
    public void onLoginClientPre(ClientConnectedToServerEvent ev) {
        justLoggedIn = true;
    }

    @SubscribeEvent
    public void onLoginClient(EntityJoinWorldEvent ev) {
        if (ev.getEntity() == Minecraft.getMinecraft().player && justLoggedIn) {
            String javaV = System.getProperty("java.version");
            if (javaV.equals("1.8.0_25"))
                Minecraft.getMinecraft().player
                        .sendMessage(new TextComponentTranslation(Lib.CHAT_INFO + "old_java", javaV));
            justLoggedIn = false;
        }
    }
}