com.mtbs3d.minecrift.control.GuiScreenNaviator.java Source code

Java tutorial

Introduction

Here is the source code for com.mtbs3d.minecrift.control.GuiScreenNaviator.java

Source

/**
 * Copyright 2013 Mark Browning, StellaArtois
 * Licensed under the LGPL 3.0 or later (See LICENSE.md for details)
 * 
 * Contains code from Minecraft, copyright Mojang AB
 */
package com.mtbs3d.minecrift.control;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiContainer;
import net.minecraft.src.GuiIngameMenu;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.GuiSlot;
import net.minecraft.src.Minecraft;
import net.minecraft.src.Slot;

import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;

public class GuiScreenNaviator {
    public ArrayList<Pair<Integer, Integer>> points = new ArrayList<Pair<Integer, Integer>>();
    private GuiSlot slot;
    private int slotIndex = -1;
    private boolean onSlot = false;
    public GuiScreen screen;
    private GuiScreen parentScreen;
    private Minecraft mc;

    private Pair<Integer, Integer> curPoint;
    private static Field guiLeft = null;
    private static Field guiTop = null;
    private static Field keyDownField = null;

    private boolean selectDepressed = false;
    private boolean altselectDepressed = false;
    private boolean shiftDepressed;

    static final int AXIS_PREFERENCE = 5;

    private static GuiScreenNaviator nav;

    static abstract class GuiControlBinding extends ControlBinding {

        public GuiControlBinding(String desc) {
            super("GUI " + desc, "gui." + desc);
        }

        boolean floatActive = false;

        @Override
        public boolean isGUI() {
            return true;
        };

        @Override
        public void setValue(float value) {
            if (Math.abs(value) > 0.5) {
                if (!floatActive)
                    setState(true);
                floatActive = true;
            } else {
                setState(false);
                floatActive = false;
            }
        }
    }

    static class GuiUpBinding extends GuiControlBinding {

        public GuiUpBinding() {
            super("Up");
        }

        @Override
        public void setState(boolean state) {
            if (state)
                nav.up();
        }
    }

    static class GuiDownBinding extends GuiControlBinding {

        public GuiDownBinding() {
            super("Down");
        }

        @Override
        public void setState(boolean state) {
            if (state)
                nav.down();
        }
    }

    static class GuiRightBinding extends GuiControlBinding {

        public GuiRightBinding() {
            super("Right");
        }

        @Override
        public void setState(boolean state) {
            if (state)
                nav.right();
        }
    }

    static class GuiLeftBinding extends GuiControlBinding {

        public GuiLeftBinding() {
            super("Left");
        }

        @Override
        public void setState(boolean state) {
            if (state)
                nav.left();
        }
    }

    static class GuiSelectBinding extends GuiControlBinding {

        public GuiSelectBinding() {
            super("Select");
        }

        @Override
        public void setState(boolean state) {
            nav.select(state);
        }
    }

    static class GuiAltSelectBinding extends GuiControlBinding {

        public GuiAltSelectBinding() {
            super("Alt. Select");
        }

        @Override
        public void setState(boolean state) {
            nav.altselect(state);
        }
    }

    static class GuiBackBinding extends GuiControlBinding {

        public GuiBackBinding() {
            super("Back");
        }

        @Override
        public void setState(boolean state) {
            if (state)
                nav.back();
        }
    }

    static class GuiShiftBinding extends GuiControlBinding {

        public GuiShiftBinding() {
            super("Shift");
        }

        @Override
        public void setState(boolean state) {
            nav.shift(state);
        }
    }

    public GuiScreenNaviator(GuiScreen screen) {
        mc = Minecraft.getMinecraft();
        nav = this;

        if (guiLeft == null) {
            try {
                keyDownField = Keyboard.class.getDeclaredField("keyDownBuffer");
                keyDownField.setAccessible(true);
                guiLeft = GuiContainer.class.getDeclaredField("guiLeft");
                guiTop = GuiContainer.class.getDeclaredField("guiTop");
                System.out.println("[Minecrift]GuiScreenNavigator: Reflected guiLeft/guiTop");
            } catch (NoSuchFieldException e) {
                try {
                    guiLeft = GuiContainer.class.getDeclaredField("p"); //obfuscated name
                    guiTop = GuiContainer.class.getDeclaredField("q"); //obfuscated name
                    System.out.println("[Minecrift]GuiScreenNavigator: Reflected obfuscated guiLeft/guiTop (p/q)");
                } catch (NoSuchFieldException e1) {
                    System.out.println(
                            "[Minecrift]GuiScreenNavigator: Couldn't get guiLeft/guiTop via reflection! Joystick navigation of inventories may be inaccurate.");
                }
                ;
            }
            if (guiLeft != null)
                guiLeft.setAccessible(true);
            if (guiTop != null)
                guiTop.setAccessible(true);
        }

        this.screen = screen;
        for (Field field : screen.getClass().getDeclaredFields()) {
            if (field.getType().getSuperclass() == GuiSlot.class) {
                field.setAccessible(true);
                try {
                    slot = (GuiSlot) field.get(screen);
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        Class<?> screenclazz = screen.getClass();
        parentScreen = null;
        while (parentScreen == null && screenclazz != null) {
            for (Field field : screenclazz.getDeclaredFields()) {
                if (GuiScreen.class.isAssignableFrom(field.getType())) {
                    field.setAccessible(true);
                    try {
                        //Assume the first declared GuiScreen object is the "parent"
                        //Might not always work.
                        parentScreen = (GuiScreen) field.get(screen);
                        break;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            screenclazz = screenclazz.getSuperclass();
        }
        curPoint = Pair.of(Mouse.getX() * screen.width / this.mc.displayWidth,
                screen.height - Mouse.getY() * screen.height / this.mc.displayHeight - 1);

        if (slot != null && slot.publicGetSize() > 0) {
            slotIndex = 0;
            slot.select(0, false);
            onSlot = true;
        }
    }

    public void back() {
        if (screen instanceof GuiIngameMenu)
            mc.displayGuiScreen(null);
        else if (parentScreen != null)
            mc.displayGuiScreen(parentScreen);

    }

    public void select(boolean state) {
        if (state && onSlot) {
            slot.select(slotIndex, true);
            return;
        }
        selectDepressed = state;
        if (curPoint != null) {
            if (keyDownField != null)
                try {
                    ((ByteBuffer) keyDownField.get(null)).put(Keyboard.KEY_RSHIFT, (byte) (shiftDepressed ? 1 : 0));
                } catch (Exception e) {
                }
            if (state)
                mc.currentScreen.mouseGuiDown(curPoint.getLeft(), curPoint.getRight(), 0); //Left click
            else
                mc.currentScreen.mouseGuiUp(curPoint.getLeft(), curPoint.getRight(), 0); //Left click
        }
    }

    public void altselect(boolean state) {
        altselectDepressed = state;
        if (curPoint != null) {
            if (keyDownField != null)
                try {
                    ((ByteBuffer) keyDownField.get(null)).put(Keyboard.KEY_RSHIFT, (byte) (shiftDepressed ? 1 : 0));
                } catch (Exception e) {
                }
            if (state)
                mc.currentScreen.mouseGuiDown(curPoint.getLeft(), curPoint.getRight(), 1); //Right click
            else
                mc.currentScreen.mouseGuiUp(curPoint.getLeft(), curPoint.getRight(), 1); //Right click
        }
    }

    public void shift(boolean state) {
        shiftDepressed = state;
    }

    private float dist(Pair<Integer, Integer> a, Pair<Integer, Integer> b, float xScale, float yScale) {
        float x = xScale * (a.getLeft() - b.getLeft());
        float y = yScale * (a.getRight() - b.getRight());
        return (float) Math.sqrt(x * x + y * y);
    }

    public void left() {
        onSlot = false;
        parsePoints();
        if (curPoint != null) {
            Pair<Integer, Integer> nextBest = null;
            for (Pair<Integer, Integer> point : points) {
                if (point.getLeft() < curPoint.getLeft()) {
                    if (nextBest == null || dist(nextBest, curPoint, 1, AXIS_PREFERENCE) > dist(point, curPoint, 1,
                            AXIS_PREFERENCE))
                        nextBest = point;
                }
            }
            if (nextBest != null) {
                mc.currentScreen.mouseGuiDrag(curPoint.getLeft(), curPoint.getRight());
                curPoint = nextBest;
                mouseto();
            }
        }
    }

    public void right() {
        onSlot = false;
        parsePoints();
        if (curPoint != null) {
            Pair<Integer, Integer> nextBest = null;
            for (Pair<Integer, Integer> point : points) {
                if (point.getLeft() > curPoint.getLeft()) {
                    if (nextBest == null || dist(nextBest, curPoint, 1, AXIS_PREFERENCE) > dist(point, curPoint, 1,
                            AXIS_PREFERENCE))
                        nextBest = point;
                }
            }
            if (nextBest != null) {
                mc.currentScreen.mouseGuiDrag(curPoint.getLeft(), curPoint.getRight());
                curPoint = nextBest;
                mouseto();
            }
        }
    }

    public void down() {
        if (onSlot && slot != null && slotIndex != slot.publicGetSize() - 1) {
            slotIndex++;
            int slotY = slot.select(slotIndex, false);
            curPoint = Pair.of(screen.width / 2, slotY);
            mouseto();
            return;
        }
        onSlot = false;
        parsePoints();
        if (curPoint != null) {
            Pair<Integer, Integer> nextBest = null;
            for (Pair<Integer, Integer> point : points) {
                if (point.getRight() > curPoint.getRight()) {
                    if (nextBest == null || dist(nextBest, curPoint, AXIS_PREFERENCE, 1) > dist(point, curPoint,
                            AXIS_PREFERENCE, 1))
                        nextBest = point;
                }
            }
            if (nextBest != null) {
                mc.currentScreen.mouseGuiDrag(curPoint.getLeft(), curPoint.getRight());
                curPoint = nextBest;
                mouseto();
            }
        }
    }

    public void up() {
        parsePoints();
        if (curPoint != null) {
            Pair<Integer, Integer> nextBest = null;
            for (Pair<Integer, Integer> point : points) {
                if (point.getRight() < curPoint.getRight()) {
                    if (nextBest == null || dist(nextBest, curPoint, AXIS_PREFERENCE, 1) > dist(point, curPoint,
                            AXIS_PREFERENCE, 1))
                        nextBest = point;
                }
            }
            if (nextBest != null) {

                mc.currentScreen.mouseGuiDrag(curPoint.getLeft(), curPoint.getRight());
                curPoint = nextBest;
                mouseto();
                onSlot = false;
            } else if (slot != null) {
                if (onSlot && slotIndex != 0)
                    slotIndex--;
                int slotY = slot.select(slotIndex, false);
                curPoint = Pair.of(screen.width / 2, slotY);
                mouseto();
                onSlot = true;
            }
        }

    }

    private void mouseto() {
        int mouseGUIX = curPoint.getLeft();
        int mouseGUIY = curPoint.getRight();

        int mouseScreenX = (int) (mouseGUIX * mc.displayWidth / (float) mc.currentScreen.width);
        int mouseScreenY = (int) (mc.displayHeight / (float) mc.currentScreen.height
                * (mc.currentScreen.height - mouseGUIY - 1));
        Mouse.setCursorPosition(mouseScreenX, mouseScreenY);

        int mouseFBX = (int) (mouseScreenX * mc.displayFBWidth / (float) mc.displayWidth);
        int mouseFBY = (int) (mouseScreenY * mc.displayFBHeight / (float) mc.displayHeight);
        mc.resetMousePos(mouseFBX, mouseFBY);

        if (altselectDepressed || selectDepressed) {
            if (keyDownField != null)
                try {
                    ((ByteBuffer) keyDownField.get(null)).put(Keyboard.KEY_RSHIFT, (byte) (shiftDepressed ? 1 : 0));
                } catch (Exception e) {
                }
            mc.currentScreen.mouseGuiDrag(mouseGUIX, mouseGUIY);
        }
    }

    @SuppressWarnings("unchecked")
    protected void parsePoints() {
        points.clear();
        for (GuiButton button : screen.buttonList) {
            if (button.drawButton)
                points.add(Pair.of(button.xPosition + 5, button.yPosition + 5));
        }
        if (screen instanceof GuiContainer) {
            GuiContainer container = (GuiContainer) screen;
            int xOffset = 125; //These are the offsets for at least the inventory screen and chest
            int yOffset = 48;
            if (guiLeft != null) {
                try {
                    xOffset = guiLeft.getInt(container);
                    yOffset = guiTop.getInt(container);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (Slot slot : (List<Slot>) container.inventorySlots.inventorySlots) {
                points.add(Pair.of(xOffset + slot.xDisplayPosition + 8, yOffset + slot.yDisplayPosition + 8));
            }
        }
    }
}