me.bigteddy98.mcproxy.Main.java Source code

Java tutorial

Introduction

Here is the source code for me.bigteddy98.mcproxy.Main.java

Source

/* 
 * MCProxy
 * Copyright (C) 2014 Sander Gielisse
 *
 *     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 me.bigteddy98.mcproxy;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ThreadFactory;

import me.bigteddy98.mcproxy.protocol.ClientboundConnectionInitializer;

public class Main {

    public static final String NAME = "MCProxy";
    public static final String VERSION = "0.0.1";
    public static final String PROTOCOL_VERSION = "1.8";
    public static final int EXCEPTED_TICK_RATE = 20;
    public static final int EXCEPTED_SLEEP_TIME = 1000 / EXCEPTED_TICK_RATE;
    public static final int CANT_KEEP_UP_TIMEOUT = -10000;
    public static final int MAX_NETTY_BOSS_THREADS = 4;
    public static final int MAX_NETTY_WORKER_THREADS = 8;
    public static final int MAX_SLEEP = 100;
    public static final int DEFAULT_PROTOCOL = 47;
    public static final String AUTHOR = "Sander Gielisse || BigTeddy98";

    public Process serverProcess;
    public PrintWriter processPrintWriter;
    private final String[] processBuilder;
    private final int fromPort;
    private final int toPort;
    private final DataManager dataManager = new DataManager();
    private static Main instance;

    public Main(String[] processBuilder) {
        instance = this;
        this.fromPort = 25566;
        this.toPort = 25565;
        this.processBuilder = processBuilder;
    }

    public static Main getInstance() {
        return instance;
    }

    public DataManager getDataManager() {
        return this.dataManager;
    }

    public void executeCommand(String command) {
        this.processPrintWriter.println(command);
        this.processPrintWriter.flush();
    }

    public void run() throws Exception {
        ProxyLogger.info("Starting " + NAME + " version " + VERSION + " developed by " + AUTHOR + "!");
        ProxyLogger.info(
                "Starting server process using commandline " + Arrays.asList(processBuilder).toString() + "...");
        ProcessBuilder builder = new ProcessBuilder(processBuilder);
        builder.redirectErrorStream(true);
        this.serverProcess = builder.start();
        this.processPrintWriter = new PrintWriter(this.serverProcess.getOutputStream());
        ProxyLogger.info("Server process started.");

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

            @Override
            public void run() {
                serverProcess.destroy();
            }
        }));

        new Thread(new Runnable() {

            @Override
            public void run() {
                try (InputStream r = serverProcess.getInputStream()) {
                    StringBuilder tmp = new StringBuilder();
                    byte[] consoleOutput = new byte[1024];
                    int read;
                    while ((read = r.read(consoleOutput)) != -1) {
                        String consoleLog = new String(consoleOutput, 0, read);
                        String[] c = consoleLog.split("\n", -1);
                        if (c.length != 0) {
                            if (c.length == 1) {
                                tmp.append(c[0]);
                            } else {
                                for (int i = 0; i < c.length - 1; i++) {
                                    tmp.append(c[i]);
                                    ProxyLogger.info(tmp.toString());
                                    tmp.setLength(0);
                                }
                                tmp.append(c[c.length - 1]);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                ProxyLogger.warn("Server thread ended!");
                System.exit(0);
            }
        }, "Server Output Reader").start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                try (Scanner in = new Scanner(System.in)) {
                    while (in.hasNextLine()) {
                        String newLine = in.nextLine();
                        executeCommand(newLine);
                    }
                }
                ProxyLogger.warn("COMMAND LOOP ENDED, this shouldn't happen!");
            }
        }, "CommandReader").start();

        final ThreadGroup nettyListeners = new ThreadGroup(Thread.currentThread().getThreadGroup(),
                "Netty Listeners");
        new Thread(nettyListeners, new Runnable() {

            @Override
            public void run() {
                ProxyLogger.info("Started Netty Server at port " + fromPort + "...");
                final ThreadGroup group = new ThreadGroup(nettyListeners, "Listener-" + toPort);
                EventLoopGroup bossGroup = new NioEventLoopGroup(MAX_NETTY_BOSS_THREADS, new ThreadFactory() {

                    private int threadCount = 0;
                    private String newName = group.getName() + "\\boss";

                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(group, r, newName + "\\" + threadCount++);
                        t.setPriority(Thread.NORM_PRIORITY - 1);
                        t.setDaemon(true);
                        return t;
                    }
                });
                EventLoopGroup workerGroup = new NioEventLoopGroup(MAX_NETTY_WORKER_THREADS, new ThreadFactory() {

                    private int threadCount = 0;
                    private String newName = group.getName() + "\\worker";

                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(group, r, newName + "\\" + threadCount++);
                        t.setPriority(Thread.NORM_PRIORITY - 1);
                        t.setDaemon(true);
                        return t;
                    }
                });
                try {
                    ServerBootstrap bootstrab = new ServerBootstrap();
                    bootstrab.group(bossGroup, workerGroup);
                    bootstrab.channel(NioServerSocketChannel.class);
                    bootstrab.childHandler(new ClientboundConnectionInitializer("localhost", toPort));
                    bootstrab.childOption(ChannelOption.AUTO_READ, false);
                    bootstrab.bind(fromPort).sync().channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();
                }
            }
        }).start();
    }

    public static void main(String[] args) throws Exception {
        // startup args:
        // -serverjar minecraft_server_1.8.jar
        if (args.length < 2) {
            ProxyLogger.warn("Required startup arguments missing! Please use the following startup arguments:");
            // TODO print a list of arguments
            return;
        }
        String[] processBuilder = null;
        int currentArg = 0;
        for (String arg : args) {
            if (arg.equalsIgnoreCase("-serverjar")) {
                String[] a = new String[args.length - currentArg - 1];
                for (int i = currentArg + 1; i < args.length; i++) {
                    a[i - currentArg - 1] = args[i];
                }
                ProxyLogger.info("Loaded processbuilder path: '" + Arrays.asList(a).toString() + "'");
                processBuilder = a;
            }
            currentArg++;
        }
        if (processBuilder == null) {
            ProxyLogger.warn("Required startup arguments missing! Please use the following startup arguments:");
            // TODO print a list of arguments
        }
        new Main(processBuilder).run();
    }
}