diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java new file mode 100644 index 000000000..b2d241cb1 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackExportTask.java @@ -0,0 +1,98 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + + +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.util.Constants; +import org.jackhuang.hmcl.util.Logging; +import org.jackhuang.hmcl.util.ZipEngine; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Export the game to a mod pack file. + */ +public class HMCLModpackExportTask extends TaskResult { + private final DefaultGameRepository repository; + private final String version; + private final List whitelist; + private final Modpack modpack; + private final File output; + private final String id; + + public HMCLModpackExportTask(DefaultGameRepository repository, String version, List whitelist, Modpack modpack, File output) { + this(repository, version, whitelist, modpack, output, ID); + } + + /** + * @param output mod pack file. + * @param version to locate version.json + */ + public HMCLModpackExportTask(DefaultGameRepository repository, String version, List whitelist, Modpack modpack, File output, String id) { + this.repository = repository; + this.version = version; + this.whitelist = whitelist; + this.modpack = modpack; + this.output = output; + this.id = id; + + onDone().register(event -> { + if (event.isFailed()) output.delete(); + }); + } + + @Override + public String getId() { + return id; + } + + @Override + public void execute() throws Exception { + ArrayList blackList = new ArrayList<>(HMCLModpackManager.MODPACK_BLACK_LIST); + blackList.add(version + ".jar"); + blackList.add(version + ".json"); + Logging.LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker"); + try (ZipEngine zip = new ZipEngine(output)) { + zip.putDirectory(repository.getRunDirectory(version), (String pathName, Boolean isDirectory) -> { + for (String s : blackList) + if (isDirectory) { + if (pathName.startsWith(s + "/")) + return null; + } else if (pathName.equals(s)) + return null; + for (String s : whitelist) + if (pathName.equals(s + (isDirectory ? "/" : ""))) + return "minecraft/" + pathName; + return null; + }); + + Version mv = repository.getVersion(version).resolve(repository); + String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version)); + if (gameVersion == null) + throw new IllegalStateException("Cannot parse the version of " + version); + zip.putTextFile(Constants.GSON.toJson(mv.setJar(gameVersion)), "minecraft/pack.json"); // Making "jar" to gameVersion is to be compatible with old HMCL. + zip.putTextFile(Constants.GSON.toJson(modpack.setGameVersion(gameVersion)), "modpack.json"); // Newer HMCL only reads 'gameVersion' field. + } + } + + public static final String ID = "zip_engine"; +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java new file mode 100644 index 000000000..76c166b19 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java @@ -0,0 +1,76 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.game.VersionJsonSaveTask; +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.CompressingUtils; +import org.jackhuang.hmcl.util.Constants; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +public final class HMCLModpackInstallTask extends Task { + private final File zipFile; + private final String version; + private final HMCLGameRepository repository; + private final DefaultDependencyManager dependency; + private final List dependencies = new LinkedList<>(); + private final List dependents = new LinkedList<>(); + + public HMCLModpackInstallTask(Profile profile, File zipFile, Modpack modpack, String id) throws IOException { + dependency = profile.getDependency(); + repository = profile.getRepository(); + this.zipFile = zipFile; + this.version = id; + + if (repository.hasVersion(id)) + throw new IllegalArgumentException("Version " + id + " already exists"); + + String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json"); + Version version = Constants.GSON.fromJson(json, Version.class).setJar(null); + dependents.add(dependency.gameBuilder().name(id).gameVersion(modpack.getGameVersion()).buildAsync()); + dependencies.add(new VersionJsonSaveTask(repository, version)); + + onDone().register(event -> { + if (event.isFailed()) repository.removeVersionFromDisk(id); + }); + } + + @Override + public List getDependencies() { + return dependencies; + } + + @Override + public List getDependents() { + return dependents; + } + + @Override + public void execute() throws Exception { + CompressingUtils.unzip(zipFile, repository.getRunDirectory(version), + "minecraft/", it -> !Objects.equals(it, "minecraft/pack.json"), false); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManager.java new file mode 100644 index 000000000..7b6ab1eaa --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManager.java @@ -0,0 +1,85 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + +import com.google.gson.JsonParseException; +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.util.*; +import sun.rmi.runtime.Log; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @author huangyuhui + */ +public final class HMCLModpackManager { + + public static final List MODPACK_BLACK_LIST = Arrays.asList("usernamecache.json", "asm", "logs", "backups", "versions", "assets", "usercache.json", "libraries", "crash-reports", "launcher_profiles.json", "NVIDIA", "AMD", "TCNodeTracker", "screenshots", "natives", "native", "$native", "pack.json", "launcher.jar", "minetweaker.log", "launcher.pack.lzma", "hmclmc.log"); + public static final List MODPACK_SUGGESTED_BLACK_LIST = Arrays.asList("fonts", "saves", "servers.dat", "options.txt", "optionsof.txt", "journeymap", "optionsshaders.txt", "mods/VoxelMods"); + + public static ModAdviser MODPACK_PREDICATE = (String fileName, boolean isDirectory) -> { + if (match(MODPACK_BLACK_LIST, fileName, isDirectory)) + return ModAdviser.ModSuggestion.HIDDEN; + if (match(MODPACK_SUGGESTED_BLACK_LIST, fileName, isDirectory)) + return ModAdviser.ModSuggestion.NORMAL; + else + return ModAdviser.ModSuggestion.SUGGESTED; + }; + + private static boolean match(List l, String fileName, boolean isDirectory) { + for (String s : l) + if (isDirectory) { + if (fileName.startsWith(s + "/")) + return true; + } else if (fileName.equals(s)) + return true; + return false; + } + + /** + * Read the manifest in a HMCL modpack. + * + * @param file a HMCL modpack file. + * @throws IOException if the file is not a valid zip file. + * @throws JsonParseException if the manifest.json is missing or malformed. + * @return the manifest of HMCL modpack. + */ + public static Modpack readHMCLModpackManifest(File file) throws IOException, JsonParseException { + String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json"); + Modpack manifest = Constants.GSON.fromJson(manifestJson, Modpack.class); + if (manifest == null) + throw new JsonParseException("`modpack.json` not found. " + file + " is not a valid HMCL modpack."); + String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json"); + Version game = Constants.GSON.fromJson(gameJson, Version.class); + if (game == null) + throw new JsonParseException("`minecraft/pack.json` not found. " + file + " iot a valid HMCL modpack."); + if (game.getJar() == null) + if (StringUtils.isBlank(manifest.getVersion())) + throw new JsonParseException("Cannot recognize the game version of modpack " + file + "."); + else + return manifest.setManifest(HMCLModpackManifest.INSTANCE); + else + return manifest.setManifest(HMCLModpackManifest.INSTANCE).setGameVersion(game.getJar()); + } +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Wizard.kt b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManifest.java similarity index 78% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Wizard.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManifest.java index f0f4ef09b..f8823b312 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Wizard.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManifest.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.wizard +package org.jackhuang.hmcl.game; -import javafx.scene.Node +public final class HMCLModpackManifest { + public static final HMCLModpackManifest INSTANCE = new HMCLModpackManifest(); -object Wizard { - fun createWizard(namespace: String = "", provider: WizardProvider): Node = DefaultWizardDisplayer(namespace, provider) -} \ No newline at end of file + private HMCLModpackManifest() {} +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java index cbe667531..cf58e929c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java @@ -28,6 +28,10 @@ import java.util.List; * @author huangyuhui */ public final class HMCLMultiCharacterSelector implements MultiCharacterSelector { + public static final HMCLMultiCharacterSelector INSTANCE = new HMCLMultiCharacterSelector(); + + private HMCLMultiCharacterSelector() {} + @Override public GameProfile select(Account account, List names) throws NoSelectedCharacterException { return names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModAdviser.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModAdviser.java new file mode 100644 index 000000000..ca9d8a70b --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModAdviser.java @@ -0,0 +1,31 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + +/** + * @author huangyuhui + */ +public interface ModAdviser { + ModSuggestion advise(String fileName, boolean isDirectory); + + enum ModSuggestion { + SUGGESTED, + NORMAL, + HIDDEN + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java new file mode 100644 index 000000000..df91ed950 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java @@ -0,0 +1,91 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + +import org.jackhuang.hmcl.mod.CurseManifest; +import org.jackhuang.hmcl.mod.Modpack; +import org.jackhuang.hmcl.mod.MultiMCInstanceConfiguration; +import org.jackhuang.hmcl.setting.EnumGameDirectory; +import org.jackhuang.hmcl.setting.VersionSetting; +import org.jackhuang.hmcl.util.Lang; + +import java.io.File; +import java.util.Optional; + +public final class ModpackHelper { + private ModpackHelper() {} + + public static Modpack readModpackManifest(File file) { + try { + return CurseManifest.readCurseForgeModpackManifest(file); + } catch (Exception e) { + // ignore it, not a valid CurseForge modpack. + } + + try { + return HMCLModpackManager.readHMCLModpackManifest(file); + } catch (Exception e) { + // ignore it, not a valid HMCL modpack. + } + + try { + return MultiMCInstanceConfiguration.readMultiMCModpackManifest(file); + } catch (Exception e) { + // ignore it, not a valid MultiMC modpack. + } + + throw new IllegalArgumentException("Modpack file " + file + " is not supported."); + } + + public static void toVersionSetting(MultiMCInstanceConfiguration c, VersionSetting vs) { + vs.setUsesGlobal(false); + vs.setGameDirType(EnumGameDirectory.VERSION_FOLDER); + + if (c.isOverrideJavaLocation()) { + vs.setJavaDir(Lang.nonNull(c.getJavaPath(), "")); + } + + if (c.isOverrideMemory()) { + vs.setPermSize(Optional.ofNullable(c.getPermGen()).map(i -> i.toString()).orElse("")); + if (c.getMaxMemory() != null) + vs.setMaxMemory(c.getMaxMemory()); + vs.setMinMemory(c.getMinMemory()); + } + + if (c.isOverrideCommands()) { + vs.setWrapper(Lang.nonNull(c.getWrapperCommand(), "")); + vs.setPreLaunchCommand(Lang.nonNull(c.getPreLaunchCommand(), "")); + } + + if (c.isOverrideJavaArgs()) { + vs.setJavaArgs(Lang.nonNull(c.getJvmArgs(), "")); + } + + if (c.isOverrideConsole()) { + vs.setShowLogs(c.isShowConsole()); + } + + if (c.isOverrideWindow()) { + vs.setFullscreen(c.isFullscreen()); + if (c.getWidth() != null) + vs.setWidth(c.getWidth()); + if (c.getHeight() != null) + vs.setHeight(c.getHeight()); + } + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java new file mode 100644 index 000000000..d4edf3306 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/MultiMCInstallVersionSettingTask.java @@ -0,0 +1,48 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.game; + +import org.jackhuang.hmcl.mod.MultiMCInstanceConfiguration; +import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.setting.VersionSetting; +import org.jackhuang.hmcl.task.Scheduler; +import org.jackhuang.hmcl.task.Schedulers; +import org.jackhuang.hmcl.task.Task; + +public final class MultiMCInstallVersionSettingTask extends Task { + private final Profile profile; + private final MultiMCInstanceConfiguration manifest; + private final String version; + + public MultiMCInstallVersionSettingTask(Profile profile, MultiMCInstanceConfiguration manifest, String version) { + this.profile = profile; + this.manifest = manifest; + this.version = version; + } + + @Override + public Scheduler getScheduler() { + return Schedulers.javafx(); + } + + @Override + public void execute() throws Exception { + VersionSetting vs = profile.specializeVersionSetting(version); + ModpackHelper.toVersionSetting(manifest, vs); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java new file mode 100644 index 000000000..1b68820bc --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java @@ -0,0 +1,51 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +import org.jackhuang.hmcl.auth.Account; +import org.jackhuang.hmcl.auth.AccountFactory; +import org.jackhuang.hmcl.auth.OfflineAccount; +import org.jackhuang.hmcl.auth.OfflineAccountFactory; +import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount; +import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory; +import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.Pair; + +import java.util.Map; + +/** + * @author huangyuhui + */ +public final class Accounts { + private Accounts() {} + + public static final String OFFLINE_ACCOUNT_KEY = "offline"; + public static final String YGGDRASIL_ACCOUNT_KEY = "yggdrasil"; + + public static final Map> ACCOUNT_FACTORY = Lang.mapOf( + new Pair<>(OFFLINE_ACCOUNT_KEY, OfflineAccountFactory.INSTANCE), + new Pair<>(YGGDRASIL_ACCOUNT_KEY, YggdrasilAccountFactory.INSTANCE) + ); + + public static String getAccountType(Account account) { + if (account instanceof OfflineAccount) return OFFLINE_ACCOUNT_KEY; + else if (account instanceof YggdrasilAccount) return YGGDRASIL_ACCOUNT_KEY; + else return YGGDRASIL_ACCOUNT_KEY; + } + +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java new file mode 100644 index 000000000..ae5fcf6a8 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java @@ -0,0 +1,36 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider; +import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.MojangDownloadProvider; +import org.jackhuang.hmcl.util.Lang; + +import java.util.Arrays; +import java.util.List; + +public final class DownloadProviders { + private DownloadProviders() {} + + public static List DOWNLOAD_PROVIDERS = Arrays.asList(MojangDownloadProvider.INSTANCE, BMCLAPIDownloadProvider.INSTANCE); + + public static DownloadProvider getDownloadProvider(int index) { + return Lang.get(DOWNLOAD_PROVIDERS, index).orElse(MojangDownloadProvider.INSTANCE); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Fonts.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Fonts.java new file mode 100644 index 000000000..e42e5e6d8 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Fonts.java @@ -0,0 +1,28 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +import javafx.scene.text.Font; + +import java.util.List; + +public final class Fonts { + private Fonts() {} + + public static final List FONTS = Font.getFamilies(); +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Locales.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Locales.java new file mode 100644 index 000000000..275bb2e9d --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Locales.java @@ -0,0 +1,112 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +import org.jackhuang.hmcl.ui.construct.UTF8Control; +import org.jackhuang.hmcl.util.Lang; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +public final class Locales { + + public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault(), "lang.default"); + + /** + * English + */ + public static final SupportedLocale EN = new SupportedLocale(Locale.ENGLISH); + + /** + * Traditional Chinese + */ + public static final SupportedLocale ZH = new SupportedLocale(Locale.TRADITIONAL_CHINESE); + + /** + * Simplified Chinese + */ + public static final SupportedLocale ZH_CN = new SupportedLocale(Locale.SIMPLIFIED_CHINESE); + + /** + * Vietnamese + */ + public static final SupportedLocale VI = new SupportedLocale(new Locale("vi")); + + /** + * Russian + */ + public static final SupportedLocale RU = new SupportedLocale(new Locale("ru")); + + public static final List LOCALES = Arrays.asList(DEFAULT, EN, ZH, ZH_CN, VI, RU); + + public static SupportedLocale getLocale(int index) { + return Lang.get(LOCALES, index).orElse(DEFAULT); + } + + public static SupportedLocale getLocaleByName(String name) { + switch (name.toLowerCase()) { + case "en": return EN; + case "zh": return ZH; + case "zh_cn": return ZH_CN; + case "vi": return VI; + case "ru": return RU; + default: return DEFAULT; + } + } + + public static String getNameByLocale(SupportedLocale locale) { + if (locale == EN) return "en"; + else if (locale == ZH) return "zh"; + else if (locale == ZH_CN) return "zh_CN"; + else if (locale == VI) return "vi"; + else if (locale == RU) return "ru"; + else if (locale == DEFAULT) return "def"; + else throw new IllegalArgumentException("Unknown locale: " + locale); + } + + public static class SupportedLocale { + private final Locale locale; + private final String name; + private final ResourceBundle resourceBundle; + + SupportedLocale(Locale locale) { + this(locale, null); + } + + SupportedLocale(Locale locale, String name) { + this.locale = locale; + this.name = name; + resourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE); + } + + public Locale getLocale() { + return locale; + } + + public ResourceBundle getResourceBundle() { + return resourceBundle; + } + + public String getName(ResourceBundle newResourceBundle) { + if (name == null) return resourceBundle.getString("lang"); + else return newResourceBundle.getString(name); + } + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Proxies.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Proxies.java new file mode 100644 index 000000000..bfce5107b --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Proxies.java @@ -0,0 +1,37 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +import org.jackhuang.hmcl.util.Lang; + +import java.net.Proxy; +import java.util.Arrays; +import java.util.List; + +/** + * @author huangyuhui + */ +public final class Proxies { + private Proxies() {} + + public static final List PROXIES = Arrays.asList(Proxy.Type.DIRECT, Proxy.Type.HTTP, Proxy.Type.SOCKS); + + public static Proxy.Type getProxyType(int index) { + return Lang.get(PROXIES, index).orElse(null); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java index 682350e3c..34af3f5e4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java @@ -28,7 +28,11 @@ import java.util.Locale; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; -public class UTF8Control extends ResourceBundle.Control { +public final class UTF8Control extends ResourceBundle.Control { + public static final UTF8Control INSTANCE = new UTF8Control(); + + private UTF8Control() {} + @Override public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Summary.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Summary.java new file mode 100644 index 000000000..df8c39000 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Summary.java @@ -0,0 +1,61 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program 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. + * + * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.wizard; + +import com.jfoenix.controls.JFXListView; +import com.jfoenix.controls.JFXTextArea; +import javafx.scene.Node; + +/** + * @author huangyuhui + */ +public final class Summary { + private final Node component; + private final Object result; + + public Summary(String[] items, Object result) { + JFXListView view = new JFXListView(); + view.getItems().addAll(items); + + this.component = view; + this.result = result; + } + + public Summary(String text, Object result) { + JFXTextArea area = new JFXTextArea(text); + area.setEditable(false); + + this.component = area; + this.result = result; + } + + /** + * The component that will display the summary information + */ + public Node getComponent() { + return component; + } + + /** + * The object that represents the actual result of whatever that Wizard + * that created this Summary object computes, or null. + */ + public Object getResult() { + return result; + } +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Summary.kt b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Wizard.java similarity index 50% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Summary.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Wizard.java index d54a624eb..5d3f9bdba 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Summary.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Wizard.java @@ -15,27 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.wizard +package org.jackhuang.hmcl.ui.wizard; -import com.jfoenix.controls.JFXListView -import com.jfoenix.controls.JFXTextArea -import javafx.scene.Node +import javafx.scene.Node; -class Summary( - /** - * The component that will display the summary information - */ - val component: Node, - /** - * The object that represents the actual result of whatever that Wizard - * that created this Summary object computes, or null. - */ - val result: Any?) { - constructor(items: Array, result: Any?) - : this(JFXListView().apply { this.items.addAll(*items) }, result) { +public final class Wizard { + + public static Node createWizard(WizardProvider provider) { + return createWizard("", provider); } - constructor(text: String, result: Any?) - : this(JFXTextArea(text).apply { isEditable = false }, result) { + public static Node createWizard(String namespace, WizardProvider provider) { + return new DefaultWizardDisplayer(namespace, provider); } -} \ No newline at end of file +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java index 66d6248dc..ea0b90b84 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java @@ -42,6 +42,7 @@ import org.jackhuang.hmcl.Main; import org.jackhuang.hmcl.MainKt; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.util.*; @@ -110,11 +111,13 @@ public class AppDataUpgrader extends IUpgrader { String hash = null; if (map.containsKey("jarsha1")) hash = map.get("jarsha1"); - if (TaskWindow.factory().append(new AppDataUpgraderJarTask(NetworkUtils.toURL(map.get("jar")), version.toString(), hash)).execute()) { + Controllers.INSTANCE.dialog(MainKt.i18n("ui.message.downloading")); + if (new AppDataUpgraderJarTask(NetworkUtils.toURL(map.get("jar")), version.toString(), hash).test()) { new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderJarTask.getSelf(version.toString()).getAbsolutePath()) .directory(new File("").getAbsoluteFile()).start(); System.exit(0); } + Controllers.INSTANCE.closeDialog(); } catch (IOException ex) { Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); } @@ -123,11 +126,13 @@ public class AppDataUpgrader extends IUpgrader { String hash = null; if (map.containsKey("packsha1")) hash = map.get("packsha1"); - if (TaskWindow.factory().append(new AppDataUpgraderPackGzTask(NetworkUtils.toURL(map.get("pack")), version.toString(), hash)).execute()) { + Controllers.INSTANCE.dialog(MainKt.i18n("ui.message.downloading")); + if (new AppDataUpgraderPackGzTask(NetworkUtils.toURL(map.get("pack")), version.toString(), hash).test()) { new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderPackGzTask.getSelf(version.toString()).getAbsolutePath()) .directory(new File("").getAbsoluteFile()).start(); System.exit(0); } + Controllers.INSTANCE.closeDialog(); } catch (IOException ex) { Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java index 88afe69be..a4b07d9e6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java @@ -17,7 +17,9 @@ */ package org.jackhuang.hmcl.upgrade; +import org.jackhuang.hmcl.MainKt; import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.util.Charsets; import org.jackhuang.hmcl.util.FileUtils; import org.jackhuang.hmcl.util.Logging; @@ -51,7 +53,8 @@ public class NewFileUpgrader extends IUpgrader { URL url = requestDownloadLink(); if (url == null) return; File newf = new File(url.getFile()); - if (TaskWindow.factory().append(new FileDownloadTask(url, newf)).execute()) { + Controllers.INSTANCE.dialog(MainKt.i18n("ui.message.downloading")); + if (new FileDownloadTask(url, newf).test()) { try { new ProcessBuilder(newf.getCanonicalPath(), "--removeOldLauncher", getRealPath()) .directory(new File("").getAbsoluteFile()) @@ -61,6 +64,7 @@ public class NewFileUpgrader extends IUpgrader { } System.exit(0); } + Controllers.INSTANCE.closeDialog(); } private static String getRealPath() { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLModpack.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLModpack.kt deleted file mode 100644 index fbdb3f97a..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLModpack.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * This program 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. - * - * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.game - -import com.google.gson.JsonParseException -import org.jackhuang.hmcl.download.game.VersionJsonSaveTask -import org.jackhuang.hmcl.game.GameVersion.minecraftVersion -import org.jackhuang.hmcl.mod.Modpack -import org.jackhuang.hmcl.setting.Profile -import org.jackhuang.hmcl.task.Task -import java.io.File -import java.io.IOException -import org.jackhuang.hmcl.task.TaskResult -import org.jackhuang.hmcl.util.* -import org.jackhuang.hmcl.util.Constants.GSON -import org.jackhuang.hmcl.util.Logging.LOG -import java.util.ArrayList - -/** - * Read the manifest in a HMCL modpack. - * - * @param f a HMCL modpack file. - * @throws IOException if the file is not a valid zip file. - * @throws JsonParseException if the manifest.json is missing or malformed. - * @return the manifest of HMCL modpack. - */ -@Throws(IOException::class, JsonParseException::class) -fun readHMCLModpackManifest(f: File): Modpack { - val manifestJson = CompressingUtils.readTextZipEntry(f, "modpack.json") - val manifest = GSON.fromJson(manifestJson) ?: throw JsonParseException("`modpack.json` not found. $f is not a valid HMCL modpack.") - val gameJson = CompressingUtils.readTextZipEntry(f, "minecraft/pack.json") - val game = GSON.fromJson(gameJson) ?: throw JsonParseException("`minecraft/pack.json` not found. $f iot a valid HMCL modpack.") - return if (game.jar == null) - if (manifest.gameVersion.isNullOrBlank()) throw JsonParseException("Cannot recognize the game version of modpack $f.") - else manifest.setManifest(HMCLModpackManifest) - else manifest.setManifest(HMCLModpackManifest).setGameVersion(game.jar) -} - -object HMCLModpackManifest - -class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, modpack: Modpack, private val version: String): Task() { - private val dependency = profile.dependency - private val repository = profile.repository - private val dependencies = mutableListOf() - private val dependents = mutableListOf() - - override fun getDependencies() = dependencies - override fun getDependents() = dependents - - init { - check(!repository.hasVersion(version), { "Version $version already exists." }) - val json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json") - var version = GSON.fromJson(json)!! - version = version.setJar(null) - dependents += dependency.gameBuilder().name(this.version).gameVersion(modpack.gameVersion!!).buildAsync() - dependencies += VersionJsonSaveTask(repository, version) // override the json created by buildAsync() - - onDone() += { event -> if (event.isFailed) repository.removeVersionFromDisk(this.version) } - } - - private val run = repository.getRunDirectory(version) - - override fun execute() { - CompressingUtils.unzip(zipFile, run, "minecraft/", { it != "minecraft/pack.json" }, false) - } -} - -val MODPACK_BLACK_LIST = listOf("usernamecache.json", "asm", "logs", "backups", "versions", "assets", "usercache.json", "libraries", "crash-reports", "launcher_profiles.json", "NVIDIA", "AMD", "TCNodeTracker", "screenshots", "natives", "native", "\$native", "pack.json", "launcher.jar", "minetweaker.log", "launcher.pack.lzma", "hmclmc.log") -val MODPACK_NORMAL_LIST = listOf("fonts", "saves", "servers.dat", "options.txt", "optionsof.txt", "journeymap", "optionsshaders.txt", "mods/VoxelMods") - -/** - * - * @author huang - */ -interface ModAdviser { - - fun advise(fileName: String, isDirectory: Boolean): ModSuggestion - - enum class ModSuggestion { - SUGGESTED, - NORMAL, - HIDDEN - } - -} - -private fun match(l: List, fileName: String, isDirectory: Boolean): Boolean { - for (s in l) - if (isDirectory) { - if (fileName.startsWith(s + "/")) - return true - } else if (fileName == s) - return true - return false -} - -var MODPACK_PREDICATE = object : ModAdviser { - override fun advise(fileName: String, isDirectory: Boolean): ModAdviser.ModSuggestion { - return if (match(MODPACK_BLACK_LIST, fileName, isDirectory)) - ModAdviser.ModSuggestion.HIDDEN - else if (match(MODPACK_NORMAL_LIST, fileName, isDirectory)) - ModAdviser.ModSuggestion.NORMAL - else - ModAdviser.ModSuggestion.SUGGESTED - } -} - -class HMCLModpackExportTask @JvmOverloads constructor( - private val repository: DefaultGameRepository, - private val version: String, - private val whitelist: List, - private val modpack: Modpack, - private val output: File, - private val id: String = ID): TaskResult() { - - override fun getId() = id - - init { - onDone() += { event -> if (event.isFailed) output.delete() } - } - - override fun execute() { - val blackList = ArrayList(MODPACK_BLACK_LIST) - blackList.add(version + ".jar") - blackList.add(version + ".json") - LOG.info("Compressing game files without some files in blacklist, including files or directories: usernamecache.json, asm, logs, backups, versions, assets, usercache.json, libraries, crash-reports, launcher_profiles.json, NVIDIA, TCNodeTracker") - ZipEngine(output).use { zip -> - zip.putDirectory(repository.getRunDirectory(version)) a@ { pathName: String, isDirectory: Boolean -> - for (s in blackList) { - if (isDirectory) { - if (pathName.startsWith(s + "/")) - return@a null - } else if (pathName == s) - return@a null - } - for (s in whitelist) - if (s + (if (isDirectory) "/" else "") == pathName) - return@a "minecraft/" + pathName - null - } - - val mv = repository.getVersion(version).resolve(repository) - val gameVersion = minecraftVersion(repository.getVersionJar(version)) ?: throw IllegalStateException("Cannot parse the version of $version") - zip.putTextFile(GSON.toJson(mv.setJar(gameVersion)), "minecraft/pack.json") // Making "jar" to gameVersion is to be compatible with old HMCL. - zip.putTextFile(GSON.toJson(modpack.setGameVersion(gameVersion)), "modpack.json") // Newer HMCL only reads 'gameVersion' field. - } - } - - companion object { - val ID = "zip_engine" - } -} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/ModpackHelper.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/ModpackHelper.kt deleted file mode 100644 index e6f2b5dcb..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/ModpackHelper.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * This program 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. - * - * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.game - -import org.jackhuang.hmcl.mod.* -import org.jackhuang.hmcl.setting.EnumGameDirectory -import org.jackhuang.hmcl.setting.Profile -import org.jackhuang.hmcl.setting.VersionSetting -import org.jackhuang.hmcl.task.Schedulers -import org.jackhuang.hmcl.task.Task -import org.jackhuang.hmcl.util.toStringOrEmpty -import java.io.File - -fun readModpackManifest(f: File): Modpack { - try { - return CurseManifest.readCurseForgeModpackManifest(f); - } catch (e: Exception) { - // ignore it, not a valid CurseForge modpack. - } - - try { - val manifest = readHMCLModpackManifest(f) - return manifest - } catch (e: Exception) { - // ignore it, not a valid HMCL modpack. - } - - try { - val manifest = MultiMCInstanceConfiguration.readMultiMCModpackManifest(f) - return manifest - } catch (e: Exception) { - // ignore it, not a valid MMC modpack. - } - - throw IllegalArgumentException("Modpack file $f is not supported.") -} - -fun MultiMCInstanceConfiguration.toVersionSetting(vs: VersionSetting) { - vs.isUsesGlobal = false - vs.gameDirType = EnumGameDirectory.VERSION_FOLDER - - if (isOverrideJavaLocation) { - vs.javaDir = javaPath.toStringOrEmpty() - } - - if (isOverrideMemory) { - vs.permSize = permGen.toStringOrEmpty() - if (maxMemory != null) - vs.maxMemory = maxMemory!! - vs.minMemory = minMemory - } - - if (isOverrideCommands) { - vs.wrapper = wrapperCommand.orEmpty() - vs.preLaunchCommand = preLaunchCommand.orEmpty() - } - - if (isOverrideJavaArgs) { - vs.javaArgs = jvmArgs.orEmpty() - } - - if (isOverrideConsole) { - vs.isShowLogs = isShowConsole - } - - if (isOverrideWindow) { - vs.isFullscreen = isFullscreen - if (width != null) - vs.width = width!! - if (height != null) - vs.height = height!! - } -} - -class MMCInstallVersionSettingTask(private val profile: Profile, val manifest: MultiMCInstanceConfiguration, private val version: String): Task() { - override fun getScheduler() = Schedulers.javafx() - override fun execute() { - val vs = profile.specializeVersionSetting(version)!! - manifest.toVersionSetting(vs) - } -} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt index ebd2c73ca..1e8933690 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/Settings.kt @@ -149,7 +149,7 @@ object Settings { var locale: Locales.SupportedLocale = Locales.getLocaleByName(SETTINGS.localization) set(value) { field = value - SETTINGS.localization = Locales.getNameByLocal(value) + SETTINGS.localization = Locales.getNameByLocale(value) } var proxy: Proxy = Proxy.NO_PROXY diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/SettingsConstants.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/SettingsConstants.kt deleted file mode 100644 index c92c4e3b4..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/SettingsConstants.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * This program 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. - * - * This program 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 this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.setting - -import javafx.scene.text.Font -import org.jackhuang.hmcl.auth.Account -import org.jackhuang.hmcl.auth.AccountFactory -import org.jackhuang.hmcl.auth.OfflineAccount -import org.jackhuang.hmcl.auth.OfflineAccountFactory -import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount -import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory -import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider -import org.jackhuang.hmcl.download.MojangDownloadProvider -import org.jackhuang.hmcl.ui.construct.UTF8Control -import java.net.Proxy -import java.util.* - -object Proxies { - val PROXIES = listOf(Proxy.Type.DIRECT, Proxy.Type.HTTP, Proxy.Type.SOCKS) - - fun getProxyType(index: Int): Proxy.Type? = PROXIES.getOrNull(index) -} - -object DownloadProviders { - val DOWNLOAD_PROVIDERS = listOf(MojangDownloadProvider.INSTANCE, BMCLAPIDownloadProvider.INSTANCE) - - fun getDownloadProvider(index: Int) = DOWNLOAD_PROVIDERS.getOrElse(index, { MojangDownloadProvider.INSTANCE }) -} - -object Accounts { - val OFFLINE_ACCOUNT_KEY = "offline" - val YGGDRASIL_ACCOUNT_KEY = "yggdrasil" - - val ACCOUNT_FACTORY = mapOf>( - OFFLINE_ACCOUNT_KEY to OfflineAccountFactory.INSTANCE, - YGGDRASIL_ACCOUNT_KEY to YggdrasilAccountFactory.INSTANCE - ) - - fun getAccountType(account: Account): String { - return when (account) { - is OfflineAccount -> OFFLINE_ACCOUNT_KEY - is YggdrasilAccount -> YGGDRASIL_ACCOUNT_KEY - else -> YGGDRASIL_ACCOUNT_KEY - } - } -} - -object Locales { - class SupportedLocale internal constructor( - val locale: Locale, - private val nameImpl: String? = null - ) { - val resourceBundle: ResourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control) - - fun getName(nowResourceBundle: ResourceBundle): String { - if (nameImpl == null) - return resourceBundle.getString("lang") - else - return nowResourceBundle.getString(nameImpl) - } - } - - val DEFAULT = SupportedLocale(Locale.getDefault(), "lang.default") - val EN = SupportedLocale(Locale.ENGLISH) - val ZH = SupportedLocale(Locale.TRADITIONAL_CHINESE) - val ZH_CN = SupportedLocale(Locale.SIMPLIFIED_CHINESE) - val VI = SupportedLocale(Locale("vi")) - val RU = SupportedLocale(Locale("ru")) - - val LOCALES = listOf(DEFAULT, EN, ZH, ZH_CN, VI, RU) - - fun getLocale(index: Int) = LOCALES.getOrElse(index, { DEFAULT }) - fun getLocaleByName(name: String?) = when(name) { - "en" -> EN - "zh" -> ZH - "zh_CN" -> ZH_CN - "vi" -> VI - "ru" -> RU - else -> DEFAULT - } - - fun getNameByLocal(supportedLocale: SupportedLocale) = when(supportedLocale) { - EN -> "en" - ZH -> "zh" - ZH_CN -> "zh_CN" - VI -> "vi" - RU -> "ru" - DEFAULT -> "def" - else -> throw IllegalArgumentException("Unknown argument: " + supportedLocale) - } -} - -object Fonts { - val FONTS = Font.getFamilies() -} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt index d62d91c50..24a308bb0 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/AccountsPage.kt @@ -135,7 +135,7 @@ class AccountsPage() : StackPane(), DecoratorPage { else -> throw UnsupportedOperationException() } - account.logIn(HMCLMultiCharacterSelector, Settings.proxy) + account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.proxy) account } catch (e: Exception) { e diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/YggdrasilAccountLoginPane.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/YggdrasilAccountLoginPane.kt index e5a9e18a0..5c7d5f799 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/YggdrasilAccountLoginPane.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/YggdrasilAccountLoginPane.kt @@ -57,7 +57,7 @@ class YggdrasilAccountLoginPane(private val oldAccount: YggdrasilAccount, privat taskResult("login") { try { val account = YggdrasilAccountFactory.INSTANCE.fromUsername(username, password) - account.logIn(HMCLMultiCharacterSelector, Settings.proxy) + account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.proxy) } catch (e: Exception) { e } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt index 4abdac73a..c17ca6db2 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/TransitionHandler.kt @@ -25,6 +25,7 @@ import javafx.scene.Parent import javafx.scene.SnapshotParameters import javafx.scene.image.ImageView import javafx.scene.image.WritableImage +import javafx.scene.layout.Pane import javafx.scene.layout.StackPane import javafx.util.Duration import org.jackhuang.hmcl.ui.takeSnapshot @@ -32,16 +33,17 @@ import org.jackhuang.hmcl.ui.takeSnapshot /** * @param view A stack pane that contains another control that is [Parent] */ -class TransitionHandler(override val view: StackPane): AnimationHandler { +class TransitionHandler(private val view: StackPane): AnimationHandler { private var animation: Timeline? = null - override val snapshot = ImageView().apply { + override fun getSnapshot() = ImageView().apply { isPreserveRatio = true isSmooth = true } - override lateinit var duration: Duration - private set + override fun getView() = view + private lateinit var duration: Duration + override fun getDuration() = duration fun setContent(newView: Node, transition: AnimationProducer, duration: Duration = Duration.millis(320.0)) { this.duration = duration diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/DownloadWizardProvider.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/DownloadWizardProvider.kt index eca1c04ca..ea3100c9a 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/DownloadWizardProvider.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/DownloadWizardProvider.kt @@ -20,7 +20,7 @@ package org.jackhuang.hmcl.ui.download import javafx.scene.Node import org.jackhuang.hmcl.game.HMCLModpackInstallTask import org.jackhuang.hmcl.game.HMCLModpackManifest -import org.jackhuang.hmcl.game.MMCInstallVersionSettingTask +import org.jackhuang.hmcl.game.MultiMCInstallVersionSettingTask import org.jackhuang.hmcl.mod.* import org.jackhuang.hmcl.setting.EnumGameDirectory import org.jackhuang.hmcl.setting.Profile @@ -80,7 +80,7 @@ class DownloadWizardProvider(): WizardProvider() { return when (modpack.manifest) { is CurseManifest -> CurseInstallTask(profile.dependency, selectedFile, modpack.manifest as CurseManifest, name) is HMCLModpackManifest -> HMCLModpackInstallTask(profile, selectedFile, modpack, name) - is MultiMCInstanceConfiguration -> MultiMCModpackInstallTask(profile.dependency, selectedFile, modpack.manifest as MultiMCInstanceConfiguration, name).with(MMCInstallVersionSettingTask(profile, modpack.manifest as MultiMCInstanceConfiguration, name)) + is MultiMCInstanceConfiguration -> MultiMCModpackInstallTask(profile.dependency, selectedFile, modpack.manifest as MultiMCInstanceConfiguration, name).with(MultiMCInstallVersionSettingTask(profile, modpack.manifest as MultiMCInstanceConfiguration, name)) else -> throw Error() }.with(finalizeTask) } diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt index f34eee7a0..af9ae9c06 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/download/ModpackPage.kt @@ -22,11 +22,10 @@ import com.jfoenix.controls.JFXTextField import javafx.application.Platform import javafx.fxml.FXML import javafx.scene.control.Label -import javafx.scene.layout.BorderPane import javafx.scene.layout.Region import javafx.scene.layout.StackPane import javafx.stage.FileChooser -import org.jackhuang.hmcl.game.readModpackManifest +import org.jackhuang.hmcl.game.ModpackHelper import org.jackhuang.hmcl.i18n import org.jackhuang.hmcl.mod.Modpack import org.jackhuang.hmcl.setting.Profile @@ -66,7 +65,7 @@ class ModpackPage(private val controller: WizardController): StackPane(), Wizard txtModpackName.textProperty().onInvalidated { btnInstall.isDisable = !txtModpackName.validate() } try { - manifest = readModpackManifest(selectedFile) + manifest = ModpackHelper.readModpackManifest(selectedFile) controller.settings[MODPACK_CURSEFORGE_MANIFEST] = manifest!! lblName.text = manifest!!.name lblVersion.text = manifest!!.version diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/export/ExportWizardProvider.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/export/ExportWizardProvider.kt index ded404b36..a48815cf1 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/export/ExportWizardProvider.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/export/ExportWizardProvider.kt @@ -19,7 +19,7 @@ package org.jackhuang.hmcl.ui.export import javafx.scene.Node import org.jackhuang.hmcl.game.HMCLModpackExportTask -import org.jackhuang.hmcl.game.MODPACK_PREDICATE +import org.jackhuang.hmcl.game.HMCLModpackManager.MODPACK_PREDICATE import org.jackhuang.hmcl.mod.Modpack import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.ui.wizard.WizardController diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 0e94890dc..de26b8901 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -171,6 +171,7 @@ ui.message.first_load=Please enter your name. ui.message.enter_password=Please enter your password. ui.message.launching=Launching... ui.message.making=Generating... +ui.message.downloading=Downloading... ui.message.sure_remove=Sure to remove profile %s? ui.message.update_java=Please upgrade your Java. ui.message.open_jdk=We have found that you started this application using OpenJDK, which will cause so many troubles drawing the UI. We suggest you using Oracle JDK instead. diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index 1b875c661..26be68a1e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -194,7 +194,7 @@ public abstract class Task { executor().start(); } - public final boolean test() throws Exception { + public final boolean test() { return executor().test(); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index 917ff6ca5..e5e40d930 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -182,6 +182,13 @@ public final class Lang { return (V) o; } + public static Optional get(List list, int index) { + if (index < 0 || index >= list.size()) + return Optional.empty(); + else + return Optional.ofNullable(list.get(index)); + } + public static Optional get(Map map, Object key, Class clazz) { return convert(map.get(key), clazz); } @@ -248,4 +255,9 @@ public final class Lang { return defaultValue; } } + + public static T nonNull(T... t) { + for (T a : t) if (a != null) return a; + return null; + } }