diff --git a/launcher/src/main/java/com/skcraft/launcher/launch/LaunchSupervisor.java b/launcher/src/main/java/com/skcraft/launcher/launch/LaunchSupervisor.java index 9dd8a27..887e620 100644 --- a/launcher/src/main/java/com/skcraft/launcher/launch/LaunchSupervisor.java +++ b/launcher/src/main/java/com/skcraft/launcher/launch/LaunchSupervisor.java @@ -16,11 +16,14 @@ import com.skcraft.launcher.auth.Session; import com.skcraft.launcher.dialog.AccountSelectDialog; import com.skcraft.launcher.dialog.ProgressDialog; import com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy; +import com.skcraft.launcher.launch.runtime.JavaRuntime; +import com.skcraft.launcher.model.minecraft.JavaVersion; import com.skcraft.launcher.persistence.Persistence; import com.skcraft.launcher.swing.SwingHelper; import com.skcraft.launcher.update.Updater; import com.skcraft.launcher.util.SharedLocale; import com.skcraft.launcher.util.SwingExecutor; +import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.apache.commons.io.FileUtils; @@ -29,6 +32,8 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.util.Date; +import java.util.concurrent.ExecutionException; +import java.util.function.BiPredicate; import java.util.logging.Level; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; @@ -119,7 +124,7 @@ public class LaunchSupervisor { final File extractDir = launcher.createExtractDir(); // Get the process - Runner task = new Runner(launcher, instance, session, extractDir); + Runner task = new Runner(launcher, instance, session, extractDir, new RuntimeVerifier(instance)); ObservableFuture processFuture = new ObservableFuture( launcher.getExecutor().submit(task), task); @@ -169,4 +174,38 @@ public class LaunchSupervisor { } }, sameThreadExecutor()); } + + @RequiredArgsConstructor + static class RuntimeVerifier implements BiPredicate { + private final Instance instance; + + @Override + public boolean test(JavaRuntime javaRuntime, JavaVersion javaVersion) { + ListenableFuture fut = SwingExecutor.INSTANCE.submit(() -> { + Object[] options = new Object[]{ + tr("button.cancel"), + tr("button.launchAnyway"), + }; + + String message = tr("runner.wrongJavaVersion", + instance.getTitle(), javaVersion.getMajorVersion(), javaRuntime.getVersion()); + int picked = JOptionPane.showOptionDialog(null, + SwingHelper.htmlWrap(message), + tr("launcher.javaMismatchTitle"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + null); + + return picked == 1; + }); + + try { + return fut.get(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + } + } } diff --git a/launcher/src/main/java/com/skcraft/launcher/launch/Runner.java b/launcher/src/main/java/com/skcraft/launcher/launch/Runner.java index 27d98e7..abbee20 100644 --- a/launcher/src/main/java/com/skcraft/launcher/launch/Runner.java +++ b/launcher/src/main/java/com/skcraft/launcher/launch/Runner.java @@ -37,6 +37,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.function.BiPredicate; import static com.skcraft.launcher.LauncherUtils.checkInterrupted; import static com.skcraft.launcher.util.SharedLocale.tr; @@ -54,6 +56,7 @@ public class Runner implements Callable, ProgressObservable { private final Instance instance; private final Session session; private final File extractDir; + private final BiPredicate javaRuntimeMismatch; @Getter @Setter private Environment environment = Environment.getInstance(); private VersionManifest versionManifest; @@ -66,18 +69,20 @@ public class Runner implements Callable, ProgressObservable { /** * Create a new instance launcher. - * - * @param launcher the launcher + * @param launcher the launcher * @param instance the instance * @param session the session * @param extractDir the directory to extract to + * @param javaRuntimeMismatch */ public Runner(@NonNull Launcher launcher, @NonNull Instance instance, - @NonNull Session session, @NonNull File extractDir) { + @NonNull Session session, @NonNull File extractDir, + BiPredicate javaRuntimeMismatch) { this.launcher = launcher; this.instance = instance; this.session = session; this.extractDir = extractDir; + this.javaRuntimeMismatch = javaRuntimeMismatch; this.featureList = new FeatureList.Mutable(); } @@ -149,6 +154,8 @@ public class Runner implements Callable, ProgressObservable { callLaunchModifier(); + verifyJavaRuntime(); + ProcessBuilder processBuilder = new ProcessBuilder(builder.buildCommand()); processBuilder.directory(instance.getContentDir()); Runner.log.info("Launching: " + builder); @@ -166,6 +173,23 @@ public class Runner implements Callable, ProgressObservable { instance.modify(builder); } + private void verifyJavaRuntime() { + JavaRuntime pickedRuntime = builder.getRuntime(); + JavaVersion targetVersion = versionManifest.getJavaVersion(); + + if (pickedRuntime == null || targetVersion == null) { + return; + } + + if (pickedRuntime.getMajorVersion() != targetVersion.getMajorVersion()) { + boolean launchAnyway = javaRuntimeMismatch.test(pickedRuntime, targetVersion); + + if (!launchAnyway) { + throw new CancellationException("Launch cancelled by user."); + } + } + } + /** * Add platform-specific arguments. */ diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java b/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java index b8239df..1ee7a1c 100644 --- a/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java +++ b/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java @@ -70,6 +70,11 @@ public final class SwingHelper { .replace("&", "&"); } + public static String htmlWrap(String message) { + // To force the label to wrap, convert the message to broken HTML + return "
" + htmlEscape(message); + } + public static void setClipboard(String text) { Toolkit.getDefaultToolkit().getSystemClipboard().setContents( new StringSelection(text), clipboardOwner); @@ -189,8 +194,7 @@ public final class SwingHelper { final int messageType) { if (SwingUtilities.isEventDispatchThread()) { - // To force the label to wrap, convert the message to broken HTML - String htmlMessage = "
" + htmlEscape(message); + String htmlMessage = htmlWrap(message); JPanel panel = new JPanel(new BorderLayout(0, detailsText != null ? 20 : 0)); diff --git a/launcher/src/main/resources/com/skcraft/launcher/lang/Launcher.properties b/launcher/src/main/resources/com/skcraft/launcher/lang/Launcher.properties index 652c774..96f1766 100644 --- a/launcher/src/main/resources/com/skcraft/launcher/lang/Launcher.properties +++ b/launcher/src/main/resources/com/skcraft/launcher/lang/Launcher.properties @@ -23,6 +23,7 @@ errors.selfUpdateCheckError=Checking for an update to the launcher has failed. button.cancel=Cancel button.ok=OK button.save=Save +button.launchAnyway=Launch Anyway options.title = Options options.useProxyCheck = Use following proxy in Minecraft @@ -88,6 +89,7 @@ launcher.noInstanceError=Please select a modpack to launch. launcher.noInstanceTitle=No Modpack Selected launcher.launchingTItle=Launching the game... launcher.launchingStatus=Launching ''{0}''. Please wait. +launcher.javaMismatchTitle=Java version warning launcher.modpackColumn=Modpack launcher.notInstalledHint=(not installed) launcher.requiresUpdateHint=(requires update) @@ -191,6 +193,7 @@ runner.updateRequired=This instance must be updated before it can be run. runner.missingLibrary={0} needs to be relaunched and updated because the library ''{1}'' is missing. runner.missingAssetsIndex={0} needs to be relaunched and updated because its asset index is missing. runner.corruptAssetsIndex={0} needs to be relaunched and updated because its asset index is corrupt. +runner.wrongJavaVersion=Instance ''{0}'' requires Java version {1}, but could only find {2}. assets.expanding1=Expanding {0} asset... ({1} remaining) assets.expandingN=Expanding {0} assets... ({1} remaining)