MessageBox

This commit is contained in:
huangyuhui 2018-01-09 21:37:04 +08:00
parent 9e21e02791
commit 8edfe7bc9c
31 changed files with 817 additions and 415 deletions

View File

@ -0,0 +1,98 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<ZipEngine> {
private final DefaultGameRepository repository;
private final String version;
private final List<String> whitelist;
private final Modpack modpack;
private final File output;
private final String id;
public HMCLModpackExportTask(DefaultGameRepository repository, String version, List<String> 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<String> 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<String> 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";
}

View File

@ -0,0 +1,76 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<Task> dependencies = new LinkedList<>();
private final List<Task> 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<Task> getDependencies() {
return dependencies;
}
@Override
public List<Task> getDependents() {
return dependents;
}
@Override
public void execute() throws Exception {
CompressingUtils.unzip(zipFile, repository.getRunDirectory(version),
"minecraft/", it -> !Objects.equals(it, "minecraft/pack.json"), false);
}
}

View File

@ -0,0 +1,85 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<String> 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<String> 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<String> 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());
}
}

View File

@ -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)
private HMCLModpackManifest() {}
}

View File

@ -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<GameProfile> names) throws NoSelectedCharacterException {
return names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account));

View File

@ -0,0 +1,31 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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
}
}

View File

@ -0,0 +1,91 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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());
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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);
}
}

View File

@ -0,0 +1,51 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<String, AccountFactory<?>> 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;
}
}

View File

@ -0,0 +1,36 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<DownloadProvider> DOWNLOAD_PROVIDERS = Arrays.asList(MojangDownloadProvider.INSTANCE, BMCLAPIDownloadProvider.INSTANCE);
public static DownloadProvider getDownloadProvider(int index) {
return Lang.get(DOWNLOAD_PROVIDERS, index).orElse(MojangDownloadProvider.INSTANCE);
}
}

View File

@ -0,0 +1,28 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<String> FONTS = Font.getFamilies();
}

View File

@ -0,0 +1,112 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<SupportedLocale> 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);
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<Proxy.Type> 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);
}
}

View File

@ -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 {

View File

@ -0,0 +1,61 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<String>();
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;
}
}

View File

@ -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<String>, result: Any?)
: this(JFXListView<String>().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);
}
}

View File

@ -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);
}

View File

@ -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() {

View File

@ -1,167 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<Modpack>(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<Version>(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<Task>()
private val dependents = mutableListOf<Task>()
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<Version>(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<String>, 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<String>,
private val modpack: Modpack,
private val output: File,
private val id: String = ID): TaskResult<ZipEngine>() {
override fun getId() = id
init {
onDone() += { event -> if (event.isFailed) output.delete() }
}
override fun execute() {
val blackList = ArrayList<String>(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"
}
}

View File

@ -1,96 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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)
}
}

View File

@ -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

View File

@ -1,110 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
*
* 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<String, AccountFactory<*>>(
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()
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -194,7 +194,7 @@ public abstract class Task {
executor().start();
}
public final boolean test() throws Exception {
public final boolean test() {
return executor().test();
}

View File

@ -182,6 +182,13 @@ public final class Lang {
return (V) o;
}
public static <V> Optional<V> get(List<V> list, int index) {
if (index < 0 || index >= list.size())
return Optional.empty();
else
return Optional.ofNullable(list.get(index));
}
public static <V> Optional<V> get(Map<?, ?> map, Object key, Class<V> clazz) {
return convert(map.get(key), clazz);
}
@ -248,4 +255,9 @@ public final class Lang {
return defaultValue;
}
}
public static <T> T nonNull(T... t) {
for (T a : t) if (a != null) return a;
return null;
}
}