vazkii.psi.client.core.handler.HUDHandler.java Source code

Java tutorial

Introduction

Here is the source code for vazkii.psi.client.core.handler.HUDHandler.java

Source

/**
 * This class was created by <Vazkii>. It's distributed as
 * part of the Psi Mod. Get the Source Code in github:
 * https://github.com/Vazkii/Psi
 *
 * Psi is Open Source and distributed under the
 * Psi License: http://psi.vazkii.us/license.php
 *
 * File Created @ [11/01/2016, 00:30:54 (GMT)]
 */
package vazkii.psi.client.core.handler;

import java.awt.Color;
import java.util.function.Consumer;
import java.util.regex.Pattern;

import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.ARBMultitexture;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;

import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiIngame;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import vazkii.psi.api.PsiAPI;
import vazkii.psi.api.cad.ICAD;
import vazkii.psi.api.cad.ICADColorizer;
import vazkii.psi.api.cad.ISocketable;
import vazkii.psi.client.gui.GuiLeveling;
import vazkii.psi.common.core.handler.ConfigHandler;
import vazkii.psi.common.core.handler.PlayerDataHandler;
import vazkii.psi.common.core.handler.PlayerDataHandler.PlayerData;
import vazkii.psi.common.core.handler.PlayerDataHandler.PlayerData.Deduction;
import vazkii.psi.common.item.base.IHUDItem;
import vazkii.psi.common.lib.LibObfuscation;
import vazkii.psi.common.lib.LibResources;

public final class HUDHandler {

    private static final ResourceLocation psiBar = new ResourceLocation(LibResources.GUI_PSI_BAR);
    private static final ResourceLocation psiBarMask = new ResourceLocation(LibResources.GUI_PSI_BAR_MASK);
    private static final ResourceLocation psiBarShatter = new ResourceLocation(LibResources.GUI_PSI_BAR_SHATTER);

    private static final int secondaryTextureUnit = 7;

    private static boolean registeredMask = false;
    private static int maxRemainingTicks = 30;
    private static int remainingLeaveTicks = 20;

    public static boolean showLevelUp = false;
    public static int levelDisplayTime = 0;
    public static int levelValue = 0;

    private static ItemStack remainingDisplayStack;
    private static int remainingTime;
    private static int remainingCount;

    @SubscribeEvent
    @SideOnly(Side.CLIENT)
    public void onDraw(RenderGameOverlayEvent.Post event) {
        if (event.getType() == ElementType.ALL) {
            ScaledResolution resolution = event.getResolution();
            float partialTicks = event.getPartialTicks();

            drawPsiBar(resolution, partialTicks);
            renderSocketableEquippedName(resolution, partialTicks);
            renderLevelUpIndicator(resolution, partialTicks);
            renderRemainingItems(resolution, partialTicks);
            renderHUDItem(resolution, partialTicks);
        }
    }

    public static void tick() {
        if (showLevelUp)
            levelDisplayTime++;

        if (remainingTime > 0)
            --remainingTime;
    }

    @SideOnly(Side.CLIENT)
    public void drawPsiBar(ScaledResolution res, float pticks) {
        Minecraft mc = Minecraft.getMinecraft();
        ItemStack cadStack = PsiAPI.getPlayerCAD(mc.thePlayer);

        if (cadStack == null)
            return;

        ICAD cad = (ICAD) cadStack.getItem();
        PlayerData data = PlayerDataHandler.get(mc.thePlayer);
        if (data.level == 0 && !mc.thePlayer.capabilities.isCreativeMode)
            return;

        GlStateManager.pushMatrix();
        int scaleFactor = res.getScaleFactor();

        if (scaleFactor > ConfigHandler.maxPsiBarScale) {
            int guiScale = mc.gameSettings.guiScale;

            mc.gameSettings.guiScale = ConfigHandler.maxPsiBarScale;
            res = new ScaledResolution(mc);
            mc.gameSettings.guiScale = guiScale;

            float s = (float) ConfigHandler.maxPsiBarScale / (float) scaleFactor;
            GlStateManager.scale(s, s, s);
        }

        boolean right = ConfigHandler.psiBarOnRight;

        int pad = 3;
        int width = 32;
        int height = 140;

        int x = -pad;
        if (right)
            x = res.getScaledWidth() + pad - width;
        int y = res.getScaledHeight() / 2 - height / 2;

        if (!registeredMask) {
            mc.renderEngine.bindTexture(psiBarMask);
            mc.renderEngine.bindTexture(psiBarShatter);
            registeredMask = true;
        }
        mc.renderEngine.bindTexture(psiBar);
        Gui.drawModalRectWithCustomSizedTexture(x, y, 0, 0, width, height, 64, 256);

        x += 8;
        y += 26;

        width = 16;
        height = 106;

        float r = 0.6F;
        float g = 0.65F;
        float b = 1F;

        int origHeight = height;
        int origY = y;
        int v = 0;
        int max = data.getTotalPsi();

        int texture = 0;
        boolean shaders = ShaderHandler.useShaders();

        if (shaders) {
            OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
            texture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
        }

        GlStateManager.enableBlend();
        GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        for (Deduction d : data.deductions) {
            float a = d.getPercentile(pticks);
            GlStateManager.color(r, g, b, a);
            height = (int) Math.ceil(origHeight * (double) d.deduct / max);
            int effHeight = (int) (origHeight * (double) d.current / max);
            v = origHeight - effHeight;
            y = origY + v;

            ShaderHandler.useShader(ShaderHandler.psiBar, generateCallback(a, d.shatter));
            Gui.drawModalRectWithCustomSizedTexture(x, y, 32, v, width, height, 64, 256);
        }

        float textY = origY;
        if (max > 0) {
            height = (int) ((double) origHeight * (double) data.availablePsi / max);
            v = origHeight - height;
            y = origY + v;

            if (data.availablePsi != data.lastAvailablePsi) {
                float textHeight = (float) (origHeight
                        * (data.availablePsi * pticks + data.lastAvailablePsi * (1.0 - pticks)) / max);
                textY = origY + (origHeight - textHeight);
            } else
                textY = y;
        } else
            height = 0;

        GlStateManager.color(r, g, b);
        ShaderHandler.useShader(ShaderHandler.psiBar, generateCallback(1F, false));
        Gui.drawModalRectWithCustomSizedTexture(x, y, 32, v, width, height, 64, 256);
        ShaderHandler.releaseShader();

        if (shaders) {
            OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
            OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB);
        }

        GlStateManager.color(1F, 1F, 1F);

        GlStateManager.pushMatrix();
        GlStateManager.translate(0F, textY, 0F);
        width = 44;
        height = 3;

        String s1 = "" + data.availablePsi;
        String s2 = "" + cad.getStoredPsi(cadStack);

        int offBar = 22;
        int offStr1 = 7 + mc.fontRendererObj.getStringWidth(s1);
        int offStr2 = 7 + mc.fontRendererObj.getStringWidth(s2);

        if (!right) {
            offBar = 6;
            offStr1 = -23;
            offStr2 = -23;
        }

        Color color = new Color(cad.getSpellColor(cadStack));
        GlStateManager.color(color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F);

        Gui.drawModalRectWithCustomSizedTexture(x - offBar, -2, 0, 140, width, height, 64, 256);
        mc.fontRendererObj.drawStringWithShadow(s1, x - offStr1, -11, 0xFFFFFF);
        GlStateManager.popMatrix();

        GlStateManager.pushMatrix();
        GlStateManager.translate(0F, Math.max(textY + 3, origY + 100), 0F);
        mc.fontRendererObj.drawStringWithShadow(s2, x - offStr2, 0, 0xFFFFFF);
        GlStateManager.popMatrix();
        GlStateManager.popMatrix();
    }

    @SideOnly(Side.CLIENT)
    private void renderSocketableEquippedName(ScaledResolution res, float pticks) {
        Minecraft mc = Minecraft.getMinecraft();
        ItemStack stack = mc.thePlayer.getHeldItem(EnumHand.MAIN_HAND);
        String name = ISocketable.getSocketedItemName(stack, "");
        if (stack == null || name == null || name.trim().isEmpty())
            return;

        int ticks = ReflectionHelper.getPrivateValue(GuiIngame.class, mc.ingameGUI,
                LibObfuscation.REMAINING_HIGHLIGHT_TICKS);
        ticks -= 10;

        if (ticks > 0) {
            ItemStack socketable = ((ISocketable) stack.getItem()).getBulletInSocket(stack,
                    ((ISocketable) stack.getItem()).getSelectedSlot(stack));

            int alpha = Math.min(255, (int) ((ticks - pticks) * 256.0F / 10.0F));
            int color = ICADColorizer.DEFAULT_SPELL_COLOR + (alpha << 24);

            int x = res.getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(name) / 2;
            int y = res.getScaledHeight() - 71;
            if (mc.thePlayer.capabilities.isCreativeMode)
                y += 14;

            GlStateManager.enableBlend();
            GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
            mc.fontRendererObj.drawStringWithShadow(name, x, y, color);

            int w = mc.fontRendererObj.getStringWidth(name);
            GlStateManager.pushMatrix();
            GlStateManager.translate(x + w, y - 6, 0);
            GlStateManager.scale(alpha / 255F, 1F, 1);
            GlStateManager.color(1F, 1F, 1F);
            mc.getRenderItem().renderItemIntoGUI(socketable, 0, 0);
            GlStateManager.popMatrix();
            GlStateManager.disableBlend();
        }
    }

    public static void levelUp(int level) {
        levelValue = level;
        levelDisplayTime = 0;
        showLevelUp = true;
    }

    @SideOnly(Side.CLIENT)
    private void renderLevelUpIndicator(ScaledResolution res, float pticks) {
        Minecraft mc = Minecraft.getMinecraft();
        if (mc.currentScreen instanceof GuiLeveling)
            showLevelUp = false;

        if (!showLevelUp)
            return;

        GlStateManager.enableBlend();
        GlStateManager.disableAlpha();
        GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        int time = 100;
        int fadeTime = time / 10;
        int fadeoutTime = fadeTime * 2;

        String levelUp = I18n.translateToLocal("psimisc.levelup");
        int len = levelUp.length();
        int effLen = Math.min(len, len * levelDisplayTime / fadeTime);
        levelUp = levelUp.substring(0, effLen);

        int swidth = mc.fontRendererObj.getStringWidth(levelUp);
        int x = res.getScaledWidth() / 4 - swidth / 2;
        int y = 25;
        float a = 1F - Math.max(0F, Math.min(1F, (float) (levelDisplayTime - time) / fadeoutTime));
        int alphaOverlay = (int) (a * 0xFF) << 24;

        GlStateManager.pushMatrix();
        GlStateManager.scale(2F, 2F, 2F);
        mc.fontRendererObj.drawStringWithShadow(levelUp, x, y, 0x0013C5FF + alphaOverlay);

        String currLevel = "" + levelValue;
        swidth = mc.fontRendererObj.getStringWidth(currLevel);
        x = res.getScaledWidth() / 4;
        y += 10;

        if (levelDisplayTime > fadeTime) {
            if (levelDisplayTime - fadeTime == 1)
                mc.getSoundHandler()
                        .playSound(PositionedSoundRecord.getMasterRecord(PsiSoundHandler.levelUp, 0.5F));

            float a1 = Math.min(1F, (float) (levelDisplayTime - fadeTime) / fadeTime) * a;
            int color1 = 0x00FFFFFF + ((int) (a1 * 0xFF) << 24);
            mc.fontRendererObj.drawStringWithShadow(TextFormatting.GOLD + currLevel, x, y, color1);
        }
        GlStateManager.popMatrix();

        if (levelDisplayTime > fadeTime * 2) {
            String s = I18n.translateToLocal("psimisc.levelUpInfo1");
            swidth = mc.fontRendererObj.getStringWidth(s);
            len = s.length();
            effLen = Math.min(len, len * (levelDisplayTime - fadeTime * 2) / fadeTime);
            s = s.substring(0, effLen);
            x = res.getScaledWidth() / 2 - swidth / 2;
            y += 65;

            mc.fontRendererObj.drawStringWithShadow(s, x, y, 0x00FFFFFF + alphaOverlay);
        }

        if (levelDisplayTime > fadeTime * 3) {
            String s = I18n.translateToLocal("psimisc.levelUpInfo2");
            s = String.format(s, TextFormatting.GREEN + Keyboard.getKeyName(KeybindHandler.keybind.getKeyCode())
                    + TextFormatting.RESET);
            swidth = mc.fontRendererObj.getStringWidth(s);
            len = s.length();
            effLen = Math.min(len, len * (levelDisplayTime - fadeTime * 3) / fadeTime);
            s = s.substring(0, effLen);
            x = res.getScaledWidth() / 2 - swidth / 2;
            y += 10;

            mc.fontRendererObj.drawStringWithShadow(s, x, y, 0x00FFFFFF + alphaOverlay);
        }

        GlStateManager.enableAlpha();
        if (levelValue > 1 && levelDisplayTime >= time + fadeoutTime)
            showLevelUp = false;
    }

    @SideOnly(Side.CLIENT)
    private void renderRemainingItems(ScaledResolution resolution, float partTicks) {
        if (remainingTime > 0 && remainingDisplayStack != null) {
            int pos = maxRemainingTicks - remainingTime;
            Minecraft mc = Minecraft.getMinecraft();
            int x = resolution.getScaledWidth() / 2 + 10 + Math.max(0, pos - remainingLeaveTicks);
            int y = resolution.getScaledHeight() / 2;

            int start = maxRemainingTicks - remainingLeaveTicks;
            float alpha = remainingTime + partTicks > start ? 1F : (remainingTime + partTicks) / start;

            GlStateManager.disableAlpha();
            GlStateManager.disableBlend();
            GlStateManager.disableRescaleNormal();
            GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

            GlStateManager.color(1F, 1F, 1F, alpha);
            RenderHelper.enableGUIStandardItemLighting();
            int xp = x + (int) (16F * (1F - alpha));
            GlStateManager.translate(xp, y, 0F);
            GlStateManager.scale(alpha, 1F, 1F);
            mc.getRenderItem().renderItemAndEffectIntoGUI(remainingDisplayStack, 0, 0);
            GlStateManager.scale(1F / alpha, 1F, 1F);
            GlStateManager.translate(-xp, -y, 0F);
            RenderHelper.disableStandardItemLighting();
            GlStateManager.color(1F, 1F, 1F, 1F);
            GlStateManager.enableBlend();

            String text = TextFormatting.GREEN + remainingDisplayStack.getDisplayName();
            if (remainingCount >= 0) {
                int max = remainingDisplayStack.getMaxStackSize();
                int stacks = remainingCount / max;
                int rem = remainingCount % max;

                if (stacks == 0)
                    text = "" + remainingCount;
                else
                    text = remainingCount + " (" + TextFormatting.AQUA + stacks + TextFormatting.RESET + "*"
                            + TextFormatting.GRAY + max + TextFormatting.RESET + "+" + TextFormatting.YELLOW + rem
                            + TextFormatting.RESET + ")";
            } else if (remainingCount == -1)
                text = "\u221E";

            int color = 0x00FFFFFF | (int) (alpha * 0xFF) << 24;
            mc.fontRendererObj.drawStringWithShadow(text, x + 20, y + 6, color);

            GlStateManager.disableBlend();
            GlStateManager.enableAlpha();
        }
    }

    @SideOnly(Side.CLIENT)
    private void renderHUDItem(ScaledResolution resolution, float partTicks) {
        Minecraft mc = Minecraft.getMinecraft();
        ItemStack stack = mc.thePlayer.getActiveItemStack();
        if (stack != null && stack.getItem() != null && stack.getItem() instanceof IHUDItem)
            ((IHUDItem) stack.getItem()).drawHUD(resolution, partTicks, stack);
    }

    public static void setRemaining(ItemStack stack, int count) {
        HUDHandler.remainingDisplayStack = stack;
        HUDHandler.remainingCount = count;
        remainingTime = stack == null ? 0 : maxRemainingTicks;
    }

    public static void setRemaining(EntityPlayer player, ItemStack displayStack, Pattern pattern) {
        int count = 0;
        for (int i = 0; i < player.inventory.getSizeInventory(); i++) {
            ItemStack stack = player.inventory.getStackInSlot(i);
            if (stack != null && (pattern == null ? ItemStack.areItemsEqual(displayStack, stack)
                    : pattern.matcher(stack.getUnlocalizedName()).find()))
                count += stack.stackSize;
        }

        setRemaining(displayStack, count);
    }

    @SideOnly(Side.CLIENT)
    private static Consumer<Integer> generateCallback(final float percentile, final boolean shatter) {
        Minecraft mc = Minecraft.getMinecraft();
        return (Integer shader) -> {
            int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "percentile");
            int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
            int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");

            OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(psiBar).getGlTextureId());
            ARBShaderObjects.glUniform1iARB(imageUniform, 0);

            OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);

            GlStateManager.enableTexture2D();
            GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);

            GL11.glBindTexture(GL11.GL_TEXTURE_2D,
                    mc.renderEngine.getTexture(shatter ? psiBarShatter : psiBarMask).getGlTextureId());
            ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);

            ARBShaderObjects.glUniform1fARB(percentileUniform, percentile);
        };
    }

}