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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}. * 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 { private HMCLModpackManifest() {}
fun createWizard(namespace: String = "", provider: WizardProvider): Node = DefaultWizardDisplayer(namespace, provider)
} }

View File

@ -28,6 +28,10 @@ import java.util.List;
* @author huangyuhui * @author huangyuhui
*/ */
public final class HMCLMultiCharacterSelector implements MultiCharacterSelector { public final class HMCLMultiCharacterSelector implements MultiCharacterSelector {
public static final HMCLMultiCharacterSelector INSTANCE = new HMCLMultiCharacterSelector();
private HMCLMultiCharacterSelector() {}
@Override @Override
public GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException { public GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException {
return names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account)); 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.PropertyResourceBundle;
import java.util.ResourceBundle; 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 @Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException { 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}. * 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 javafx.scene.Node;
import com.jfoenix.controls.JFXTextArea
import javafx.scene.Node
class Summary( public final class Wizard {
/**
* The component that will display the summary information public static Node createWizard(WizardProvider provider) {
*/ return createWizard("", provider);
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) {
} }
constructor(text: String, result: Any?) public static Node createWizard(String namespace, WizardProvider provider) {
: this(JFXTextArea(text).apply { isEditable = false }, result) { 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.MainKt;
import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.MessageBox;
import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.*;
@ -110,11 +111,13 @@ public class AppDataUpgrader extends IUpgrader {
String hash = null; String hash = null;
if (map.containsKey("jarsha1")) if (map.containsKey("jarsha1"))
hash = map.get("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()) new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderJarTask.getSelf(version.toString()).getAbsolutePath())
.directory(new File("").getAbsoluteFile()).start(); .directory(new File("").getAbsoluteFile()).start();
System.exit(0); System.exit(0);
} }
Controllers.INSTANCE.closeDialog();
} catch (IOException ex) { } catch (IOException ex) {
Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex);
} }
@ -123,11 +126,13 @@ public class AppDataUpgrader extends IUpgrader {
String hash = null; String hash = null;
if (map.containsKey("packsha1")) if (map.containsKey("packsha1"))
hash = map.get("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()) new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderPackGzTask.getSelf(version.toString()).getAbsolutePath())
.directory(new File("").getAbsoluteFile()).start(); .directory(new File("").getAbsoluteFile()).start();
System.exit(0); System.exit(0);
} }
Controllers.INSTANCE.closeDialog();
} catch (IOException ex) { } catch (IOException ex) {
Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex);
} }

View File

@ -17,7 +17,9 @@
*/ */
package org.jackhuang.hmcl.upgrade; package org.jackhuang.hmcl.upgrade;
import org.jackhuang.hmcl.MainKt;
import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.util.Charsets; import org.jackhuang.hmcl.util.Charsets;
import org.jackhuang.hmcl.util.FileUtils; import org.jackhuang.hmcl.util.FileUtils;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
@ -51,7 +53,8 @@ public class NewFileUpgrader extends IUpgrader {
URL url = requestDownloadLink(); URL url = requestDownloadLink();
if (url == null) return; if (url == null) return;
File newf = new File(url.getFile()); 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 { try {
new ProcessBuilder(newf.getCanonicalPath(), "--removeOldLauncher", getRealPath()) new ProcessBuilder(newf.getCanonicalPath(), "--removeOldLauncher", getRealPath())
.directory(new File("").getAbsoluteFile()) .directory(new File("").getAbsoluteFile())
@ -61,6 +64,7 @@ public class NewFileUpgrader extends IUpgrader {
} }
System.exit(0); System.exit(0);
} }
Controllers.INSTANCE.closeDialog();
} }
private static String getRealPath() { 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) var locale: Locales.SupportedLocale = Locales.getLocaleByName(SETTINGS.localization)
set(value) { set(value) {
field = value field = value
SETTINGS.localization = Locales.getNameByLocal(value) SETTINGS.localization = Locales.getNameByLocale(value)
} }
var proxy: Proxy = Proxy.NO_PROXY 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() else -> throw UnsupportedOperationException()
} }
account.logIn(HMCLMultiCharacterSelector, Settings.proxy) account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.proxy)
account account
} catch (e: Exception) { } catch (e: Exception) {
e e

View File

@ -57,7 +57,7 @@ class YggdrasilAccountLoginPane(private val oldAccount: YggdrasilAccount, privat
taskResult("login") { taskResult("login") {
try { try {
val account = YggdrasilAccountFactory.INSTANCE.fromUsername(username, password) val account = YggdrasilAccountFactory.INSTANCE.fromUsername(username, password)
account.logIn(HMCLMultiCharacterSelector, Settings.proxy) account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.proxy)
} catch (e: Exception) { } catch (e: Exception) {
e e
} }

View File

@ -25,6 +25,7 @@ import javafx.scene.Parent
import javafx.scene.SnapshotParameters import javafx.scene.SnapshotParameters
import javafx.scene.image.ImageView import javafx.scene.image.ImageView
import javafx.scene.image.WritableImage import javafx.scene.image.WritableImage
import javafx.scene.layout.Pane
import javafx.scene.layout.StackPane import javafx.scene.layout.StackPane
import javafx.util.Duration import javafx.util.Duration
import org.jackhuang.hmcl.ui.takeSnapshot 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] * @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 private var animation: Timeline? = null
override val snapshot = ImageView().apply { override fun getSnapshot() = ImageView().apply {
isPreserveRatio = true isPreserveRatio = true
isSmooth = true isSmooth = true
} }
override lateinit var duration: Duration override fun getView() = view
private set private lateinit var duration: Duration
override fun getDuration() = duration
fun setContent(newView: Node, transition: AnimationProducer, duration: Duration = Duration.millis(320.0)) { fun setContent(newView: Node, transition: AnimationProducer, duration: Duration = Duration.millis(320.0)) {
this.duration = duration this.duration = duration

View File

@ -20,7 +20,7 @@ package org.jackhuang.hmcl.ui.download
import javafx.scene.Node import javafx.scene.Node
import org.jackhuang.hmcl.game.HMCLModpackInstallTask import org.jackhuang.hmcl.game.HMCLModpackInstallTask
import org.jackhuang.hmcl.game.HMCLModpackManifest 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.mod.*
import org.jackhuang.hmcl.setting.EnumGameDirectory import org.jackhuang.hmcl.setting.EnumGameDirectory
import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.setting.Profile
@ -80,7 +80,7 @@ class DownloadWizardProvider(): WizardProvider() {
return when (modpack.manifest) { return when (modpack.manifest) {
is CurseManifest -> CurseInstallTask(profile.dependency, selectedFile, modpack.manifest as CurseManifest, name) is CurseManifest -> CurseInstallTask(profile.dependency, selectedFile, modpack.manifest as CurseManifest, name)
is HMCLModpackManifest -> HMCLModpackInstallTask(profile, selectedFile, modpack, 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() else -> throw Error()
}.with(finalizeTask) }.with(finalizeTask)
} }

View File

@ -22,11 +22,10 @@ import com.jfoenix.controls.JFXTextField
import javafx.application.Platform import javafx.application.Platform
import javafx.fxml.FXML import javafx.fxml.FXML
import javafx.scene.control.Label import javafx.scene.control.Label
import javafx.scene.layout.BorderPane
import javafx.scene.layout.Region import javafx.scene.layout.Region
import javafx.scene.layout.StackPane import javafx.scene.layout.StackPane
import javafx.stage.FileChooser 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.i18n
import org.jackhuang.hmcl.mod.Modpack import org.jackhuang.hmcl.mod.Modpack
import org.jackhuang.hmcl.setting.Profile 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() } txtModpackName.textProperty().onInvalidated { btnInstall.isDisable = !txtModpackName.validate() }
try { try {
manifest = readModpackManifest(selectedFile) manifest = ModpackHelper.readModpackManifest(selectedFile)
controller.settings[MODPACK_CURSEFORGE_MANIFEST] = manifest!! controller.settings[MODPACK_CURSEFORGE_MANIFEST] = manifest!!
lblName.text = manifest!!.name lblName.text = manifest!!.name
lblVersion.text = manifest!!.version lblVersion.text = manifest!!.version

View File

@ -19,7 +19,7 @@ package org.jackhuang.hmcl.ui.export
import javafx.scene.Node import javafx.scene.Node
import org.jackhuang.hmcl.game.HMCLModpackExportTask 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.mod.Modpack
import org.jackhuang.hmcl.setting.Profile import org.jackhuang.hmcl.setting.Profile
import org.jackhuang.hmcl.ui.wizard.WizardController 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.enter_password=Please enter your password.
ui.message.launching=Launching... ui.message.launching=Launching...
ui.message.making=Generating... ui.message.making=Generating...
ui.message.downloading=Downloading...
ui.message.sure_remove=Sure to remove profile %s? ui.message.sure_remove=Sure to remove profile %s?
ui.message.update_java=Please upgrade your Java. 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. 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(); executor().start();
} }
public final boolean test() throws Exception { public final boolean test() {
return executor().test(); return executor().test();
} }

View File

@ -182,6 +182,13 @@ public final class Lang {
return (V) o; 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) { public static <V> Optional<V> get(Map<?, ?> map, Object key, Class<V> clazz) {
return convert(map.get(key), clazz); return convert(map.get(key), clazz);
} }
@ -248,4 +255,9 @@ public final class Lang {
return defaultValue; return defaultValue;
} }
} }
public static <T> T nonNull(T... t) {
for (T a : t) if (a != null) return a;
return null;
}
} }