diff --git a/src/main/java/com/skcraft/launcher/auth/OfflineSession.java b/src/main/java/com/skcraft/launcher/auth/OfflineSession.java index 04223df..0431b2c 100644 --- a/src/main/java/com/skcraft/launcher/auth/OfflineSession.java +++ b/src/main/java/com/skcraft/launcher/auth/OfflineSession.java @@ -62,4 +62,9 @@ return UserType.LEGACY; } + @Override + public boolean isOnline() { + return false; + } + } diff --git a/src/main/java/com/skcraft/launcher/auth/Session.java b/src/main/java/com/skcraft/launcher/auth/Session.java index 5aa5adf..95b3e58 100644 --- a/src/main/java/com/skcraft/launcher/auth/Session.java +++ b/src/main/java/com/skcraft/launcher/auth/Session.java @@ -64,4 +64,11 @@ */ UserType getUserType(); + /** + * Return true if the user is in an online session. + * + * @return true if online + */ + boolean isOnline(); + } diff --git a/src/main/java/com/skcraft/launcher/auth/YggdrasilLoginService.java b/src/main/java/com/skcraft/launcher/auth/YggdrasilLoginService.java index ca97a47..b686953 100644 --- a/src/main/java/com/skcraft/launcher/auth/YggdrasilLoginService.java +++ b/src/main/java/com/skcraft/launcher/auth/YggdrasilLoginService.java @@ -118,6 +118,11 @@ public UserType getUserType() { return legacy ? UserType.LEGACY : UserType.MOJANG; } + + @Override + public boolean isOnline() { + return true; + } } } diff --git a/src/main/java/com/skcraft/launcher/dialog/LauncherFrame.java b/src/main/java/com/skcraft/launcher/dialog/LauncherFrame.java index d6783c1..92fe0da 100644 --- a/src/main/java/com/skcraft/launcher/dialog/LauncherFrame.java +++ b/src/main/java/com/skcraft/launcher/dialog/LauncherFrame.java @@ -14,7 +14,7 @@ import com.skcraft.launcher.InstanceList; import com.skcraft.launcher.Launcher; import com.skcraft.launcher.auth.Session; -import com.skcraft.launcher.launch.InstanceLauncher; +import com.skcraft.launcher.launch.Runner; import com.skcraft.launcher.launch.LaunchProcessHandler; import com.skcraft.launcher.persistence.Persistence; import com.skcraft.launcher.selfupdate.UpdateChecker; @@ -430,6 +430,7 @@ if (update) { // Execute the updater Updater updater = new Updater(launcher, instance); + updater.setOnline(session.isOnline()); ObservableFuture future = new ObservableFuture( launcher.getExecutor().submit(updater), updater); @@ -469,7 +470,7 @@ final File extractDir = launcher.createExtractDir(); // Get the process - InstanceLauncher task = new InstanceLauncher(launcher, instance, session, extractDir); + Runner task = new Runner(launcher, instance, session, extractDir); ObservableFuture processFuture = new ObservableFuture( launcher.getExecutor().submit(task), task); diff --git a/src/main/java/com/skcraft/launcher/install/HttpDownloader.java b/src/main/java/com/skcraft/launcher/install/HttpDownloader.java index 30a85f0..71b0060 100644 --- a/src/main/java/com/skcraft/launcher/install/HttpDownloader.java +++ b/src/main/java/com/skcraft/launcher/install/HttpDownloader.java @@ -135,7 +135,7 @@ synchronized (this) { if (failed.size() > 0) { - throw new IOException(failed.size() + "files could not be downloaded"); + throw new IOException(failed.size() + " files could not be downloaded"); } } } finally { diff --git a/src/main/java/com/skcraft/launcher/launch/InstanceLauncher.java b/src/main/java/com/skcraft/launcher/launch/InstanceLauncher.java deleted file mode 100644 index b5eae54..0000000 --- a/src/main/java/com/skcraft/launcher/launch/InstanceLauncher.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.launch; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Strings; -import com.google.common.io.Files; -import com.skcraft.concurrency.DefaultProgress; -import com.skcraft.concurrency.ProgressObservable; -import com.skcraft.launcher.AssetsRoot; -import com.skcraft.launcher.Configuration; -import com.skcraft.launcher.Instance; -import com.skcraft.launcher.Launcher; -import com.skcraft.launcher.auth.Session; -import com.skcraft.launcher.install.ZipExtract; -import com.skcraft.launcher.model.minecraft.AssetsIndex; -import com.skcraft.launcher.model.minecraft.Library; -import com.skcraft.launcher.model.minecraft.VersionManifest; -import com.skcraft.launcher.util.Environment; -import com.skcraft.launcher.util.Platform; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import lombok.extern.java.Log; -import org.apache.commons.lang.text.StrSubstitutor; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; - -import static com.skcraft.launcher.LauncherUtils.checkInterrupted; -import static com.skcraft.launcher.util.SharedLocale._; - -/** - * Handles the launching of an instance. - */ -@Log -public class InstanceLauncher implements Callable, ProgressObservable { - - private ProgressObservable progress = new DefaultProgress(0, _("instanceLauncher.preparing")); - - private final ObjectMapper mapper = new ObjectMapper(); - private final Launcher launcher; - private final Instance instance; - private final Session session; - private final File extractDir; - @Getter @Setter private Environment environment = Environment.getInstance(); - - private VersionManifest versionManifest; - private AssetsIndex assetsIndex; - private File virtualAssetsDir; - private Configuration config; - private JavaProcessBuilder builder; - private AssetsRoot assetsRoot; - - /** - * Create a new instance launcher. - * - * @param launcher the launcher - * @param instance the instance - * @param session the session - * @param extractDir the directory to extract to - */ - public InstanceLauncher(@NonNull Launcher launcher, @NonNull Instance instance, - @NonNull Session session, @NonNull File extractDir) { - this.launcher = launcher; - this.instance = instance; - this.session = session; - this.extractDir = extractDir; - } - - /** - * Get the path to the JAR. - * - * @return the JAR path - */ - private File getJarPath() { - File jarPath = instance.getCustomJarPath(); - if (!jarPath.exists()) { - jarPath = launcher.getJarPath(versionManifest); - } - return jarPath; - } - - @Override - public Process call() throws Exception { - config = launcher.getConfig(); - builder = new JavaProcessBuilder(); - assetsRoot = launcher.getAssets(); - - // Load versionManifest and assets index - versionManifest = mapper.readValue(instance.getVersionPath(), VersionManifest.class); - assetsIndex = mapper.readValue(assetsRoot.getIndexPath(versionManifest), AssetsIndex.class); - - // Copy over assets to the tree - AssetsRoot.AssetsTreeBuilder assetsBuilder = assetsRoot.createAssetsBuilder(versionManifest); - progress = assetsBuilder; - virtualAssetsDir = assetsBuilder.build(); - - progress = new DefaultProgress(0.9, _("instanceLauncher.collectingArgs")); - - addJvmArgs(); - addLibraries(); - addJarArgs(); - addProxyArgs(); - addWindowArgs(); - addPlatformArgs(); - - builder.classPath(getJarPath()); - builder.setMainClass(versionManifest.getMainClass()); - - ProcessBuilder processBuilder = new ProcessBuilder(builder.buildCommand()); - processBuilder.directory(instance.getContentDir()); - log.info("Launching: " + builder); - checkInterrupted(); - - progress = new DefaultProgress(1, _("instanceLauncher.startingJava")); - - return processBuilder.start(); - } - - /** - * Add platform-specific arguments. - */ - private void addPlatformArgs() { - // Mac OS X arguments - if (getEnvironment().getPlatform() == Platform.MAC_OS_X) { - File icnsPath = assetsIndex.getObjectPath(assetsRoot, "icons/minecraft.icns"); - if (icnsPath != null) { - builder.getFlags().add("-Xdock:icon=" + icnsPath.getAbsolutePath()); - builder.getFlags().add("-Xdock:name=Minecraft"); - } - } - - // Windows arguments - if (getEnvironment().getPlatform() == Platform.WINDOWS) { - builder.getFlags().add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump"); - } - } - - /** - * Add libraries. - */ - private void addLibraries() { - // Add libraries to classpath or extract the libraries as necessary - for (Library library : versionManifest.getLibraries()) { - File path = new File(launcher.getLibrariesDir(), library.getPath(environment)); - - if (path.exists()) { - Library.Extract extract = library.getExtract(); - if (extract != null) { - ZipExtract zipExtract = new ZipExtract(Files.asByteSource(path), extractDir); - zipExtract.setExclude(extract.getExclude()); - zipExtract.run(); - } else { - builder.classPath(path); - } - } - } - - builder.getFlags().add("-Djava.library.path=" + extractDir.getAbsoluteFile()); - } - - /** - * Add JVM arguments. - * - * @throws IOException on I/O error - */ - private void addJvmArgs() throws IOException { - int minMemory = config.getMinMemory(); - int maxMemory = config.getMaxMemory(); - int permGen = config.getPermGen(); - - if (minMemory <= 0) { - minMemory = 1024; - } - - if (maxMemory <= 0) { - maxMemory = 1024; - } - - if (permGen <= 0) { - permGen = 128; - } - - if (permGen <= 64) { - permGen = 64; - } - - if (minMemory > maxMemory) { - maxMemory = minMemory; - } - - builder.setMinMemory(minMemory); - builder.setMaxMemory(maxMemory); - builder.setPermGen(permGen); - - String rawJvmPath = config.getJvmPath(); - if (!Strings.isNullOrEmpty(rawJvmPath)) { - builder.tryJvmPath(new File(rawJvmPath)); - } - - String rawJvmArgs = config.getJvmArgs(); - if (!Strings.isNullOrEmpty(rawJvmArgs)) { - List flags = builder.getFlags(); - - for (String arg : JavaProcessBuilder.splitArgs(rawJvmArgs)) { - flags.add(arg); - } - } - } - - /** - * Add arguments for the application. - * - * @throws JsonProcessingException on error - */ - private void addJarArgs() throws JsonProcessingException { - List args = builder.getArgs(); - - String[] rawArgs = versionManifest.getMinecraftArguments().split(" +"); - StrSubstitutor substitutor = new StrSubstitutor(getCommandSubstitutions()); - for (String arg : rawArgs) { - args.add(substitutor.replace(arg)); - } - } - - /** - * Add proxy arguments. - */ - private void addProxyArgs() { - List args = builder.getArgs(); - - if (config.isProxyEnabled()) { - String host = config.getProxyHost(); - int port = config.getProxyPort(); - String username = config.getProxyUsername(); - String password = config.getProxyPassword(); - - if (!Strings.isNullOrEmpty(host) && port > 0 && port < 65535) { - args.add("--proxyHost"); - args.add(config.getProxyHost()); - args.add("--proxyPort"); - args.add(String.valueOf(port)); - - if (!Strings.isNullOrEmpty(username)) { - builder.getArgs().add("--proxyUser"); - builder.getArgs().add(username); - builder.getArgs().add("--proxyPass"); - builder.getArgs().add(password); - } - } - } - } - - /** - * Add window arguments. - */ - private void addWindowArgs() { - List args = builder.getArgs(); - int width = config.getWindowWidth(); - int height = config.getWidowHeight(); - - if (width >= 10) { - args.add("--width"); - args.add(String.valueOf(width)); - args.add("--height"); - args.add(String.valueOf(height)); - } - } - - /** - * Build the list of command substitutions. - * - * @return the map of substitutions - * @throws JsonProcessingException on error - */ - private Map getCommandSubstitutions() throws JsonProcessingException { - Map map = new HashMap(); - - map.put("version_name", versionManifest.getId()); - - map.put("auth_access_token", session.getAccessToken()); - map.put("auth_session", session.getSessionToken()); - map.put("auth_player_name", session.getName()); - map.put("auth_uuid", session.getUuid()); - - map.put("profile_name", session.getName()); - map.put("user_type", session.getUserType().getName()); - map.put("user_properties", mapper.writeValueAsString(session.getUserProperties())); - - map.put("game_directory", instance.getContentDir().getAbsolutePath()); - map.put("game_assets", virtualAssetsDir.getAbsolutePath()); - map.put("assets_root", launcher.getAssets().getDir().getAbsolutePath()); - map.put("assets_index_name", versionManifest.getAssetsIndex()); - - return map; - } - - @Override - public double getProgress() { - return progress.getProgress(); - } - - @Override - public String getStatus() { - return progress.getStatus(); - } - -} diff --git a/src/main/java/com/skcraft/launcher/launch/Runner.java b/src/main/java/com/skcraft/launcher/launch/Runner.java new file mode 100644 index 0000000..a3237cb --- /dev/null +++ b/src/main/java/com/skcraft/launcher/launch/Runner.java @@ -0,0 +1,319 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.launch; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; +import com.google.common.io.Files; +import com.skcraft.concurrency.DefaultProgress; +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.model.minecraft.AssetsIndex; +import com.skcraft.launcher.model.minecraft.Library; +import com.skcraft.launcher.model.minecraft.VersionManifest; +import com.skcraft.launcher.util.Environment; +import com.skcraft.launcher.util.Platform; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import lombok.extern.java.Log; +import org.apache.commons.lang.text.StrSubstitutor; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +import static com.skcraft.launcher.LauncherUtils.checkInterrupted; +import static com.skcraft.launcher.util.SharedLocale._; + +/** + * Handles the launching of an instance. + */ +@Log +public class Runner implements Callable, ProgressObservable { + + private ProgressObservable progress = new DefaultProgress(0, _("runner.preparing")); + + private final ObjectMapper mapper = new ObjectMapper(); + private final Launcher launcher; + private final Instance instance; + private final Session session; + private final File extractDir; + @Getter @Setter private Environment environment = Environment.getInstance(); + + private VersionManifest versionManifest; + private AssetsIndex assetsIndex; + private File virtualAssetsDir; + private Configuration config; + private JavaProcessBuilder builder; + private AssetsRoot assetsRoot; + + /** + * Create a new instance launcher. + * + * @param launcher the launcher + * @param instance the instance + * @param session the session + * @param extractDir the directory to extract to + */ + public Runner(@NonNull Launcher launcher, @NonNull Instance instance, + @NonNull Session session, @NonNull File extractDir) { + this.launcher = launcher; + this.instance = instance; + this.session = session; + this.extractDir = extractDir; + } + + /** + * Get the path to the JAR. + * + * @return the JAR path + */ + private File getJarPath() { + File jarPath = instance.getCustomJarPath(); + if (!jarPath.exists()) { + jarPath = launcher.getJarPath(versionManifest); + } + return jarPath; + } + + @Override + public Process call() throws Exception { + if (!instance.isInstalled()) { + throw new LauncherException("Update required", _("runner.updateRequired")); + } + + config = launcher.getConfig(); + builder = new JavaProcessBuilder(); + assetsRoot = launcher.getAssets(); + + // Load versionManifest and assets index + versionManifest = mapper.readValue(instance.getVersionPath(), VersionManifest.class); + assetsIndex = mapper.readValue(assetsRoot.getIndexPath(versionManifest), AssetsIndex.class); + + // Copy over assets to the tree + AssetsRoot.AssetsTreeBuilder assetsBuilder = assetsRoot.createAssetsBuilder(versionManifest); + progress = assetsBuilder; + virtualAssetsDir = assetsBuilder.build(); + + progress = new DefaultProgress(0.9, _("runner.collectingArgs")); + + addJvmArgs(); + addLibraries(); + addJarArgs(); + addProxyArgs(); + addWindowArgs(); + addPlatformArgs(); + + builder.classPath(getJarPath()); + builder.setMainClass(versionManifest.getMainClass()); + + ProcessBuilder processBuilder = new ProcessBuilder(builder.buildCommand()); + processBuilder.directory(instance.getContentDir()); + Runner.log.info("Launching: " + builder); + checkInterrupted(); + + progress = new DefaultProgress(1, _("runner.startingJava")); + + return processBuilder.start(); + } + + /** + * Add platform-specific arguments. + */ + private void addPlatformArgs() { + // Mac OS X arguments + if (getEnvironment().getPlatform() == Platform.MAC_OS_X) { + File icnsPath = assetsIndex.getObjectPath(assetsRoot, "icons/minecraft.icns"); + if (icnsPath != null) { + builder.getFlags().add("-Xdock:icon=" + icnsPath.getAbsolutePath()); + builder.getFlags().add("-Xdock:name=Minecraft"); + } + } + + // Windows arguments + if (getEnvironment().getPlatform() == Platform.WINDOWS) { + builder.getFlags().add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump"); + } + } + + /** + * Add libraries. + */ + private void addLibraries() { + // Add libraries to classpath or extract the libraries as necessary + for (Library library : versionManifest.getLibraries()) { + File path = new File(launcher.getLibrariesDir(), library.getPath(environment)); + + if (path.exists()) { + Library.Extract extract = library.getExtract(); + if (extract != null) { + ZipExtract zipExtract = new ZipExtract(Files.asByteSource(path), extractDir); + zipExtract.setExclude(extract.getExclude()); + zipExtract.run(); + } else { + builder.classPath(path); + } + } + } + + builder.getFlags().add("-Djava.library.path=" + extractDir.getAbsoluteFile()); + } + + /** + * Add JVM arguments. + * + * @throws IOException on I/O error + */ + private void addJvmArgs() throws IOException { + int minMemory = config.getMinMemory(); + int maxMemory = config.getMaxMemory(); + int permGen = config.getPermGen(); + + if (minMemory <= 0) { + minMemory = 1024; + } + + if (maxMemory <= 0) { + maxMemory = 1024; + } + + if (permGen <= 0) { + permGen = 128; + } + + if (permGen <= 64) { + permGen = 64; + } + + if (minMemory > maxMemory) { + maxMemory = minMemory; + } + + builder.setMinMemory(minMemory); + builder.setMaxMemory(maxMemory); + builder.setPermGen(permGen); + + String rawJvmPath = config.getJvmPath(); + if (!Strings.isNullOrEmpty(rawJvmPath)) { + builder.tryJvmPath(new File(rawJvmPath)); + } + + String rawJvmArgs = config.getJvmArgs(); + if (!Strings.isNullOrEmpty(rawJvmArgs)) { + List flags = builder.getFlags(); + + for (String arg : JavaProcessBuilder.splitArgs(rawJvmArgs)) { + flags.add(arg); + } + } + } + + /** + * Add arguments for the application. + * + * @throws JsonProcessingException on error + */ + private void addJarArgs() throws JsonProcessingException { + List args = builder.getArgs(); + + String[] rawArgs = versionManifest.getMinecraftArguments().split(" +"); + StrSubstitutor substitutor = new StrSubstitutor(getCommandSubstitutions()); + for (String arg : rawArgs) { + args.add(substitutor.replace(arg)); + } + } + + /** + * Add proxy arguments. + */ + private void addProxyArgs() { + List args = builder.getArgs(); + + if (config.isProxyEnabled()) { + String host = config.getProxyHost(); + int port = config.getProxyPort(); + String username = config.getProxyUsername(); + String password = config.getProxyPassword(); + + if (!Strings.isNullOrEmpty(host) && port > 0 && port < 65535) { + args.add("--proxyHost"); + args.add(config.getProxyHost()); + args.add("--proxyPort"); + args.add(String.valueOf(port)); + + if (!Strings.isNullOrEmpty(username)) { + builder.getArgs().add("--proxyUser"); + builder.getArgs().add(username); + builder.getArgs().add("--proxyPass"); + builder.getArgs().add(password); + } + } + } + } + + /** + * Add window arguments. + */ + private void addWindowArgs() { + List args = builder.getArgs(); + int width = config.getWindowWidth(); + int height = config.getWidowHeight(); + + if (width >= 10) { + args.add("--width"); + args.add(String.valueOf(width)); + args.add("--height"); + args.add(String.valueOf(height)); + } + } + + /** + * Build the list of command substitutions. + * + * @return the map of substitutions + * @throws JsonProcessingException on error + */ + private Map getCommandSubstitutions() throws JsonProcessingException { + Map map = new HashMap(); + + map.put("version_name", versionManifest.getId()); + + map.put("auth_access_token", session.getAccessToken()); + map.put("auth_session", session.getSessionToken()); + map.put("auth_player_name", session.getName()); + map.put("auth_uuid", session.getUuid()); + + map.put("profile_name", session.getName()); + map.put("user_type", session.getUserType().getName()); + map.put("user_properties", mapper.writeValueAsString(session.getUserProperties())); + + map.put("game_directory", instance.getContentDir().getAbsolutePath()); + map.put("game_assets", virtualAssetsDir.getAbsolutePath()); + map.put("assets_root", launcher.getAssets().getDir().getAbsolutePath()); + map.put("assets_index_name", versionManifest.getAssetsIndex()); + + return map; + } + + @Override + public double getProgress() { + return progress.getProgress(); + } + + @Override + public String getStatus() { + return progress.getStatus(); + } + +} diff --git a/src/main/java/com/skcraft/launcher/swing/InstanceTableModel.java b/src/main/java/com/skcraft/launcher/swing/InstanceTableModel.java index eb9bd41..03887bf 100644 --- a/src/main/java/com/skcraft/launcher/swing/InstanceTableModel.java +++ b/src/main/java/com/skcraft/launcher/swing/InstanceTableModel.java @@ -20,12 +20,15 @@ private final InstanceList instances; private final ImageIcon instanceIcon; + private final ImageIcon customInstanceIcon; private final ImageIcon downloadIcon; public InstanceTableModel(InstanceList instances) { this.instances = instances; instanceIcon = new ImageIcon(SwingHelper.readIconImage(Launcher.class, "instance_icon.png") .getScaledInstance(16, 16, Image.SCALE_SMOOTH)); + customInstanceIcon = new ImageIcon(SwingHelper.readIconImage(Launcher.class, "custom_instance_icon.png") + .getScaledInstance(16, 16, Image.SCALE_SMOOTH)); downloadIcon = new ImageIcon(SwingHelper.readIconImage(Launcher.class, "download_icon.png") .getScaledInstance(14, 14, Image.SCALE_SMOOTH)); } @@ -95,11 +98,19 @@ @Override public Object getValueAt(int rowIndex, int columnIndex) { + Instance instance; switch (columnIndex) { case 0: - return instances.get(rowIndex).isLocal() ? instanceIcon : downloadIcon; + instance = instances.get(rowIndex); + if (!instance.isLocal()) { + return downloadIcon; + } else if (instance.getManifestURL() != null) { + return instanceIcon; + } else { + return customInstanceIcon; + } case 1: - Instance instance = instances.get(rowIndex); + instance = instances.get(rowIndex); return "" + SwingHelper.htmlEscape(instance.getTitle()) + getAddendum(instance) + ""; default: return null; diff --git a/src/main/java/com/skcraft/launcher/update/Updater.java b/src/main/java/com/skcraft/launcher/update/Updater.java index 58165c3..deccb77 100644 --- a/src/main/java/com/skcraft/launcher/update/Updater.java +++ b/src/main/java/com/skcraft/launcher/update/Updater.java @@ -12,12 +12,15 @@ import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.Instance; import com.skcraft.launcher.Launcher; +import com.skcraft.launcher.LauncherException; import com.skcraft.launcher.install.Installer; import com.skcraft.launcher.model.minecraft.VersionManifest; import com.skcraft.launcher.model.modpack.Manifest; import com.skcraft.launcher.persistence.Persistence; import com.skcraft.launcher.util.HttpRequest; +import lombok.Getter; import lombok.NonNull; +import lombok.Setter; import lombok.extern.java.Log; import java.io.File; @@ -40,11 +43,13 @@ private final Launcher launcher; private final Instance instance; + @Getter @Setter + private boolean online; + private List librarySources = new ArrayList(); private List assetsSources = new ArrayList(); - private ProgressObservable progress = new DefaultProgress( - -1, _("instanceUpdater.preparingUpdate")); + private ProgressObservable progress = new DefaultProgress(-1, _("instanceUpdater.preparingUpdate")); public Updater(@NonNull Launcher launcher, @NonNull Instance instance) { super(launcher); @@ -59,16 +64,34 @@ @Override public Instance call() throws Exception { - Updater.log.info("Checking for an update for '" + instance.getName() + "'..."); - if (instance.getManifestURL() == null) { - Updater.log.log(Level.INFO, - "No URL set for {0}, so it can't be updated (the modpack may be removed from the server)", - new Object[] { instance }); - } else if (instance.isUpdatePending() || !instance.isInstalled()) { - Updater.log.log(Level.INFO, "Updating {0}...", new Object[]{instance}); + log.info("Checking for an update for '" + instance.getName() + "'..."); + + boolean updateRequired = !instance.isInstalled(); + boolean updateDesired = (instance.isUpdatePending() || updateRequired); + boolean updateCapable = (instance.getManifestURL() != null); + + if (!online && updateRequired) { + log.info("Can't update " + instance.getTitle() + " because offline"); + String message = _("updater.updateRequiredButOffline"); + throw new LauncherException("Update required but currently offline", message); + } + + if (updateDesired && !updateCapable) { + if (updateRequired) { + log.info("Update required for " + instance.getTitle() + " but there is no manifest"); + String message = _("updater.updateRequiredButNoManifest"); + throw new LauncherException("Update required but no manifest", message); + } else { + log.info("Can't update " + instance.getTitle() + ", but update is not required"); + return instance; // Can't update + } + } + + if (updateDesired) { + log.info("Updating " + instance.getTitle() + "..."); update(instance); } else { - Updater.log.log(Level.INFO, "No update found for {0}.", new Object[] { instance }); + log.info("No update found for " + instance.getTitle()); } return instance; @@ -146,7 +169,7 @@ instance.setLocal(true); Persistence.commitAndForget(instance); - Updater.log.log(Level.INFO, instance.getName() + + log.log(Level.INFO, instance.getName() + " has been updated to version " + manifest.getVersion() + "."); } diff --git a/src/main/resources/com/skcraft/launcher/custom_instance_icon.png b/src/main/resources/com/skcraft/launcher/custom_instance_icon.png new file mode 100644 index 0000000..867849c --- /dev/null +++ b/src/main/resources/com/skcraft/launcher/custom_instance_icon.png Binary files differ diff --git a/src/main/resources/com/skcraft/launcher/lang/Launcher.properties b/src/main/resources/com/skcraft/launcher/lang/Launcher.properties index 030a1f7..624ab64 100644 --- a/src/main/resources/com/skcraft/launcher/lang/Launcher.properties +++ b/src/main/resources/com/skcraft/launcher/lang/Launcher.properties @@ -142,6 +142,8 @@ installer.movingFile=Moving {0} to {1} updater.updating=Updating launcher... +updater.updateRequiredButOffline=An update is required but you need to be in online mode. +updater.updateRequiredButNoManifest=An update is required but update information for this instance is no longer available. instanceUpdater.preparingUpdate=Preparing to update... instanceUpdater.readingManifest=Reading package manifest... @@ -151,9 +153,11 @@ instanceResetter.resetting=Resetting {0}... instanceLoader.loadingLocal=Loading local instances from disk... instanceLoader.checkingRemote=Checking for new modpacks... -instanceLauncher.preparing=Preparing for launch... -instanceLauncher.collectingArgs=Collecting arguments... -instanceLauncher.startingJava=Starting java... + +runner.preparing=Preparing for launch... +runner.collectingArgs=Collecting arguments... +runner.startingJava=Starting java... +runner.updateRequired=This instance must be updated before it can be run. assets.expanding1=Expanding {0} asset... ({1} remaining) assets.expandingN=Expanding {0} assets... ({1} remaining)