com.rogue.simpleclient.SimpleClient.java Source code

Java tutorial

Introduction

Here is the source code for com.rogue.simpleclient.SimpleClient.java

Source

/*
 * Copyright (C) 2014 Spencer Alderman
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.rogue.simpleclient;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

/**
 * A simple class for launching authenticated Minecraft clients
 * <br /><br />
 * Made with MC release 1.7.9 in mind
 *
 * @since 1.0.0
 * @author 1Rogue
 * @version 1.0.0
 */
public final class SimpleClient {

    /** The minecraft version to launch */
    private final String version;
    /** The url for Mojang's authentication server */
    private final URL url = new URL("https://authserver.mojang.com/authenticate");
    /** The application data folder that contains minecraft */
    private final File appData;
    /** The minecraft directory */
    private final File minecraftDir;
    /** The game version directory */
    private final File gameDir;
    /** The natives folder for the version in use */
    private final File natives;
    /** Random client UUID used for two-factor client auth */
    private final UUID uuid = UUID.randomUUID();
    /** The response payload from the authentication server */
    private JSONObject response;

    /**
     * Constructs and authenticates a new client instance. Will ask for input
     * from a supplied {@link Scanner} source.
     *
     * @since 1.0.0
     * @version 1.0.0
     *
     * @param input The {@link Scanner} to read input from
     * @throws IOException Any type of communications failure with Mojang
     */
    public SimpleClient(Scanner input) throws IOException {
        System.out.print("What version are you launching (e.g. '1.7.9')?: ");
        this.version = input.nextLine();
        System.out.print("What is the full path for your application data folder containing minecraft?: ");
        this.appData = new File(input.nextLine());
        this.minecraftDir = new File(this.appData.getAbsoluteFile(), ".minecraft" + File.separatorChar);
        this.gameDir = new File(minecraftDir, "versions" + File.separator + this.version + File.separatorChar);
        this.natives = new File(gameDir, "natives" + File.separatorChar);
        System.out.print("Username: ");
        String username = input.nextLine();
        System.out.print("Password: ");
        this.connect(username, input.nextLine());
    }

    /**
     * Constructs and authenticates a new client instance. Will ask for input
     * from a supplied {@link Scanner} source.
     *
     * @since 1.0.0
     * @version 1.0.0
     *
     * @param version The minecraft version to use
     * @param username The username/email to authenticate with
     * @param password The password to authenticate with
     * @param appData The location of the application data folder containing MC
     * @throws IOException Any type of communications failure with Mojang
     */
    public SimpleClient(String version, String username, String password, File appData) throws IOException {
        this.version = version;
        this.appData = appData;
        this.minecraftDir = new File(this.appData.getAbsoluteFile(), ".minecraft" + File.separatorChar);
        this.gameDir = new File(minecraftDir, "versions" + File.separator + this.version + File.separatorChar);
        this.natives = new File(gameDir, "natives" + File.separatorChar);
        this.connect(username, password);
    }

    /**
     * Connects to and authenticates with the Mojang auth server
     *
     * @since 1.0.0
     * @version 1.0.0
     *
     * @param username The username/email to use
     * @param password The password to use
     * @throws IOException Incorrect credentials or some other connection error
     */
    private void connect(String username, String password) throws IOException {
        HttpURLConnection http = (HttpURLConnection) this.url.openConnection();
        http.setRequestMethod("POST");
        http.setRequestProperty("Content-Type", "application/json");
        http.setUseCaches(false);
        http.setDoOutput(true);
        try (DataOutputStream wr = new DataOutputStream(http.getOutputStream())) {
            wr.writeBytes(this.getPayload(username, password).toJSONString());
            wr.flush();
        }
        StringBuilder sb = new StringBuilder();
        try (InputStreamReader is = new InputStreamReader(http.getInputStream());
                BufferedReader br = new BufferedReader(is)) {
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        }
        this.response = (JSONObject) JSONValue.parse(sb.toString());
    }

    /**
     * Constructs the JSON payload to send to Mojang's authentication server
     *
     * @since 1.0.0
     * @version 1.0.0
     *
     * @param username The username to use
     * @param password The password to use
     * @return A JSON payload for deployment to a webserver
     */
    private JSONObject getPayload(String username, String password) {
        JSONObject back = new JSONObject();
        JSONObject client = new JSONObject();
        client.put("name", "Minecraft");
        client.put("version", 1);
        back.put("agent", client);
        back.put("username", username);
        back.put("password", password);
        back.put("clientToken", this.uuid.toString());
        return back;
    }

    /**
     * Opens the minecraft client.
     *
     * @since 1.0.0
     * @version 1.0.0
     *
     * @throws SecurityException Lack of permissions to execute a process
     * @throws IOException Unobserved I/O Error
     */
    public void openMinecraft() throws SecurityException, IOException {
        MCProc mc = new MCProc(this.natives, this.minecraftDir, this.gameDir, this.version);
        JSONObject prof = (JSONObject) this.response.get("selectedProfile");
        mc.appendTag("username", (String) prof.get("name"), "=");
        mc.appendTag("version", this.version, " ");
        mc.appendTag("gameDir", this.minecraftDir.getAbsolutePath(), " ");
        mc.appendTag("assetsDir", new File(this.minecraftDir, "assets").getAbsolutePath(), " ");
        mc.appendTag("userProperties", "{}", " ");
        mc.appendTag("accessToken", (String) this.response.get("accessToken"), " ");
        mc.appendTag("uuid", (String) prof.get("id"), " ");
        try {
            ProcessBuilder pb = new ProcessBuilder();
            pb.redirectErrorStream(true);
            pb.command(mc.getExec());
            Process p = Runtime.getRuntime().exec(mc.getExec());
            p.waitFor();
            try (BufferedReader bf = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
                String line;
                while ((line = bf.readLine()) != null) {
                    System.out.println(line);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Helper class holding information about the execution process of the
     * Minecraft client.
     *
     * @since 1.0.0
     * @author 1Rogue
     * @version 1.0.0
     */
    private static class MCProc {

        /** Whether or not to print to console */
        private final boolean output = false;
        /** The raw, unfiltered executable statement */
        private String exec = "java -Djava.library.path=%NATIVES% " + "-cp %LIBS%%GAMEDIR%" + File.separator
                + "%VERSION%.jar " + "net.minecraft.client.main.Main";

        /**
         * {@link MCProc} constructor
         * 
         * @since 1.0.0
         * @version 1.0.0
         * 
         * @param natives The natives folder location
         * @param mcdir Minecraft main folder location
         * @param gamedir The version directory
         * @param version The version of minecraft to use
         */
        public MCProc(File natives, File mcdir, File gamedir, String version) {
            this.out("exec: " + this.exec);
            this.exec = this.exec.replaceAll("\\%LIBS\\%",
                    Matcher.quoteReplacement(Library.getLibraryString(version)));
            this.out("exec: " + this.exec);
            this.exec = this.exec.replaceAll("\\%NATIVES\\%", Matcher.quoteReplacement(natives.getAbsolutePath()));
            this.out("exec: " + this.exec);
            this.exec = this.exec.replaceAll("\\%GAMEDIR\\%", Matcher.quoteReplacement(gamedir.getAbsolutePath()));
            this.out("exec: " + this.exec);
            this.exec = this.exec.replaceAll("\\%MCDIR\\%", Matcher.quoteReplacement(mcdir.getAbsolutePath()));
            this.out("exec: " + this.exec);
            this.exec = this.exec.replaceAll("\\%VERSION\\%", Matcher.quoteReplacement(version));
            this.out("exec: " + this.exec);
        }

        /**
         * Appends a varargs argument for the minecraft client
         * 
         * @since 1.0.0
         * @version 1.0.0
         * 
         * @param tag The tag key
         * @param value The tag value
         * @param delimiter Inbetween spacing, since some arguments differ
         */
        public void appendTag(String tag, String value, String delimiter) {
            this.exec += " --" + tag + delimiter + value;
        }

        /**
         * Returns an executable statement for {@link Runtime#exec(java.lang.String)}
         * 
         * @since 1.0.0
         * @version 1.0.0
         * 
         * @return A string representing an executable command for minecraft
         */
        public String getExec() {
            return this.exec;
        }

        /**
         * Returns a human-readable form of the executable command, new-line
         * delimited by a carat for use on a windows command-line environment
         * 
         * @since 1.0.0
         * @version 1.0.0
         * 
         * @return A readable executable statement
         */
        public String getReadableExec() {
            return this.getExec().replaceAll(Pattern.quote(";"), ";^\n");
        }

        /**
         * Prints out a string to stdout. Can be disabled
         * 
         * @since 1.0.0
         * @version 1.0.0
         * 
         * @param out The string to print
         */
        private void out(String out) {
            if (this.output) {
                System.out.println(out);
            }
        }

    }

    private static enum Library {
        APACHE_COMMONS_3("org\\apache\\commons\\commons-lang3\\%s\\commons-lang3-%s", map("1.7.9", "3.1"),
                map("1.8.3", "3.3.2")), APACHE_COMMONS_COMPRESS(
                        "org\\apache\\commons\\commons-compress\\%s\\commons-compress-%s",
                        map("1.8.3", "1.8.1")), ARGO("argo\\argo\\%s\\argo-%s",
                                map("1.7.9", "2.25_fixed")), AUTHLIB("com\\mojang\\authlib\\%s\\authlib-%s",
                                        map("1.7.9", "1.5.13"), map("1.8.3", "1.5.17")), CODEC_JORBIS(
                                                "com\\paulscode\\codecjorbis\\%s\\codecjorbis-%s",
                                                map("1.7.9", "20101023"), map("1.8.3", "20101023")), CODEC_WAV(
                                                        "com\\paulscode\\codecwav\\%s\\codecwav-%s",
                                                        map("1.7.9", "20101023"),
                                                        map("1.8.3", "20101023")), CODEC_COMMONS(
                                                                "commons-codec\\commons-codec\\%s\\commons-codec-%s",
                                                                map("1.7.9", "1.9"), map("1.8.3", "1.9")), GSON(
                                                                        "com\\google\\code\\gson\\gson\\%s\\gson-%s",
                                                                        map("1.7.9", "2.2.4"),
                                                                        map("1.8.3", "2.2.4")), GUAVA(
                                                                                "com\\google\\guava\\guava\\%s\\guava-%s",
                                                                                map("1.7.9", "15.0"),
                                                                                map("1.8.3", "17.0")), HTTP_CORE(
                                                                                        "org\\apache\\httpcomponents\\httpcore\\%s\\httpcore-%s",
                                                                                        map("1.8.3",
                                                                                                "4.3.2")), HTTP_CLIENT(
                                                                                                        "org\\apache\\httpcomponents\\httpclient\\%s\\httpclient-%s",
                                                                                                        map("1.8.3",
                                                                                                                "4.3.3")), ICU4J(
                                                                                                                        "com\\ibm\\icu\\icu4j-core-mojang\\%s\\icu4j-core-mojang-51.2",
                                                                                                                        map("1.7.9",
                                                                                                                                "51.2"),
                                                                                                                        map("1.8.3",
                                                                                                                                "51.2")), IO_COMMONS(
                                                                                                                                        "commons-io\\commons-io\\%s\\commons-io-%s",
                                                                                                                                        map("1.7.9",
                                                                                                                                                "2.4"),
                                                                                                                                        map("1.8.3",
                                                                                                                                                "2.4")), JINPUT(
                                                                                                                                                        "net\\java\\jinput\\jinput\\%s\\jinput-%s",
                                                                                                                                                        map("1.7.9",
                                                                                                                                                                "2.0.5"),
                                                                                                                                                        map("1.8.3",
                                                                                                                                                                "2.0.5")), JINPUT_PLATFORM(
                                                                                                                                                                        "net\\java\\jinput\\jinput-platform\\%s\\jinput-platform-%s-natives-windows",
                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                "2.0.5"),
                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                "2.0.5")), JNA(
                                                                                                                                                                                        "net\\java\\dev\\jna\\jna\\%s\\jna-%s",
                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                "3.4.0")), JNA_PLATFORM(
                                                                                                                                                                                                        "net\\java\\dev\\jna\\platform\\%s\\platform-%s",
                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                "3.4.0")), JOPT_SIMPLE(
                                                                                                                                                                                                                        "net\\sf\\jopt-simple\\jopt-simple\\%s\\jopt-simple-%s",
                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                "4.5"),
                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                "4.6")), JUTILS(
                                                                                                                                                                                                                                        "net\\java\\jutils\\jutils\\%s\\jutils-%s",
                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                "1.0.0"),
                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                "1.0.0")), LIBRARY_JAVASOUND(
                                                                                                                                                                                                                                                        "libraries\\com\\paulscode\\libraryjavasound\\%s\\libraryjavasound-%s",
                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                "20101123"),
                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                "20101123")), LIBRARY_LWJGL_OPENAL(
                                                                                                                                                                                                                                                                        "com\\paulscode\\librarylwjglopenal\\%s\\librarylwjglopenal-%s",
                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                "20100824"),
                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                "20100824")), LOG4J_API(
                                                                                                                                                                                                                                                                                        "org\\apache\\logging\\log4j\\log4j-api\\%s\\log4j-api-%s",
                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                "2.0-beta9"),
                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                "2.0-beta9")), LOG4J_CORE(
                                                                                                                                                                                                                                                                                                        "org\\apache\\logging\\log4j\\log4j-core\\%s\\log4j-core-%s",
                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                "2.0-beta9"),
                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                "2.0-beta9")), LOGGING_COMMONS(
                                                                                                                                                                                                                                                                                                                        "commons-logging\\commons-logging\\%s\\commons-logging-%s",
                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                "1.1.3")), LWJGL(
                                                                                                                                                                                                                                                                                                                                        "libraries\\org\\lwjgl\\lwjgl\\lwjgl\\%s\\lwjgl-%s",
                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                "2.9.1"),
                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                "2.9.4-nightly-20150209")), LWJGL_UTIL(
                                                                                                                                                                                                                                                                                                                                                        "org\\lwjgl\\lwjgl\\lwjgl_util\\%s\\lwjgl_util-%s",
                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                "2.9.1"),
                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                "2.9.4-nightly-20150209")), LWJGL_PLATFORM(
                                                                                                                                                                                                                                                                                                                                                                        "org\\lwjgl\\lwjgl\\lwjgl-platform\\%s\\lwjgl-platform-%s-natives-windows",
                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                "2.9.1"),
                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                "2.9.4-nightly-20150209")), NETTY_ALL(
                                                                                                                                                                                                                                                                                                                                                                                        "io\\netty\\netty-all\\%s\\netty-all-%s",
                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                "4.0.10.Final"),
                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                "4.0.23.Final")), OSHI(
                                                                                                                                                                                                                                                                                                                                                                                                        "oshi-project\\oshi-core\\%s\\oshi-core-%s",
                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                "1.1")), REALMS(
                                                                                                                                                                                                                                                                                                                                                                                                                        "com\\mojang\\realms\\%s\\realms-%s",
                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                                "1.7.13")), SOUND_SYSTEM(
                                                                                                                                                                                                                                                                                                                                                                                                                                        "com\\paulscode\\soundsystem\\%s\\soundsystem-%s",
                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                "20120107"),
                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                                                "20120107")), TROVE4J(
                                                                                                                                                                                                                                                                                                                                                                                                                                                        "net\\sf\\trove4j\\trove4j\\%s\\trove4j-%s",
                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                "3.0.3")), TWITCH(
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "tv\\twitch\\twitch\\%s\\twitch-%s",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "5.16"),
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "6.5")), TWITCH_PLATFORM(
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "tv\\twitch\\twitch-platform\\%s\\twitch-%s-natives-windows-"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                + arch(),
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "5.16"),
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "6.5")), TWITCH_EXTERNAL_PLATFORM(
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "tv\\twitch\\twitch-external-platform\\%s\\twitch-%s-natives-windows-"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                + arch(),
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "5.16"),
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.8.3",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "6.5")), VECTOR_MATH(
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "java3d\\vecmath\\%s\\vecmath-%s",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        map("1.7.9",
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "1.3.1")),;

        private final String format;
        private final Map<String, String> vers;

        @SafeVarargs
        private Library(String format, Mapping<String, String>... vers) {
            this.format = "%%MCDIR%%" + File.separator + "libraries" + File.separator
                    + format.replace("\\", File.separator) + ".jar;";
            this.vers = new HashMap<>(vers.length);
            for (Mapping<String, String> val : vers) {
                this.vers.put(val.getKey(), val.getValue());
            }
        }

        public Map<String, String> getLibraryVersionMappings() {
            return Collections.unmodifiableMap(this.vers);
        }

        public static Set<String> getMappedVersions(String version) {
            Set<String> back = new HashSet<>();
            for (Library lib : Library.values()) {
                if (lib.vers.containsKey(version)) {
                    String repl = lib.vers.get(version);
                    back.add(String.format(lib.format, repl, repl));
                }
            }
            return back;
        }

        public static String getLibraryString(String version) {
            StringBuilder sb = new StringBuilder();
            Library.getMappedVersions(version).forEach(sb::append);
            return sb.toString();
        }

        private static Mapping<String, String> map(String key, String val) {
            return new Mapping<>(key, val);
        }

        private static String arch() {
            boolean mojangUsesJVMArch = true;
            if (mojangUsesJVMArch) {
                return System.getProperty("os.arch").endsWith("64") ? "64" : "32";
            } else {
                String arch = System.getenv("PROCESSOR_ARCHITECTURE");
                String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
                return arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64") ? "64" : "32";
            }
        }
    }

    private static class Mapping<K, V> implements Map.Entry<K, V> {

        private final K key;
        private V value;

        public Mapping(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return this.key;
        }

        @Override
        public V getValue() {
            return this.value;
        }

        @Override
        public V setValue(V value) {
            V old = this.value;
            this.value = value;
            return old;
        }
    }

}