mirror of
https://github.com/SKCraft/Launcher.git
synced 2024-11-27 12:46:22 +01:00
Refactor JavaRuntimeFinder into subclasses & clean up
The getAvailableRuntimes function is now parseable, & the new PlatformRuntimeFinder interface makes it clear what each stage does.
This commit is contained in:
parent
8c9f903e16
commit
08335637f9
@ -7,8 +7,8 @@
|
||||
package com.skcraft.launcher;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.skcraft.launcher.launch.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntimeFinder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.skcraft.launcher;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.skcraft.launcher.launch.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.MemorySettings;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
|
@ -9,9 +9,9 @@ package com.skcraft.launcher.dialog;
|
||||
import com.skcraft.launcher.Configuration;
|
||||
import com.skcraft.launcher.Launcher;
|
||||
import com.skcraft.launcher.dialog.component.BetterComboBox;
|
||||
import com.skcraft.launcher.launch.AddJavaRuntime;
|
||||
import com.skcraft.launcher.launch.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.launch.runtime.AddJavaRuntime;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.*;
|
||||
import com.skcraft.launcher.util.SharedLocale;
|
||||
|
@ -3,9 +3,9 @@ package com.skcraft.launcher.dialog;
|
||||
import com.skcraft.launcher.Instance;
|
||||
import com.skcraft.launcher.InstanceSettings;
|
||||
import com.skcraft.launcher.dialog.component.BetterComboBox;
|
||||
import com.skcraft.launcher.launch.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.launch.MemorySettings;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.swing.FormPanel;
|
||||
import com.skcraft.launcher.swing.LinedBoxPanel;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
package com.skcraft.launcher.launch;
|
||||
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
@ -1,260 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.launch;
|
||||
|
||||
import com.dd.plist.NSArray;
|
||||
import com.dd.plist.NSDictionary;
|
||||
import com.dd.plist.NSObject;
|
||||
import com.dd.plist.PropertyListParser;
|
||||
import com.skcraft.launcher.model.minecraft.JavaVersion;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
import com.skcraft.launcher.util.EnvironmentParser;
|
||||
import com.skcraft.launcher.util.Platform;
|
||||
import com.skcraft.launcher.util.WinRegistry;
|
||||
import com.sun.jna.platform.win32.WinReg;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Finds the best Java runtime to use.
|
||||
*/
|
||||
@Log
|
||||
public final class JavaRuntimeFinder {
|
||||
|
||||
private JavaRuntimeFinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available Java runtimes on the system
|
||||
* @return List of available Java runtimes sorted by newest first
|
||||
*/
|
||||
public static List<JavaRuntime> getAvailableRuntimes() {
|
||||
Environment env = Environment.getInstance();
|
||||
Set<JavaRuntime> entries = new HashSet<>();
|
||||
Set<File> launcherDirs = new HashSet<>();
|
||||
|
||||
if (env.getPlatform() == Platform.WINDOWS) {
|
||||
try {
|
||||
String launcherPath = WinRegistry.readString(WinReg.HKEY_CURRENT_USER,
|
||||
"SOFTWARE\\Mojang\\InstalledProducts\\Minecraft Launcher", "InstallLocation");
|
||||
|
||||
launcherDirs.add(new File(launcherPath));
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.WARNING, "Failed to read launcher location from registry", err);
|
||||
}
|
||||
|
||||
String programFiles = Objects.equals(env.getArchBits(), "64")
|
||||
? System.getenv("ProgramFiles(x86)")
|
||||
: System.getenv("ProgramFiles");
|
||||
|
||||
// Mojang likes to move the java runtime directory
|
||||
launcherDirs.add(new File(programFiles, "Minecraft"));
|
||||
launcherDirs.add(new File(programFiles, "Minecraft Launcher"));
|
||||
launcherDirs.add(new File(System.getenv("LOCALAPPDATA"), "Packages\\Microsoft.4297127D64EC6_8wekyb3d8bbwe\\LocalCache\\Local"));
|
||||
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\Java Development Kit");
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\JDK");
|
||||
} else if (env.getPlatform() == Platform.LINUX) {
|
||||
launcherDirs.add(new File(System.getenv("HOME"), ".minecraft"));
|
||||
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
if (javaHome != null) {
|
||||
entries.add(getRuntimeFromPath(javaHome));
|
||||
}
|
||||
|
||||
File[] runtimesList = new File("/usr/lib/jvm").listFiles();
|
||||
if (runtimesList != null) {
|
||||
Arrays.stream(runtimesList).map(file -> {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException exception) {
|
||||
return file;
|
||||
}
|
||||
}).distinct().forEach(file -> entries.add(getRuntimeFromPath(file.getAbsolutePath())));
|
||||
}
|
||||
} else if (env.getPlatform() == Platform.MAC_OS_X) {
|
||||
launcherDirs.add(new File(System.getenv("HOME"), "Library/Application Support/minecraft"));
|
||||
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec("/usr/libexec/java_home -X");
|
||||
NSArray root = (NSArray) PropertyListParser.parse(p.getInputStream());
|
||||
NSObject[] arr = root.getArray();
|
||||
for (NSObject obj : arr) {
|
||||
NSDictionary dict = (NSDictionary) obj;
|
||||
entries.add(new JavaRuntime(
|
||||
new File(dict.objectForKey("JVMHomePath").toString()).getAbsoluteFile(),
|
||||
dict.objectForKey("JVMVersion").toString(),
|
||||
isArch64Bit(dict.objectForKey("JVMArch").toString())
|
||||
));
|
||||
}
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.WARNING, "Failed to parse java_home command", err);
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
for (File install : launcherDirs) {
|
||||
File runtimes = new File(install, "runtime");
|
||||
File[] runtimeList = runtimes.listFiles();
|
||||
if (runtimeList != null) {
|
||||
for (File potential : runtimeList) {
|
||||
String runtimeName = potential.getName();
|
||||
if (runtimeName.startsWith("jre-x")) {
|
||||
boolean is64Bit = runtimeName.equals("jre-x64");
|
||||
|
||||
JavaRuntime runtime = new JavaRuntime(potential.getAbsoluteFile(), readVersionFromRelease(potential), is64Bit);
|
||||
runtime.setMinecraftBundled(true);
|
||||
entries.add(runtime);
|
||||
} else {
|
||||
String[] children = potential.list((dir, name) -> new File(dir, name).isDirectory());
|
||||
if (children == null || children.length != 1) continue;
|
||||
String platformName = children[0];
|
||||
|
||||
File javaDir = new File(potential, String.format("%s/%s", platformName, runtimeName));
|
||||
if (env.getPlatform() == Platform.MAC_OS_X) {
|
||||
javaDir = new File(javaDir, "jre.bundle/Contents/Home");
|
||||
}
|
||||
|
||||
String arch = readArchFromRelease(javaDir);
|
||||
boolean is64Bit = isArch64Bit(arch);
|
||||
|
||||
JavaRuntime runtime = new JavaRuntime(javaDir.getAbsoluteFile(), readVersionFromRelease(javaDir), is64Bit);
|
||||
runtime.setMinecraftBundled(true);
|
||||
entries.add(runtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entries.stream().sorted().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the best found JVM location.
|
||||
*
|
||||
* @return the JVM location, or null
|
||||
*/
|
||||
public static File findBestJavaPath() {
|
||||
List<JavaRuntime> entries = getAvailableRuntimes();
|
||||
if (entries.size() > 0) {
|
||||
return new File(entries.get(0).getDir(), "bin");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Optional<JavaRuntime> findBestJavaRuntime(JavaVersion targetVersion) {
|
||||
List<JavaRuntime> entries = getAvailableRuntimes();
|
||||
|
||||
return entries.stream().sorted()
|
||||
.filter(runtime -> runtime.getMajorVersion() == targetVersion.getMajorVersion())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public static Optional<JavaRuntime> findAnyJavaRuntime() {
|
||||
return getAvailableRuntimes().stream().sorted().findFirst();
|
||||
}
|
||||
|
||||
public static JavaRuntime getRuntimeFromPath(String path) {
|
||||
File target = new File(path);
|
||||
|
||||
if (target.isFile()) {
|
||||
// Probably referring directly to bin/java, back up two levels
|
||||
target = target.getParentFile().getParentFile();
|
||||
} else if (target.getName().equals("bin")) {
|
||||
// Probably copied the bin directory that java.exe is in
|
||||
target = target.getParentFile();
|
||||
}
|
||||
|
||||
{
|
||||
File jre = new File(target, "jre/release");
|
||||
if (jre.isFile()) {
|
||||
target = jre.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
return new JavaRuntime(target, readVersionFromRelease(target), guessIf64BitWindows(target));
|
||||
}
|
||||
|
||||
private static void getEntriesFromRegistry(Collection<JavaRuntime> entries, String basePath)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
List<String> subKeys = WinRegistry.readStringSubKeys(WinReg.HKEY_LOCAL_MACHINE, basePath);
|
||||
for (String subKey : subKeys) {
|
||||
JavaRuntime entry = getEntryFromRegistry(basePath, subKey);
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.INFO, "Failed to read Java locations from registry in " + basePath);
|
||||
}
|
||||
}
|
||||
|
||||
private static JavaRuntime getEntryFromRegistry(String basePath, String version) {
|
||||
String regPath = basePath + "\\" + version;
|
||||
String path = WinRegistry.readString(WinReg.HKEY_LOCAL_MACHINE, regPath, "JavaHome");
|
||||
File dir = new File(path);
|
||||
if (dir.exists() && new File(dir, "bin/java.exe").exists()) {
|
||||
return new JavaRuntime(dir, version, guessIf64BitWindows(dir));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean guessIf64BitWindows(File path) {
|
||||
try {
|
||||
String programFilesX86 = System.getenv("ProgramFiles(x86)");
|
||||
return programFilesX86 == null || !path.getCanonicalPath().startsWith(new File(programFilesX86).getCanonicalPath());
|
||||
} catch (IOException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isArch64Bit(String string) {
|
||||
return string == null || string.matches("x64|x86_64|amd64|aarch64");
|
||||
}
|
||||
|
||||
private static String readVersionFromRelease(File javaPath) {
|
||||
File releaseFile = new File(javaPath, "release");
|
||||
if (releaseFile.exists()) {
|
||||
try {
|
||||
Map<String, String> releaseDetails = EnvironmentParser.parse(releaseFile);
|
||||
|
||||
return releaseDetails.get("JAVA_VERSION");
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to read release file " + releaseFile.getAbsolutePath(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String readArchFromRelease(File javaPath) {
|
||||
File releaseFile = new File(javaPath, "release");
|
||||
if (releaseFile.exists()) {
|
||||
try {
|
||||
Map<String, String> releaseDetails = EnvironmentParser.parse(releaseFile);
|
||||
|
||||
return releaseDetails.get("OS_ARCH");
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to read release file " + releaseFile.getAbsolutePath(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.launcher.*;
|
||||
import com.skcraft.launcher.auth.Session;
|
||||
import com.skcraft.launcher.install.ZipExtract;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntime;
|
||||
import com.skcraft.launcher.launch.runtime.JavaRuntimeFinder;
|
||||
import com.skcraft.launcher.model.minecraft.*;
|
||||
import com.skcraft.launcher.persistence.Persistence;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.skcraft.launcher.launch;
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -0,0 +1,47 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.skcraft.launcher.util.EnvironmentParser;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Log
|
||||
public class JavaReleaseFile {
|
||||
private Map<String, String> backingMap;
|
||||
|
||||
private JavaReleaseFile(Map<String, String> releaseDetails) {
|
||||
this.backingMap = releaseDetails;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return backingMap.get("JAVA_VERSION");
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return backingMap.get("OS_ARCH");
|
||||
}
|
||||
|
||||
public boolean isArch64Bit() {
|
||||
return getArch() == null || getArch().matches("x64|x86_64|amd64|aarch64");
|
||||
}
|
||||
|
||||
public static JavaReleaseFile parseFromRelease(File javaPath) {
|
||||
File releaseFile = new File(javaPath, "release");
|
||||
|
||||
if (releaseFile.exists()) {
|
||||
try {
|
||||
Map<String, String> releaseDetails = EnvironmentParser.parse(releaseFile);
|
||||
|
||||
return new JavaReleaseFile(releaseDetails);
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to read release file " + releaseFile.getAbsolutePath(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.skcraft.launcher.launch;
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.skcraft.launcher.model.minecraft.JavaVersion;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Finds the best Java runtime to use.
|
||||
*/
|
||||
@Log
|
||||
public final class JavaRuntimeFinder {
|
||||
|
||||
private JavaRuntimeFinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available Java runtimes on the system
|
||||
* @return List of available Java runtimes sorted by newest first
|
||||
*/
|
||||
public static List<JavaRuntime> getAvailableRuntimes() {
|
||||
Environment env = Environment.getInstance();
|
||||
PlatformRuntimeFinder runtimeFinder = getRuntimeFinder(env);
|
||||
|
||||
if (runtimeFinder == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Add Minecraft javas
|
||||
List<JavaRuntime> mcRuntimes = MinecraftJavaFinder.scanLauncherDirectories(env,
|
||||
runtimeFinder.getLauncherDirectories(env));
|
||||
Set<JavaRuntime> entries = new HashSet<>(mcRuntimes);
|
||||
|
||||
// Add system Javas
|
||||
runtimeFinder.getCandidateJavaLocations().stream()
|
||||
.map(JavaRuntimeFinder::getRuntimeFromPath)
|
||||
.forEach(entries::add);
|
||||
|
||||
// Add extra runtimes
|
||||
entries.addAll(runtimeFinder.getExtraRuntimes());
|
||||
|
||||
return entries.stream().sorted().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the best runtime for a given Java version
|
||||
* @param targetVersion Version to match
|
||||
* @return Java runtime if available, empty Optional otherwise
|
||||
*/
|
||||
public static Optional<JavaRuntime> findBestJavaRuntime(JavaVersion targetVersion) {
|
||||
List<JavaRuntime> entries = getAvailableRuntimes();
|
||||
|
||||
return entries.stream().sorted()
|
||||
.filter(runtime -> runtime.getMajorVersion() == targetVersion.getMajorVersion())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public static Optional<JavaRuntime> findAnyJavaRuntime() {
|
||||
return getAvailableRuntimes().stream().sorted().findFirst();
|
||||
}
|
||||
|
||||
public static JavaRuntime getRuntimeFromPath(String path) {
|
||||
return getRuntimeFromPath(new File(path));
|
||||
}
|
||||
|
||||
public static JavaRuntime getRuntimeFromPath(File target) {
|
||||
if (target.isFile()) {
|
||||
// Probably referring directly to bin/java, back up two levels
|
||||
target = target.getParentFile().getParentFile();
|
||||
} else if (target.getName().equals("bin")) {
|
||||
// Probably copied the bin directory that java.exe is in
|
||||
target = target.getParentFile();
|
||||
}
|
||||
|
||||
{
|
||||
File jre = new File(target, "jre/release");
|
||||
if (jre.isFile()) {
|
||||
target = jre.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
JavaReleaseFile release = JavaReleaseFile.parseFromRelease(target);
|
||||
if (release == null) {
|
||||
// Make some assumptions...
|
||||
return new JavaRuntime(target, null, true);
|
||||
}
|
||||
|
||||
return new JavaRuntime(target, release.getVersion(), release.isArch64Bit());
|
||||
}
|
||||
|
||||
private static PlatformRuntimeFinder getRuntimeFinder(Environment env) {
|
||||
switch (env.getPlatform()) {
|
||||
case WINDOWS:
|
||||
return new WindowsRuntimeFinder();
|
||||
case MAC_OS_X:
|
||||
return new MacRuntimeFinder();
|
||||
case LINUX:
|
||||
return new LinuxRuntimeFinder();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class LinuxRuntimeFinder implements PlatformRuntimeFinder {
|
||||
@Override
|
||||
public Set<File> getLauncherDirectories(Environment env) {
|
||||
return ImmutableSet.of(new File(System.getenv("HOME"), ".minecraft"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> getCandidateJavaLocations() {
|
||||
ArrayList<File> entries = Lists.newArrayList();
|
||||
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
if (javaHome != null) {
|
||||
entries.add(new File(javaHome));
|
||||
}
|
||||
|
||||
File[] runtimesList = new File("/usr/lib/jvm").listFiles();
|
||||
if (runtimesList != null) {
|
||||
Arrays.stream(runtimesList).map(file -> {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException exception) {
|
||||
return file;
|
||||
}
|
||||
}).distinct().forEach(entries::add);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JavaRuntime> getExtraRuntimes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.dd.plist.NSArray;
|
||||
import com.dd.plist.NSDictionary;
|
||||
import com.dd.plist.NSObject;
|
||||
import com.dd.plist.PropertyListParser;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Log
|
||||
public class MacRuntimeFinder implements PlatformRuntimeFinder {
|
||||
@Override
|
||||
public Set<File> getLauncherDirectories(Environment env) {
|
||||
return ImmutableSet.of(new File(System.getenv("HOME"), "Library/Application Support/minecraft"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> getCandidateJavaLocations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JavaRuntime> getExtraRuntimes() {
|
||||
ArrayList<JavaRuntime> entries = Lists.newArrayList();
|
||||
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec("/usr/libexec/java_home -X");
|
||||
NSArray root = (NSArray) PropertyListParser.parse(p.getInputStream());
|
||||
NSObject[] arr = root.getArray();
|
||||
for (NSObject obj : arr) {
|
||||
NSDictionary dict = (NSDictionary) obj;
|
||||
entries.add(new JavaRuntime(
|
||||
new File(dict.objectForKey("JVMHomePath").toString()).getAbsoluteFile(),
|
||||
dict.objectForKey("JVMVersion").toString(),
|
||||
isArch64Bit(dict.objectForKey("JVMArch").toString())
|
||||
));
|
||||
}
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.WARNING, "Failed to parse java_home command", err);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static boolean isArch64Bit(String string) {
|
||||
return string == null || string.matches("x64|x86_64|amd64|aarch64");
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
import com.skcraft.launcher.util.Platform;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Scans Minecraft bundled Java directories
|
||||
*/
|
||||
public class MinecraftJavaFinder {
|
||||
public static List<JavaRuntime> scanLauncherDirectories(Environment env, Collection<File> launcherDirs) {
|
||||
ArrayList<JavaRuntime> entries = new ArrayList<>();
|
||||
|
||||
for (File install : launcherDirs) {
|
||||
File runtimes = new File(install, "runtime");
|
||||
File[] runtimeList = runtimes.listFiles();
|
||||
if (runtimeList != null) {
|
||||
for (File potential : runtimeList) {
|
||||
JavaRuntime runtime = scanPotentialRuntime(env, potential);
|
||||
|
||||
if (runtime != null) {
|
||||
entries.add(runtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static JavaRuntime scanPotentialRuntime(Environment env, File potential) {
|
||||
String runtimeName = potential.getName();
|
||||
if (runtimeName.startsWith("jre-x")) {
|
||||
boolean is64Bit = runtimeName.equals("jre-x64");
|
||||
|
||||
JavaReleaseFile release = JavaReleaseFile.parseFromRelease(potential);
|
||||
String version = release != null ? release.getVersion() : null;
|
||||
|
||||
JavaRuntime runtime = new JavaRuntime(potential.getAbsoluteFile(), version, is64Bit);
|
||||
runtime.setMinecraftBundled(true);
|
||||
return runtime;
|
||||
} else {
|
||||
String[] children = potential.list((dir, name) -> new File(dir, name).isDirectory());
|
||||
if (children == null || children.length != 1) return null;
|
||||
String platformName = children[0];
|
||||
|
||||
File javaDir = new File(potential, String.format("%s/%s", platformName, runtimeName));
|
||||
if (env.getPlatform() == Platform.MAC_OS_X) {
|
||||
javaDir = new File(javaDir, "jre.bundle/Contents/Home");
|
||||
}
|
||||
|
||||
JavaReleaseFile release = JavaReleaseFile.parseFromRelease(javaDir);
|
||||
if (release == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JavaRuntime runtime = new JavaRuntime(javaDir.getAbsoluteFile(), release.getVersion(), release.isArch64Bit());
|
||||
runtime.setMinecraftBundled(true);
|
||||
return runtime;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface PlatformRuntimeFinder {
|
||||
/**
|
||||
* Get the list of possible launcher locations for this platform
|
||||
* @return List of possible launcher locations
|
||||
*/
|
||||
Set<File> getLauncherDirectories(Environment env);
|
||||
|
||||
/**
|
||||
* Get a list of candidate folders to check for Java runtimes.
|
||||
* The returned folders will be checked for "release" files which describe the version and architecture.
|
||||
*
|
||||
* @return List of folders that may contain Java runtimes
|
||||
*/
|
||||
List<File> getCandidateJavaLocations();
|
||||
|
||||
/**
|
||||
* Get a list of extra runtimes obtained using platform-specific logic.
|
||||
* e.g. on Windows, registry entries are returned
|
||||
*
|
||||
* @return List of extra Java runtimes
|
||||
*/
|
||||
List<JavaRuntime> getExtraRuntimes();
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.skcraft.launcher.launch.runtime;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.skcraft.launcher.util.Environment;
|
||||
import com.skcraft.launcher.util.WinRegistry;
|
||||
import com.sun.jna.platform.win32.WinReg;
|
||||
import lombok.extern.java.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Log
|
||||
public class WindowsRuntimeFinder implements PlatformRuntimeFinder {
|
||||
@Override
|
||||
public Set<File> getLauncherDirectories(Environment env) {
|
||||
HashSet<File> launcherDirs = new HashSet<>();
|
||||
|
||||
try {
|
||||
String launcherPath = WinRegistry.readString(WinReg.HKEY_CURRENT_USER,
|
||||
"SOFTWARE\\Mojang\\InstalledProducts\\Minecraft Launcher", "InstallLocation");
|
||||
|
||||
launcherDirs.add(new File(launcherPath));
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.WARNING, "Failed to read launcher location from registry", err);
|
||||
}
|
||||
|
||||
String programFiles = Objects.equals(env.getArchBits(), "64")
|
||||
? System.getenv("ProgramFiles(x86)")
|
||||
: System.getenv("ProgramFiles");
|
||||
|
||||
// Mojang likes to move the java runtime directory
|
||||
launcherDirs.add(new File(programFiles, "Minecraft"));
|
||||
launcherDirs.add(new File(programFiles, "Minecraft Launcher"));
|
||||
launcherDirs.add(new File(System.getenv("LOCALAPPDATA"), "Packages\\Microsoft.4297127D64EC6_8wekyb3d8bbwe\\LocalCache\\Local"));
|
||||
|
||||
return launcherDirs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> getCandidateJavaLocations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JavaRuntime> getExtraRuntimes() {
|
||||
ArrayList<JavaRuntime> entries = Lists.newArrayList();
|
||||
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\Java Development Kit");
|
||||
getEntriesFromRegistry(entries, "SOFTWARE\\JavaSoft\\JDK");
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static void getEntriesFromRegistry(Collection<JavaRuntime> entries, String basePath)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
List<String> subKeys = WinRegistry.readStringSubKeys(WinReg.HKEY_LOCAL_MACHINE, basePath);
|
||||
for (String subKey : subKeys) {
|
||||
JavaRuntime entry = getEntryFromRegistry(basePath, subKey);
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
} catch (Throwable err) {
|
||||
log.log(Level.INFO, "Failed to read Java locations from registry in " + basePath);
|
||||
}
|
||||
}
|
||||
|
||||
private static JavaRuntime getEntryFromRegistry(String basePath, String version) {
|
||||
String regPath = basePath + "\\" + version;
|
||||
String path = WinRegistry.readString(WinReg.HKEY_LOCAL_MACHINE, regPath, "JavaHome");
|
||||
File dir = new File(path);
|
||||
if (dir.exists() && new File(dir, "bin/java.exe").exists()) {
|
||||
return new JavaRuntime(dir, version, guessIf64BitWindows(dir));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean guessIf64BitWindows(File path) {
|
||||
try {
|
||||
String programFilesX86 = System.getenv("ProgramFiles(x86)");
|
||||
return programFilesX86 == null || !path.getCanonicalPath().startsWith(new File(programFilesX86).getCanonicalPath());
|
||||
} catch (IOException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user