/*
* ATLauncher - https://github.com/ATLauncher/ATLauncher
* Copyright (C) 2013 ATLauncher
*
* 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.atlauncher.mclauncher;
import com.atlauncher.App;
import com.atlauncher.LogManager;
import com.atlauncher.data.Account;
import com.atlauncher.data.Instance;
import com.atlauncher.data.LoginResponse;
import com.atlauncher.data.mojang.PropertyMapSerializer;
import com.atlauncher.utils.Utils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.authlib.properties.PropertyMap;
import com.mojang.util.UUIDTypeAdapter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MCLauncher {
public static Process launch(Account account, Instance instance, LoginResponse response) throws IOException {
StringBuilder cpb = new StringBuilder();
boolean hasCustomJarMods = false;
File jarMods = instance.getJarModsDirectory();
File[] jarModFiles = jarMods.listFiles();
if (jarMods.exists() && jarModFiles != null && (instance.hasJarMods() || jarModFiles.length != 0)) {
if (instance.hasJarMods()) {
ArrayList<String> jarmods = new ArrayList<String>(Arrays.asList(instance.getJarOrder().split(",")));
if (jarmods.size() > 1) {
hasCustomJarMods = true;
}
for (String mod : jarmods) {
File thisFile = new File(jarMods, mod);
if (thisFile.exists()) {
cpb.append(File.pathSeparator);
cpb.append(thisFile);
}
}
for (File file : jarModFiles) {
if (jarmods.contains(file.getName())) {
continue;
}
hasCustomJarMods = true;
cpb.append(File.pathSeparator);
cpb.append(file);
}
} else {
for (File file : jarModFiles) {
hasCustomJarMods = true;
cpb.append(File.pathSeparator);
cpb.append(file);
}
}
}
for (String jarFile : instance.getLibrariesNeeded().split(",")) {
cpb.append(File.pathSeparator);
cpb.append(new File(instance.getBinDirectory(), jarFile));
}
File binFolder = instance.getBinDirectory();
File[] libraryFiles = binFolder.listFiles();
if (binFolder.exists() && libraryFiles != null && libraryFiles.length != 0) {
for (File file : libraryFiles) {
if (file.isDirectory() || file.getName().equalsIgnoreCase(instance.getMinecraftJar().getName()) ||
instance.getLibrariesNeeded().contains(file.getName())) {
continue;
}
LogManager.info("Added in custom library " + file.getName());
cpb.append(File.pathSeparator);
cpb.append(file);
}
}
cpb.append(File.pathSeparator);
cpb.append(instance.getMinecraftJar());
List<String> arguments = new ArrayList<String>();
String path = App.settings.getJavaPath() + File.separator + "bin" + File.separator + "java";
if (Utils.isWindows()) {
path += "w";
}
arguments.add(path);
if (Utils.isWindows()) {
arguments.add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump");
}
arguments.add("-XX:-OmitStackTraceInFastThrow");
String javaParams = App.settings.getJavaParameters();
if (javaParams.isEmpty()) {
// Mojang launcher defaults if user has no custom java arguments
javaParams = "-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:-UseAdaptiveSizePolicy";
}
arguments.add("-Xms" + App.settings.getInitialMemory() + "M");
if (App.settings.getMaximumMemory() < instance.getMemory()) {
if ((Utils.getMaximumRam() / 2) < instance.getMemory()) {
arguments.add("-Xmx" + App.settings.getMaximumMemory() + "M");
} else {
arguments.add("-Xmx" + instance.getMemory() + "M");
}
} else {
arguments.add("-Xmx" + App.settings.getMaximumMemory() + "M");
}
if (App.settings.getPermGen() < instance.getPermGen() && (Utils.getMaximumRam() / 8) < instance.getPermGen()) {
if (Utils.useMetaspace()) {
arguments.add("-XX:MetaspaceSize=" + instance.getPermGen() + "M");
} else {
arguments.add("-XX:PermSize=" + instance.getPermGen() + "M");
}
} else {
if (Utils.useMetaspace()) {
arguments.add("-XX:MetaspaceSize=" + App.settings.getPermGen() + "M");
} else {
arguments.add("-XX:PermSize=" + App.settings.getPermGen() + "M");
}
}
arguments.add("-Duser.language=en");
arguments.add("-Duser.country=US");
if (hasCustomJarMods) {
System.out.println("OH NOES! Avert your eyes!");
arguments.add("-Dfml.ignorePatchDiscrepancies=true");
arguments.add("-Dfml.ignoreInvalidMinecraftCertificates=true");
System.out.println("Okay you can look again, you saw NOTHING!");
}
arguments.add("-Dfml.log.level=" + App.settings.getForgeLoggingLevel());
if (Utils.isMac()) {
arguments.add("-Dapple.laf.useScreenMenuBar=true");
arguments.add("-Xdock:icon=" + new File(instance.getAssetsDir(), "icons/minecraft.icns").getAbsolutePath());
arguments.add("-Xdock:name=\"" + instance.getName() + "\"");
}
ArrayList<String> negatedArgs = new ArrayList<String>();
if (!javaParams.isEmpty()) {
for (String arg : javaParams.split(" ")) {
if (!arg.isEmpty()) {
if (instance.hasExtraArguments()) {
if (instance.getExtraArguments().contains(arg)) {
LogManager.error("Duplicate argument " + arg + " found and not added!");
continue;
}
if (arg.startsWith("-XX:+")) {
if (instance.getExtraArguments().contains("-XX:-" + arg.substring(5))) {
negatedArgs.add("-XX:-" + arg.substring(5));
LogManager.error("Argument " + arg + " is negated by pack developer and not added!");
continue;
}
}
}
if (arguments.toString().contains(arg)) {
LogManager.error("Duplicate argument " + arg + " found and not added!");
continue;
}
arguments.add(arg);
}
}
}
arguments.add("-Djava.library.path=" + instance.getNativesDirectory().getAbsolutePath());
arguments.add("-cp");
arguments.add(System.getProperty("java.class.path") + cpb.toString());
arguments.add(instance.getMainClass());
String props = "[]";
if (!response.isOffline()) {
Gson gson = new GsonBuilder().registerTypeAdapter(PropertyMap.class, new PropertyMapSerializer()).create();
props = gson.toJson(response.getAuth().getUserProperties());
}
if (instance.hasMinecraftArguments()) {
String[] minecraftArguments = instance.getMinecraftArguments().split(" ");
for (String argument : minecraftArguments) {
argument = argument.replace("${auth_player_name}", account.getMinecraftUsername());
argument = argument.replace("${profile_name}", instance.getName());
argument = argument.replace("${user_properties}", props);
argument = argument.replace("${version_name}", instance.getMinecraftVersion());
argument = argument.replace("${game_directory}", instance.getRootDirectory().getAbsolutePath());
argument = argument.replace("${game_assets}", instance.getAssetsDir().getAbsolutePath());
argument = argument.replace("${assets_root}", App.settings.getResourcesDir().getAbsolutePath());
argument = argument.replace("${assets_index_name}", instance.getAssets());
argument = argument.replace("${auth_uuid}", UUIDTypeAdapter.fromUUID(account.getRealUUID()));
argument = argument.replace("${auth_access_token}", account.getAccessToken());
argument = argument.replace("${auth_session}", account.getSession(response));
argument = argument.replace("${version_type}", instance.getVersionType());
argument = argument.replace("${user_type}", response.isOffline() ? com.mojang.authlib.UserType.MOJANG
.getName() : response.getAuth().getUserType().getName());
arguments.add(argument);
}
} else {
arguments.add("--username=" + account.getMinecraftUsername());
arguments.add("--session=" + account.getSession(response));
// This is for 1.7
arguments.add("--accessToken=" + account.getAccessToken());
arguments.add("--uuid=" + UUIDTypeAdapter.fromUUID(account.getRealUUID()));
// End of stuff for 1.7
arguments.add("--version=" + instance.getMinecraftVersion());
arguments.add("--gameDir=" + instance.getRootDirectory().getAbsolutePath());
arguments.add("--assetsDir=" + App.settings.getResourcesDir().getAbsolutePath());
}
if (App.settings.startMinecraftMaximised()) {
arguments.add("--width=" + Utils.getMaximumWindowWidth());
arguments.add("--height=" + Utils.getMaximumWindowHeight());
} else {
arguments.add("--width=" + App.settings.getWindowWidth());
arguments.add("--height=" + App.settings.getWindowHeight());
}
if (instance.hasExtraArguments()) {
String args = instance.getExtraArguments();
if (args.contains(" ")) {
for (String argument : args.split(" ")) {
if (!negatedArgs.contains(argument)) {
arguments.add(argument);
}
}
} else {
if (!negatedArgs.contains(args)) {
arguments.add(args);
}
}
}
String argsString = arguments.toString();
if (!LogManager.showDebug) {
if (App.settings != null) {
argsString = argsString.replace(App.settings.getBaseDir().getAbsolutePath(), "USERSDIR");
}
argsString = argsString.replace(account.getMinecraftUsername(), "REDACTED");
argsString = argsString.replace(account.getUUID(), "REDACTED");
argsString = argsString.replace(account.getAccessToken(), "REDACTED");
argsString = argsString.replace(account.getSession(response), "REDACTED");
argsString = argsString.replace(props, "REDACTED");
}
LogManager.info("Launching Minecraft with the following arguments " + "(user related stuff has been removed):" +
" " + argsString);
ProcessBuilder processBuilder = new ProcessBuilder(arguments);
processBuilder.directory(instance.getRootDirectory());
processBuilder.redirectErrorStream(true);
processBuilder.environment().remove("_JAVA_OPTIONS"); // Remove any _JAVA_OPTIONS, they are a PAIN
return processBuilder.start();
}
}