-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLauncher.java
142 lines (133 loc) · 7.27 KB
/
Launcher.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import com.google.gson.JsonObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class Launcher
{
public static final String USER_DIR = System.getProperty("user.dir") + File.separator;
public static final String VERSIONS_DIR = "versions" + File.separator;
public static final String ASSETS_DIR = "assets" + File.separator;
public static final String ASSETS_INDEXES_DIR = ASSETS_DIR + "indexes" + File.separator;
public static final String RESOURCES_DIR = "resources" + File.separator;
public static final String LIBRARIES_DIR = "libraries" + File.separator;
public static final String DEFAULT_MC_PATH = System.getenv("APPDATA") + File.separator + ".minecraft" + File.separator; // This is necessary for older versions, since they
// require their assets to be under appdata/.minecraft
public static final String RUNTIME_PATH = "runtime" + File.separator;
public static void main(String[] args)
{
final String customJavaOption = "--java";
final String memoryOption = "--memory";
final String dryRunOption = "--dry-run";
final String helpMenu = "Usage: Launcher [options] [version] [username]\n" +
"Options:\n " +
customJavaOption + " [java.exe]: set a custom Java executable\n " +
memoryOption + " [number of MBs]: set the game max memory\n " +
dryRunOption + ": output only the launch command";
String customJavaExePath = "";
int memoryAmount = 1024;
boolean isDrRun = false;
String version = null, username = null;
if(args.length < 2)
{
System.out.println(helpMenu);
System.exit(0);
}
for(int i = 0; i < args.length; i++)
{
String arg = args[i];
if(arg.startsWith("--"))
{
switch(arg)
{
case "--help": System.out.println(helpMenu); System.exit(0);
case customJavaOption: customJavaExePath = args[++i]; break;
case memoryOption: memoryAmount = Integer.parseInt(args[++i]); break;
case dryRunOption: isDrRun = true; break;
default: System.out.println("Invalid flag. Exiting."); System.exit(-1);
}
}
else
{
if(version == null)
{
version = arg;
} else { username = arg; }
}
}
Launch(version, username, memoryAmount, isDrRun, customJavaExePath);
}
public static void Launch(String version, String username, int memoryAmountMB, boolean isDryRun, String customJavaExe)
{
JsonObject manifest = ManifestParser.GetJsonObjectFromFile(VERSIONS_DIR + version + File.separator + version + ".json");
JsonObject assetsManifest = ManifestParser.GetLocalAssetIndexFromVersion(manifest);
String nativesPath = VERSIONS_DIR + version + File.separator + "natives";
String clientJar = VERSIONS_DIR + version + File.separator + version + ".jar";
String assetIndex = manifest.getAsJsonObject("assetIndex").get("id").getAsString();
String startingClass = manifest.get("mainClass").getAsString();
boolean pre16 = assetIndex.equals("pre-1.6");
//String startingClass = !assetIndex.equals("pre-1.6") ? manifest.get("mainClass").getAsString() : "net.minecraft.client.Minecraft";
String assetsDir = "\"" + ManifestParser.GetAssetsDirFromAssetIndex(assetsManifest, "").replaceAll("objects" + Downloader.separator, "") + "\"";
Map<String, String> paramValues = new HashMap<String, String>() {{ // All parameters we could need
put("auth_player_name", username); // --username
put("version_name", version); // --version
put("game_directory", pre16 ? "\"" + DEFAULT_MC_PATH + "\"" : "\"" + System.getProperty("user.dir") + "\""); // --gameDir
put("assets_root", assetsDir); // --assetsDir
put("game_assets", assetsDir); // --assetsDir for some classic versions
put("assets_index_name", assetIndex); // --assetIndex
put("auth_uuid", UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)).toString().replaceAll("-", ""));
put("auth_access_token", "69420");
put("clientid", "\"\"");
put("auth_xuid", "\"\"");
put("user_properties", "{}");
put("user_type", "legacy");
put("version_type", manifest.get("type").getAsString());
}};
// Populate list of needed libraries
String libsPaths = "";
String divider = System.getProperty("os.name").toLowerCase().contains("windows") ? ";" : ":";
for(Pair<String, String> lib : ManifestParser.GetLibsFromVersion(manifest, Downloader.GetOSName()))
{
String path = LIBRARIES_DIR + lib.getKey();
libsPaths += path + lib.getValue().split("/")[lib.getValue().split("/").length - 1] + divider;
}
List<String> cmd = new ArrayList<>();
if(Objects.equals(customJavaExe, ""))
{
cmd.add(ManifestParser.GetRuntimePathFromVersion(manifest).getAbsolutePath());
} else { cmd.add(customJavaExe); }
if(Objects.equals(System.getProperty("os.name"), "Windows 11"))
{
cmd.add("-Dos.name=\"Windows 10\"");
cmd.add("-Dos.version=10.0");
}
cmd.add("-Djava.library.path=\"" + nativesPath + "\"");
cmd.add("-Dminecraft.client.jar=\"" + clientJar + "\"");
cmd.add("-cp");
cmd.add("\"" + clientJar + divider + libsPaths + "\"");
cmd.add("-Xmx" + memoryAmountMB + "M");
// Garbage collector flags, provides better performance
cmd.add("-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M -Xss1M");
cmd.add(startingClass);
cmd.add(ManifestParser.GetLaunchParams(manifest, paramValues));
String cmdString = String.join(" ", cmd);
cmd = Arrays.asList(cmdString.replaceAll(Downloader.separator, "/").split(" "));
System.out.println(String.join(" ", cmd));
if(isDryRun) { System.exit(0); }
try
{
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // Redirect the output of the process
pb.directory(new File("."));
System.out.println("Starting Minecraft " + version + "...");
Process mcProc = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(mcProc.getInputStream()));
String line;
while((line = reader.readLine()) != null) { System.out.println(line); } // and print it
int exitCode = mcProc.waitFor();
System.out.println("Minecraft exited with code: " + exitCode);
} catch (IOException | InterruptedException e) { e.printStackTrace(); }
}
}