/* * 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; import com.skcraft.launcher.bootstrap.*; import lombok.Getter; import lombok.extern.java.Log; import javax.swing.*; import javax.swing.filechooser.FileSystemView; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.logging.Level; import static com.skcraft.launcher.bootstrap.SharedLocale.tr; @Log public class Bootstrap { private static final int BOOTSTRAP_VERSION = 1; @Getter private final File baseDir; @Getter private final boolean portable; @Getter private final File binariesDir; @Getter private final Properties properties; private final String[] originalArgs; public static void main(String[] args) throws Throwable { SimpleLogFormatter.configureGlobalLogger(); SharedLocale.loadBundle("com.skcraft.launcher.lang.Bootstrap", Locale.getDefault()); boolean portable = isPortableMode(); Bootstrap bootstrap = new Bootstrap(portable, args); try { bootstrap.cleanup(); bootstrap.launch(); } catch (Throwable t) { Bootstrap.log.log(Level.WARNING, "Error", t); Bootstrap.setSwingLookAndFeel(); SwingHelper.showErrorDialog(null, tr("errors.bootstrapError"), tr("errorTitle"), t); } } public Bootstrap(boolean portable, String[] args) throws IOException { this.properties = BootstrapUtils.loadProperties(Bootstrap.class, "bootstrap.properties"); File baseDir = portable ? new File(".") : getUserLauncherDir(); this.baseDir = baseDir; this.portable = portable; this.binariesDir = new File(baseDir, "launcher"); this.originalArgs = args; binariesDir.mkdirs(); } public void cleanup() { File[] files = binariesDir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getName().endsWith(".tmp"); } }); if (files != null) { for (File file : files) { file.delete(); } } } public void launch() throws Throwable { File[] files = binariesDir.listFiles(new LauncherBinary.Filter()); List<LauncherBinary> binaries = new ArrayList<LauncherBinary>(); if (files != null) { for (File file : files) { Bootstrap.log.info("Found " + file.getAbsolutePath() + "..."); binaries.add(new LauncherBinary(file)); } } if (!binaries.isEmpty()) { launchExisting(binaries, true); } else { launchInitial(); } } public void launchInitial() throws Exception { Bootstrap.log.info("Downloading the launcher..."); Thread thread = new Thread(new Downloader(this)); thread.start(); } public void launchExisting(List<LauncherBinary> binaries, boolean redownload) throws Exception { Collections.sort(binaries); LauncherBinary working = null; Class<?> clazz = null; for (LauncherBinary binary : binaries) { File testFile = binary.getPath(); try { testFile = binary.getExecutableJar(); Bootstrap.log.info("Trying " + testFile.getAbsolutePath() + "..."); clazz = load(testFile); Bootstrap.log.info("Launcher loaded successfully."); working = binary; break; } catch (Throwable t) { Bootstrap.log.log(Level.WARNING, "Failed to load " + testFile.getAbsoluteFile(), t); } } if (working != null) { for (LauncherBinary binary : binaries) { if (working != binary) { log.info("Removing " + binary.getPath() + "..."); binary.remove(); } } execute(clazz); } else { if (redownload) { launchInitial(); } else { throw new IOException("Failed to find launchable .jar"); } } } public void execute(Class<?> clazz) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { Method method = clazz.getDeclaredMethod("main", String[].class); String[] launcherArgs; if (portable) { launcherArgs = new String[] { "--portable", "--dir", baseDir.getAbsolutePath(), "--bootstrap-version", String.valueOf(BOOTSTRAP_VERSION) }; } else { launcherArgs = new String[] { "--dir", baseDir.getAbsolutePath(), "--bootstrap-version", String.valueOf(BOOTSTRAP_VERSION) }; } String[] args = new String[originalArgs.length + launcherArgs.length]; System.arraycopy(launcherArgs, 0, args, 0, launcherArgs.length); System.arraycopy(originalArgs, 0, args, launcherArgs.length, originalArgs.length); log.info("Launching with arguments " + Arrays.toString(args)); method.invoke(null, new Object[] { args }); } public Class<?> load(File jarFile) throws MalformedURLException, ClassNotFoundException { URL[] urls = new URL[] { jarFile.toURI().toURL() }; URLClassLoader child = new URLClassLoader(urls, this.getClass().getClassLoader()); Class<?> clazz = Class.forName(getProperties().getProperty("launcherClass"), true, child); return clazz; } public static void setSwingLookAndFeel() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Throwable e) { } } private static File getFileChooseDefaultDir() { JFileChooser chooser = new JFileChooser(); FileSystemView fsv = chooser.getFileSystemView(); return fsv.getDefaultDirectory(); } private File getUserLauncherDir() { String osName = System.getProperty("os.name").toLowerCase(); if (osName.contains("win")) { return new File(getFileChooseDefaultDir(), getProperties().getProperty("homeFolderWindows")); } else { return new File(System.getProperty("user.home"), getProperties().getProperty("homeFolder")); } } private static boolean isPortableMode() { return new File("portable.txt").exists(); } }