com.mtbs3d.minecrift.provider.MCController.java Source code

Java tutorial

Introduction

Here is the source code for com.mtbs3d.minecrift.provider.MCController.java

Source

/**
 * Copyright 2013 Mark Browning, StellaArtois
 * Licensed under the LGPL 3.0 or later (See LICENSE.md for details)
 */
package com.mtbs3d.minecrift.provider;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.mtbs3d.minecrift.api.PluginType;
import com.mtbs3d.minecrift.control.*;

import net.minecraft.client.Minecraft;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;

import com.mtbs3d.minecrift.api.BasePlugin;
import com.mtbs3d.minecrift.api.IBodyAimController;
import com.mtbs3d.minecrift.control.GuiScreenNavigator;
import com.mtbs3d.minecrift.settings.VRSettings;

public class MCController extends BasePlugin implements IBodyAimController {
    public static final Logger logger = LogManager.getLogger();
    JoystickAim joyAim;
    boolean hasControllers = false;
    ControlBinding nextBind = null;
    Field fieldCreated = null;

    HashMap<String, String> bindingSaves = new HashMap<String, String>();

    class BindingMap {
        HashMap<Pair<Integer, Boolean>, ControlBinding> axisBinds = new HashMap<Pair<Integer, Boolean>, ControlBinding>();
        HashMap<Integer, ControlBinding> buttonBinds = new HashMap<Integer, ControlBinding>();
        HashMap<ControlBinding, Pair<Integer, Boolean>> revAxisBinds = new HashMap<ControlBinding, Pair<Integer, Boolean>>();
        HashMap<ControlBinding, Integer> revButtonBinds = new HashMap<ControlBinding, Integer>();
        ControlBinding povXBindPos;
        ControlBinding povXBindNeg;
        ControlBinding povYBindPos;
        ControlBinding povYBindNeg;

        void bindAxis(ControlBinding nextBind, int index, boolean posVal, String axisName) {
            axisName = axisName.replace("axis", "").replace("Axis", "");
            Pair<Integer, Boolean> key = Pair.of(index, posVal);
            if (!nextBind.isBiAxis()) {
                if (axisBinds.get(key) == null) {
                    nextBind.bindTo(axisName + (posVal ? "+" : "-") + " axis");
                    axisBinds.put(key, nextBind);
                    revAxisBinds.put(nextBind, key);
                    nextBind.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    nextBind.setValid(false);
                }
            } else {
                Pair<Integer, Boolean> key2 = Pair.of(index, !posVal);
                if (axisBinds.get(key) == null && axisBinds.get(key2) == null) {
                    nextBind.bindTo(axisName + " axis");
                    axisBinds.put(key, nextBind);
                    axisBinds.put(key2, nextBind);
                    revAxisBinds.put(nextBind, key);
                    nextBind.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    nextBind.setValid(false);
                }
            }
            if (nextBind.isValid())
                bindingSaves.put(nextBind.key, String.format("a:%d:%s:%s", index, posVal ? "+" : "-", axisName));
        }

        void bindButton(ControlBinding nextBind, int index, String buttonName) {
            if (buttonBinds.get(index) == null) {
                nextBind.bindTo(buttonName + " button");
                buttonBinds.put(index, nextBind);
                revButtonBinds.put(nextBind, index);
                nextBind.setValid(true);
            } else {
                nextBind.bindTo("Conflict!");
                nextBind.setValid(false);
            }
            if (nextBind.isValid())
                bindingSaves.put(nextBind.key, String.format("b:%d:%s", index, buttonName));
        }

        void bindPovX(ControlBinding nextBind, boolean posVal) {
            if (posVal) {
                if (povXBindPos == null) {
                    nextBind.bindTo("POV X+");
                    povXBindPos = nextBind;
                    povXBindPos.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    povXBindPos.setValid(false);
                }
            } else {
                if (povXBindNeg == null) {
                    nextBind.bindTo("POV X-");
                    povXBindNeg = nextBind;
                    povXBindNeg.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    povXBindNeg.setValid(false);
                }
            }
            if (nextBind.isValid())
                bindingSaves.put(nextBind.key, String.format("px:%s", posVal ? "+" : "-"));
        }

        void bindPovY(ControlBinding nextBind, boolean posVal) {
            if (posVal) {
                if (povYBindPos == null) {
                    nextBind.bindTo("POV Y+");
                    povYBindPos = nextBind;
                    povYBindPos.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    povYBindPos.setValid(false);
                }
            } else {
                if (povYBindNeg == null) {
                    nextBind.bindTo("POV Y-");
                    povYBindNeg = nextBind;
                    povYBindNeg.setValid(true);
                } else {
                    nextBind.bindTo("Conflict!");
                    povYBindNeg.setValid(false);
                }
            }
            if (nextBind.isValid())
                bindingSaves.put(nextBind.key, String.format("py:%s", posVal ? "+" : "-"));
        }

        boolean bind(ControlBinding nextBind) {
            boolean bound = false;
            Controller cont = Controllers.getEventSource();
            String alreadyBound = "";

            //Unbind a value if it is being remapped
            int index = Controllers.getEventControlIndex();
            if (revAxisBinds.containsKey(nextBind)) {
                alreadyBound = cont.getAxisName(revAxisBinds.get(nextBind).getLeft()) + " axis";
                if (nextBind.isBiAxis()) {
                    int axis_index = revAxisBinds.get(nextBind).getKey();
                    axisBinds.remove(Pair.of(axis_index, true));
                    axisBinds.remove(Pair.of(axis_index, false));
                } else {
                    axisBinds.remove(revAxisBinds.get(nextBind));
                }
                revAxisBinds.remove(nextBind);
            }
            if (revButtonBinds.containsKey(nextBind)) {
                Integer button = revButtonBinds.get(nextBind);
                alreadyBound = cont.getButtonName(button) + " button";
                buttonBinds.remove(button);
                revButtonBinds.remove(nextBind);
            }
            if (povXBindPos == nextBind) {
                povXBindPos = null;
                alreadyBound = "POV X+";
            } else if (povYBindPos == nextBind) {
                povYBindPos = null;
                alreadyBound = "POV Y+";
            } else if (povXBindNeg == nextBind) {
                povXBindNeg = null;
                alreadyBound = "POV X-";
            } else if (povYBindNeg == nextBind) {
                povYBindNeg = null;
                alreadyBound = "POV Y-";
            }

            if (!alreadyBound.isEmpty())
                System.out.println(nextBind.getDescription() + " already bound to " + alreadyBound + ". Removing.");

            //Bind to value
            if (Controllers.isEventAxis()) {
                float joyVal = cont.getAxisValue(index);
                boolean posVal = joyVal > 0;
                if (Math.abs(joyVal) > 0.5f) {
                    bindAxis(nextBind, index, posVal, cont.getAxisName(index));
                    bound = true;
                }
            } else if (Controllers.isEventButton()) {
                if (cont.isButtonPressed(index)) {
                    bindButton(nextBind, index, cont.getButtonName(index));
                    bound = true;
                }
            } else if (Controllers.isEventPovX()) {
                if (cont.getPovX() != 0) {
                    bindPovX(nextBind, cont.getPovX() > 0);
                    bound = true;
                }
            } else if (Controllers.isEventPovY()) {
                if (cont.getPovY() != 0) {
                    bindPovY(nextBind, cont.getPovY() > 0);
                    bound = true;
                }
            }
            return bound;
        }

        void activate() {
            Controller cont = Controllers.getEventSource();
            int index = Controllers.getEventControlIndex();
            if (Controllers.isEventAxis()) {
                float joyVal = cont.getAxisValue(index);
                ControlBinding bindPos = axisBinds.get(Pair.of(index, true));
                ControlBinding bindNeg = axisBinds.get(Pair.of(index, false));
                if (bindPos == bindNeg) {
                    if (bindPos != null)
                        bindPos.setValue(joyVal);
                } else {
                    if (joyVal > 0) {
                        if (bindNeg != null)
                            bindNeg.setValue(0);
                        if (bindPos != null)
                            bindPos.setValue(joyVal);
                    } else {
                        if (bindPos != null)
                            bindPos.setValue(0);
                        if (bindNeg != null)
                            bindNeg.setValue(-joyVal);
                    }
                }
            } else if (Controllers.isEventButton()) {
                ControlBinding bind = buttonBinds.get(index);
                if (bind != null) {
                    bind.setState(cont.isButtonPressed(index));
                }
            } else if (Controllers.isEventPovX()) {
                if (cont.getPovX() > 0) {
                    if (povXBindPos != null)
                        povXBindPos.setState(true);
                } else if (cont.getPovX() < 0) {
                    if (povXBindNeg != null)
                        povXBindNeg.setState(true);
                } else {
                    if (povXBindPos != null)
                        povXBindPos.setState(false);
                    if (povXBindNeg != null)
                        povXBindNeg.setState(false);
                }
            } else if (Controllers.isEventPovY()) {
                if (cont.getPovY() > 0) {
                    if (povYBindPos != null)
                        povYBindPos.setState(true);
                } else if (cont.getPovY() < 0) {
                    if (povYBindNeg != null)
                        povYBindNeg.setState(true);
                } else {
                    if (povYBindPos != null)
                        povYBindPos.setState(false);
                    if (povYBindNeg != null)
                        povYBindNeg.setState(false);
                }
            }
        }
    }

    BindingMap ingame = new BindingMap();
    BindingMap GUI = new BindingMap();
    JoystickAim[] aimTypes = new JoystickAim[] { new JoystickAim(), new JoystickAimLoose(),
            new JoystickRecenterAim() };
    private Minecraft mc;
    private GuiScreenNavigator screenNavigator;
    private boolean loaded = false;

    public MCController() {
        super();
        mc = Minecraft.getMinecraft();
        System.out.println("Created Controller plugin");
        pluginID = "controller";
        pluginName = "Controller";
    }

    @Override
    public String getInitializationStatus() {
        return hasControllers ? "Ready." : "No Controllers found.";
    }

    @Override
    public String getVersion() {
        return "1.0";
    }

    @Override
    public boolean init(File nativeDir) {
        return init();
    }

    @Override
    public boolean init() {
        try {
            setCreated(false);
            Controllers.create();
            hasControllers = Controllers.getControllerCount() > 0;

            System.out.println("[Minecrift]Initialized controllers: " + getInitializationStatus());
        } catch (LWJGLException e) {
            e.printStackTrace();
        }
        return isInitialized();
    }

    public void setupControllerCreated() {
        try {
            if (fieldCreated == null) {
                fieldCreated = Controllers.class.getDeclaredField("created");
                fieldCreated.setAccessible(true);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setCreated(boolean created) {
        setupControllerCreated();
        if (fieldCreated != null) {
            try {
                fieldCreated.set(null, (Object) created);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean isInitialized() {
        return hasControllers;
    }

    @Override
    public void poll(float delta) {
        if (polledThisFrame)
            return;

        polledThisFrame = true;

        if (!loaded)
            loadBindings();
        JoystickAim.selectedJoystickMode = aimTypes[mc.vrSettings.joystickAimType];
        joyAim = JoystickAim.selectedJoystickMode;
        for (int c = 0; c < Controllers.getControllerCount(); c++) {
            Controller cont = Controllers.getController(c);
            for (int a = 0; a < cont.getAxisCount(); a++) {
                cont.setDeadZone(a, mc.vrSettings.joystickDeadzone);
            }
        }
        if (this.mc.currentScreen != null
                && (this.screenNavigator == null || this.screenNavigator.screen != this.mc.currentScreen))
            this.screenNavigator = new GuiScreenNavigator(this.mc.currentScreen);
        Controllers.poll();
        while (Controllers.next()) {
            if (nextBind != null) {
                boolean bound = false;
                if (nextBind.isGUI())
                    bound = GUI.bind(nextBind);
                else
                    bound = ingame.bind(nextBind);
                if (nextBind instanceof InventoryBinding || nextBind instanceof MenuBinding) //These are in both
                    GUI.bind(nextBind);

                if (bound) {
                    saveBindings();
                    nextBind.doneBinding();
                    nextBind = null;
                }
            } else if (mc.currentScreen == null) {
                ingame.activate();
            } else {
                GUI.activate();
            }
        }
        Controllers.clearEvents();

        // Update the aim / pitch
        if (JoystickAim.selectedJoystickMode != null)
            JoystickAim.selectedJoystickMode.update(1f);

        // Update gui cursor
        this.screenNavigator.guiCursor();
    }

    private void saveBindings() {
        File bindingsSave = new File(mc.mcDataDir, "options_controller.txt");
        PrintWriter bindingsWriter;
        try {
            bindingsWriter = new PrintWriter(new FileWriter(bindingsSave));
            for (Map.Entry<String, String> entry : bindingSaves.entrySet()) {
                bindingsWriter.println(entry.getKey() + ":" + entry.getValue());
            }
            bindingsWriter.close();
        } catch (IOException e) {
            logger.error("Failed to save controller bindings: " + e.getMessage());
        }
    }

    private void loadBinding(ControlBinding binding, BindingMap map, String[] bindingTokens) {
        if (bindingTokens[1].equals("a") && bindingTokens.length >= 5) {
            int index = Integer.parseInt(bindingTokens[2]);
            boolean posVal = bindingTokens[3].equals("+");
            map.bindAxis(binding, index, posVal, bindingTokens[4]);
        } else if (bindingTokens[1].equals("b") && bindingTokens.length >= 4) {
            int index = Integer.parseInt(bindingTokens[2]);
            map.bindButton(binding, index, bindingTokens[3]);
        } else if (bindingTokens[1].equals("px") && bindingTokens.length >= 3) {
            boolean posVal = bindingTokens[2].equals("+");
            map.bindPovX(binding, posVal);
        } else if (bindingTokens[1].equals("py") && bindingTokens.length >= 3) {
            boolean posVal = bindingTokens[2].equals("+");
            map.bindPovY(binding, posVal);
        }

    }

    private void loadBindings() {
        File bindingsSave = new File(mc.mcDataDir, "options_controller.txt");
        if (!bindingsSave.exists()) {
            //TODO: load a default binding?

        } else {
            try {
                BufferedReader bindingsReader = new BufferedReader(new FileReader(bindingsSave));
                String line;
                while ((line = bindingsReader.readLine()) != null) {
                    String[] bindingTokens = line.split(":");
                    if (bindingTokens.length > 1) {
                        String key = bindingTokens[0];
                        for (ControlBinding binding : ControlBinding.bindings) {
                            if (binding.key.equals(key)) {

                                if (binding.isGUI())
                                    loadBinding(binding, GUI, bindingTokens);
                                else
                                    loadBinding(binding, ingame, bindingTokens);

                                if (binding instanceof InventoryBinding || binding instanceof MenuBinding) //These are in both
                                    loadBinding(binding, GUI, bindingTokens);
                                break;
                            }
                        }
                    }
                }
                bindingsReader.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        loaded = true;
    }

    @Override
    public void destroy() {
        Controllers.destroy();
    }

    @Override
    public boolean isCalibrated(PluginType type) {
        return true;
    }

    @Override
    public void beginCalibration(PluginType type) {
    }

    @Override
    public void updateCalibration(PluginType type) {
    }

    @Override
    public String getCalibrationStep(PluginType type) {
        return "";
    }

    @Override
    public void eventNotification(int eventId) {
    }

    @Override
    public float getBodyYawDegrees() {
        return JoystickAim.getBodyYaw();
    }

    @Override
    public void setBodyYawDegrees(float yawOffset) {
        JoystickAim.setAimYawOffset(yawOffset);
    }

    @Override
    public float getBodyPitchDegrees() {
        return JoystickAim.getBodyPitch();
    }

    @Override
    public float getAimYaw() {
        return JoystickAim.getAimYaw();
    }

    @Override
    public float getAimPitch() {
        return JoystickAim.getAimPitch();
    }

    @Override
    public void mapBinding(ControlBinding binding) {
        nextBind = binding;
    }

    public void beginFrame() {
        beginFrame(0);
    }

    public void beginFrame(int frameIndex) {
        polledThisFrame = false;
    }

    public void endFrame() {
    }

    @Override
    public double ratchetingYawTransitionPercent() {
        if (joyAim == null)
            return -1d;

        return this.joyAim.getYawTransitionPercent();
    }

    @Override
    public double ratchetingPitchTransitionPercent() {
        if (joyAim == null)
            return -1d;

        return this.joyAim.getPitchTransitionPercent();
    }

    @Override
    public boolean initBodyAim() {
        return init();
    }
}