Java tutorial
/** * 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)); } } } }