/* * This file is part of The Technic Launcher Version 3. * Copyright ©2015 Syndicate, LLC * * The Technic Launcher 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. * * The Technic Launcher 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 the Technic Launcher. If not, see <http://www.gnu.org/licenses/>. */ package net.technicpack.launcher.launch; import net.technicpack.launcher.ui.components.FixRunDataDialog; import net.technicpack.launchercore.TechnicConstants; import net.technicpack.launchercore.launch.java.IJavaVersion; import net.technicpack.launchercore.launch.java.JavaVersionRepository; import net.technicpack.launchercore.modpacks.RunData; import net.technicpack.minecraftcore.mojang.version.MojangVersion; import net.technicpack.minecraftcore.mojang.version.MojangVersionBuilder; import net.technicpack.minecraftcore.mojang.version.builder.FileVersionBuilder; import net.technicpack.minecraftcore.mojang.version.builder.MojangVersionRetriever; import net.technicpack.minecraftcore.mojang.version.builder.retrievers.HttpFileRetriever; import net.technicpack.minecraftcore.mojang.version.builder.retrievers.ZipFileRetriever; import net.technicpack.minecraftcore.mojang.version.chain.ChainVersionBuilder; import net.technicpack.ui.lang.ResourceLoader; import net.technicpack.launcher.settings.StartupParameters; import net.technicpack.launcher.settings.TechnicSettings; import net.technicpack.launcher.ui.LauncherFrame; import net.technicpack.launchercore.exception.BuildInaccessibleException; import net.technicpack.launchercore.exception.CacheDeleteException; import net.technicpack.launchercore.exception.DownloadException; import net.technicpack.launchercore.exception.PackNotAvailableOfflineException; import net.technicpack.launchercore.install.InstallTasksQueue; import net.technicpack.launchercore.install.ModpackInstaller; import net.technicpack.launchercore.install.Version; import net.technicpack.launchercore.install.tasks.*; import net.technicpack.launchercore.install.verifiers.ValidZipFileVerifier; import net.technicpack.minecraftcore.launch.LaunchOptions; import net.technicpack.minecraftcore.install.tasks.*; import net.technicpack.minecraftcore.launch.MinecraftLauncher; import net.technicpack.launchercore.mirror.MirrorStore; import net.technicpack.launchercore.modpacks.ModpackModel; import net.technicpack.launchercore.modpacks.resources.PackResourceMapper; import net.technicpack.launchercore.util.DownloadListener; import net.technicpack.launchercore.util.LaunchAction; import net.technicpack.launchercore.install.LauncherDirectories; import net.technicpack.rest.io.Modpack; import net.technicpack.rest.io.PackInfo; import net.technicpack.utilslib.Memory; import net.technicpack.utilslib.OperatingSystem; import net.technicpack.utilslib.Utils; import javax.rmi.CORBA.Util; import javax.swing.*; import java.awt.*; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.zip.ZipException; public class Installer { protected final ModpackInstaller<MojangVersion> installer; protected final MinecraftLauncher launcher; protected final TechnicSettings settings; protected final PackResourceMapper packIconMapper; protected final StartupParameters startupParameters; protected final MirrorStore mirrorStore; protected final LauncherDirectories directories; protected Object cancelLock = new Object(); protected boolean isCancelledByUser = false; private Thread runningThread; private LauncherUnhider launcherUnhider; public Installer(StartupParameters startupParameters, MirrorStore mirrorStore, LauncherDirectories directories, ModpackInstaller installer, MinecraftLauncher launcher, TechnicSettings settings, PackResourceMapper packIconMapper) { this.installer = installer; this.launcher = launcher; this.settings = settings; this.packIconMapper = packIconMapper; this.startupParameters = startupParameters; this.mirrorStore = mirrorStore; this.directories = directories; } public void cancel() { Utils.getLogger().info("User pressed cancel button."); synchronized (cancelLock) { isCancelledByUser = true; } runningThread.interrupt(); } public void justInstall(final ResourceLoader resources, final ModpackModel pack, final String build, final boolean doFullInstall, final LauncherFrame frame, final DownloadListener listener) { internalInstallAndRun(resources, pack, build, doFullInstall, frame, listener, false); } public void installAndRun(final ResourceLoader resources, final ModpackModel pack, final String build, final boolean doFullInstall, final LauncherFrame frame, final DownloadListener listener) { internalInstallAndRun(resources, pack, build, doFullInstall, frame, listener, true); } protected void internalInstallAndRun(final ResourceLoader resources, final ModpackModel pack, final String build, final boolean doFullInstall, final LauncherFrame frame, final DownloadListener listener, final boolean doLaunch) { runningThread = new Thread(new Runnable() { @Override public void run() { boolean everythingWorked = false; try { MojangVersion version = null; InstallTasksQueue<MojangVersion> tasksQueue = new InstallTasksQueue<MojangVersion>(listener, mirrorStore); MojangVersionBuilder versionBuilder = createVersionBuilder(pack, tasksQueue); if (!pack.isLocalOnly() && build != null && !build.isEmpty()) { buildTasksQueue(tasksQueue, resources, pack, build, doFullInstall, versionBuilder); version = installer.installPack(tasksQueue, pack, build); } else { version = versionBuilder.buildVersionFromKey(null); if (version != null) pack.initDirectories(); } if (doLaunch) { if (version == null) { throw new PackNotAvailableOfflineException(pack.getDisplayName()); } JavaVersionRepository javaVersions = launcher.getJavaVersions(); Memory memoryObj = Memory.getClosestAvailableMemory(Memory.getMemoryFromId(settings.getMemory()), javaVersions.getSelectedVersion().is64Bit()); long memory = memoryObj.getMemoryMB(); String versionNumber = javaVersions.getSelectedVersion().getVersionNumber(); RunData data = pack.getRunData(); if (data != null && !data.isRunDataValid(memory, versionNumber)) { FixRunDataDialog dialog = new FixRunDataDialog(frame, resources, data, javaVersions, memoryObj, !settings.shouldAutoAcceptModpackRequirements()); dialog.setVisible(true); if (dialog.getResult() == FixRunDataDialog.Result.ACCEPT) { memoryObj = dialog.getRecommendedMemory(); memory = memoryObj.getMemoryMB(); IJavaVersion recommendedJavaVersion = dialog.getRecommendedJavaVersion(); javaVersions.selectVersion(recommendedJavaVersion.getVersionNumber(), recommendedJavaVersion.is64Bit()); if (dialog.shouldRemember()) { settings.setAutoAcceptModpackRequirements(true); } } else return; } LaunchAction launchAction = settings.getLaunchAction(); if (launchAction == null || launchAction == LaunchAction.HIDE) { launcherUnhider = new LauncherUnhider(settings, frame); } else launcherUnhider = null; LaunchOptions options = new LaunchOptions(pack.getDisplayName(), packIconMapper.getImageLocation(pack).getAbsolutePath(), settings); launcher.launch(pack, memory, options, launcherUnhider, version); if (launchAction == null || launchAction == LaunchAction.HIDE) { frame.setVisible(false); } else if (launchAction == LaunchAction.NOTHING) { EventQueue.invokeLater(new Runnable() { @Override public void run() { frame.launchCompleted(); } }); } else if (launchAction == LaunchAction.CLOSE) { System.exit(0); } } everythingWorked = true; } catch (InterruptedException e) { boolean cancelledByUser = false; synchronized (cancelLock) { if (isCancelledByUser) { cancelledByUser = true; isCancelledByUser = false; } } //Canceled by user if (!cancelledByUser) { if (e.getCause() != null) Utils.getLogger().info("Cancelled by exception."); else Utils.getLogger().info("Cancelled by code."); e.printStackTrace(); } else Utils.getLogger().info("Cancelled by user."); } catch (PackNotAvailableOfflineException e) { JOptionPane.showMessageDialog(frame, e.getMessage(), resources.getString("launcher.installerror.unavailable"), JOptionPane.WARNING_MESSAGE); } catch (DownloadException e) { JOptionPane.showMessageDialog(frame, resources.getString("launcher.installerror.download", pack.getDisplayName(), e.getMessage()), resources.getString("launcher.installerror.title"), JOptionPane.WARNING_MESSAGE); } catch (ZipException e) { JOptionPane.showMessageDialog(frame, resources.getString("launcher.installerror.unzip", pack.getDisplayName(), e.getMessage()), resources.getString("launcher.installerror.title"), JOptionPane.WARNING_MESSAGE); } catch (CacheDeleteException e) { JOptionPane.showMessageDialog(frame, resources.getString("launcher.installerror.cache", pack.getDisplayName(), e.getMessage()), resources.getString("launcher.installerror.title"), JOptionPane.WARNING_MESSAGE); } catch (BuildInaccessibleException e) { e.printStackTrace(); JOptionPane.showMessageDialog(frame, e.getMessage(), resources.getString("launcher.installerror.title"), JOptionPane.WARNING_MESSAGE); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (!everythingWorked || !doLaunch) { EventQueue.invokeLater(new Runnable() { @Override public void run() { frame.launchCompleted(); } }); } } } }) { ///Interrupt is being called from a mysterious source, so unless this is a user-initiated cancel ///Let's print the stack trace of the interruptor. @Override public void interrupt() { boolean userCancelled = false; synchronized (cancelLock) { if (isCancelledByUser) userCancelled = true; } if (!userCancelled) { Utils.getLogger().info("Mysterious interruption source."); try { //I am a charlatan and a hack. throw new Exception("Grabbing stack trace- this isn't necessarily an error."); } catch (Exception ex) { ex.printStackTrace(); } } super.interrupt(); } }; runningThread.start(); } public boolean isCurrentlyRunning() { if (runningThread != null && runningThread.isAlive()) return true; if (launcherUnhider != null && !launcherUnhider.hasExited()) return true; return false; } public void buildTasksQueue(InstallTasksQueue queue, ResourceLoader resources, ModpackModel modpack, String build, boolean doFullInstall, MojangVersionBuilder versionBuilder) throws CacheDeleteException, BuildInaccessibleException { PackInfo packInfo = modpack.getPackInfo(); Modpack modpackData = packInfo.getModpack(build); if (modpackData.getGameVersion() == null) return; String minecraft = modpackData.getGameVersion(); Version installedVersion = modpack.getInstalledVersion(); TaskGroup examineModpackData = new TaskGroup(resources.getString("install.message.examiningmodpack")); TaskGroup checkVersionFile = new TaskGroup(resources.getString("install.message.checkversionfile")); TaskGroup installVersionFile = new TaskGroup(resources.getString("install.message.installversionfile")); TaskGroup examineVersionFile = new TaskGroup(resources.getString("install.message.examiningversionfile")); TaskGroup verifyingFiles = new TaskGroup(resources.getString("install.message.verifyingfiles")); TaskGroup downloadingMods = new TaskGroup(resources.getString("install.message.downloadmods")); TaskGroup installingMods = new TaskGroup(resources.getString("install.message.installmods")); TaskGroup installingLibs = new TaskGroup(resources.getString("install.message.installlibs")); TaskGroup installingMinecraft = new TaskGroup(resources.getString("install.message.installminecraft")); TaskGroup examineIndex = new TaskGroup(resources.getString("install.message.examiningindex")); TaskGroup verifyingAssets = new TaskGroup(resources.getString("install.message.verifyassets")); TaskGroup installingAssets = new TaskGroup(resources.getString("install.message.installassets")); TaskGroup grabLibs = new TaskGroup(resources.getString("install.message.grablibraries")); TaskGroup checkNonMavenLibs = new TaskGroup(resources.getString("install.message.nonmavenlibs")); TaskGroup rundataTaskGroup = new TaskGroup(resources.getString("install.message.runData")); queue.addTask(examineModpackData); queue.addTask(verifyingFiles); queue.addTask(downloadingMods); queue.addTask(installingMods); queue.addTask(checkVersionFile); queue.addTask(installVersionFile); queue.addTask(rundataTaskGroup); queue.addTask(examineVersionFile); queue.addTask(grabLibs); queue.addTask(checkNonMavenLibs); queue.addTask(installingLibs); queue.addTask(installingMinecraft); queue.addTask(examineIndex); queue.addTask(verifyingAssets); queue.addTask(installingAssets); if (OperatingSystem.getOperatingSystem() == OperatingSystem.OSX) queue.addTask(new CopyDylibJnilibTask(modpack)); if (minecraft.startsWith("1.5")) { verifyingFiles.addTask(new EnsureFileTask(new File(directories.getCacheDirectory(), "fml_libs15.zip"), new ValidZipFileVerifier(), new File(modpack.getInstalledDirectory(), "lib"), "http://mirror.technicpack.net/Technic/lib/fml/fml_libs15.zip", installingLibs, installingLibs)); } else if (minecraft.startsWith("1.4")) { verifyingFiles.addTask(new EnsureFileTask(new File(directories.getCacheDirectory(), "fml_libs.zip"), new ValidZipFileVerifier(), new File(modpack.getInstalledDirectory(), "lib"), "http://mirror.technicpack.net/Technic/lib/fml/fml_libs.zip", installingLibs, installingLibs)); } if (doFullInstall) { //If we're installing a new version of modpack, then we need to get rid of the existing version.json File versionFile = new File(modpack.getBinDir(), "version.json"); if (versionFile.exists()) { if (!versionFile.delete()) { throw new CacheDeleteException(versionFile.getAbsolutePath()); } } examineModpackData.addTask(new InstallModpackTask(modpack, modpackData, verifyingFiles, downloadingMods, installingMods)); } if (doFullInstall) rundataTaskGroup.addTask(new WriteRundataFile(modpack, modpackData)); else rundataTaskGroup.addTask(new CheckRundataFile(modpack, modpackData, rundataTaskGroup)); checkVersionFile.addTask(new VerifyVersionFilePresentTask(modpack, minecraft, versionBuilder)); examineVersionFile.addTask(new HandleVersionFileTask(modpack, directories, checkNonMavenLibs, grabLibs, installingLibs, installingLibs, versionBuilder)); examineVersionFile.addTask(new EnsureAssetsIndexTask(directories.getAssetsDirectory(), installingMinecraft, examineIndex, verifyingAssets, installingAssets, installingAssets)); if (doFullInstall || (installedVersion != null && installedVersion.isLegacy())) installingMinecraft.addTask(new InstallMinecraftIfNecessaryTask(modpack, minecraft, directories.getCacheDirectory())); } private MojangVersionBuilder createVersionBuilder(ModpackModel modpack, InstallTasksQueue tasksQueue) { ZipFileRetriever zipVersionRetriever = new ZipFileRetriever(new File(modpack.getBinDir(), "modpack.jar")); HttpFileRetriever fallbackVersionRetriever = new HttpFileRetriever(mirrorStore, TechnicConstants.technicVersions, tasksQueue.getDownloadListener()); ArrayList<MojangVersionRetriever> fallbackRetrievers = new ArrayList<MojangVersionRetriever>(1); fallbackRetrievers.add(fallbackVersionRetriever); File versionJson = new File(modpack.getBinDir(), "version.json"); FileVersionBuilder zipVersionBuilder = new FileVersionBuilder(versionJson, zipVersionRetriever, fallbackRetrievers); FileVersionBuilder webVersionBuilder = new FileVersionBuilder(modpack.getBinDir(), null, fallbackRetrievers); return new ChainVersionBuilder(zipVersionBuilder, webVersionBuilder); } }