Support exporting multimc modpack

This commit is contained in:
huanghongxun 2019-08-16 21:13:54 +08:00
parent 86bf3d473a
commit 880b8cb072
15 changed files with 450 additions and 92 deletions

View File

@ -17,6 +17,7 @@
*/ */
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.mod.ModAdviser;
import org.jackhuang.hmcl.mod.Modpack; import org.jackhuang.hmcl.mod.Modpack;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
@ -55,7 +56,7 @@ public class HMCLModpackExportTask extends Task<Void> {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
ArrayList<String> blackList = new ArrayList<>(HMCLModpackManager.MODPACK_BLACK_LIST); ArrayList<String> blackList = new ArrayList<>(ModAdviser.MODPACK_BLACK_LIST);
blackList.add(version + ".jar"); blackList.add(version + ".jar");
blackList.add(version + ".json"); 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"); 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");

View File

@ -19,7 +19,6 @@ package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import org.jackhuang.hmcl.mod.Modpack; import org.jackhuang.hmcl.mod.Modpack;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.CompressingUtils;
@ -27,51 +26,12 @@ import org.jackhuang.hmcl.util.io.CompressingUtils;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
/** /**
* @author huangyuhui * @author huangyuhui
*/ */
public final class HMCLModpackManager { public final class HMCLModpackManager {
public static final List<String> MODPACK_BLACK_LIST = Lang.immutableListOf(
"usernamecache.json", "usercache.json", // Minecraft
"launcher_profiles.json", "launcher.pack.lzma", // Minecraft Launcher
"pack.json", "launcher.jar", "hmclmc.log", "cache", // HMCL
"manifest.json", "minecraftinstance.json", ".curseclient", // Curse
"minetweaker.log", // Mods
"jars", "logs", "versions", "assets", "libraries", "crash-reports", "NVIDIA", "AMD", "screenshots", "natives", "native", "$native", "server-resource-packs", // Minecraft
"downloads", // Curse
"asm", "backups", "TCNodeTracker", "CustomDISkins", "data" // Mods
);
public static final List<String> MODPACK_SUGGESTED_BLACK_LIST = Lang.immutableListOf(
"fonts", // BetterFonts
"saves", "servers.dat", "options.txt", // Minecraft
"blueprints" /* BuildCraft */,
"optionsof.txt" /* OptiFine */,
"journeymap" /* JourneyMap */,
"optionsshaders.txt",
"mods/VoxelMods");
public static ModAdviser.ModSuggestion suggestMod(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. * Read the manifest in a HMCL modpack.
* *

View File

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

@ -20,14 +20,18 @@ package org.jackhuang.hmcl.ui.export;
import javafx.scene.Node; import javafx.scene.Node;
import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.game.HMCLModpackExportTask; import org.jackhuang.hmcl.game.HMCLModpackExportTask;
import org.jackhuang.hmcl.game.HMCLModpackManager; import org.jackhuang.hmcl.mod.ModAdviser;
import org.jackhuang.hmcl.mod.Modpack; import org.jackhuang.hmcl.mod.Modpack;
import org.jackhuang.hmcl.mod.MultiMCInstanceConfiguration;
import org.jackhuang.hmcl.mod.MultiMCModpackExportTask;
import org.jackhuang.hmcl.setting.Config; import org.jackhuang.hmcl.setting.Config;
import org.jackhuang.hmcl.setting.ConfigHolder; import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.VersionSetting;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardProvider; import org.jackhuang.hmcl.ui.wizard.WizardProvider;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.io.Zipper; import org.jackhuang.hmcl.util.io.Zipper;
import java.io.File; import java.io.File;
@ -57,27 +61,37 @@ public final class ExportWizardProvider implements WizardProvider {
public Object finish(Map<String, Object> settings) { public Object finish(Map<String, Object> settings) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<String> whitelist = (List<String>) settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION); List<String> whitelist = (List<String>) settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION);
File modpackFile = (File) settings.get(ModpackInfoPage.MODPACK_FILE);
String modpackName = (String) settings.get(ModpackInfoPage.MODPACK_NAME);
String modpackAuthor = (String) settings.get(ModpackInfoPage.MODPACK_AUTHOR);
String modpackVersion = (String) settings.get(ModpackInfoPage.MODPACK_VERSION);
String modpackDescription = (String) settings.get(ModpackInfoPage.MODPACK_DESCRIPTION);
String modpackType = (String) settings.get(ModpackTypeSelectionPage.MODPACK_TYPE);
boolean includeLauncher = (Boolean) settings.get(ModpackInfoPage.MODPACK_INCLUDE_LAUNCHER);
switch (modpackType) {
case ModpackTypeSelectionPage.MODPACK_TYPE_HMCL:
return exportAsHMCL(whitelist, modpackFile, modpackName, modpackAuthor, modpackVersion, modpackDescription, includeLauncher);
case ModpackTypeSelectionPage.MODPACK_TYPE_MULTIMC:
return exportAsMultiMC(whitelist, modpackFile, modpackName, modpackAuthor, modpackVersion, modpackDescription);
default:
throw new IllegalStateException("Unrecognized modpack type " + modpackType);
}
}
private Task<?> exportAsHMCL(List<String> whitelist, File modpackFile, String modpackName, String modpackAuthor, String modpackVersion, String modpackDescription, boolean includeLauncherRaw) {
List<File> launcherJar = Launcher.getCurrentJarFiles(); List<File> launcherJar = Launcher.getCurrentJarFiles();
boolean includeLauncher = (Boolean) settings.get(ModpackInfoPage.MODPACK_INCLUDE_LAUNCHER) && launcherJar != null; boolean includeLauncher = includeLauncherRaw && launcherJar != null;
return new Task<Void>() { return new Task<Void>() {
Task<?> dependency = null; Task<?> dependency = null;
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
File modpackFile = (File) settings.get(ModpackInfoPage.MODPACK_FILE);
File tempModpack = includeLauncher ? Files.createTempFile("hmcl", ".zip").toFile() : modpackFile; File tempModpack = includeLauncher ? Files.createTempFile("hmcl", ".zip").toFile() : modpackFile;
dependency = new HMCLModpackExportTask(profile.getRepository(), version, whitelist, dependency = new HMCLModpackExportTask(profile.getRepository(), version, whitelist,
new Modpack( new Modpack(modpackName, modpackAuthor, modpackVersion, null, modpackDescription, StandardCharsets.UTF_8, null), tempModpack);
(String) settings.get(ModpackInfoPage.MODPACK_NAME),
(String) settings.get(ModpackInfoPage.MODPACK_AUTHOR),
(String) settings.get(ModpackInfoPage.MODPACK_VERSION),
null,
(String) settings.get(ModpackInfoPage.MODPACK_DESCRIPTION),
StandardCharsets.UTF_8,
null
), tempModpack);
if (includeLauncher) { if (includeLauncher) {
dependency = dependency.thenRunAsync(() -> { dependency = dependency.thenRunAsync(() -> {
@ -120,11 +134,55 @@ public final class ExportWizardProvider implements WizardProvider {
}; };
} }
private Task<?> exportAsMultiMC(List<String> whitelist, File modpackFile, String modpackName, String modpackAuthor, String modpackVersion, String modpackDescription) {
return new Task<Void>() {
Task<?> dependency;
@Override
public void execute() {
VersionSetting vs = profile.getVersionSetting(version);
dependency = new MultiMCModpackExportTask(profile.getRepository(), version, whitelist,
new MultiMCInstanceConfiguration(
"OneSix",
modpackName + "-" + modpackVersion,
null,
Lang.toIntOrNull(vs.getPermSize()),
vs.getWrapper(),
vs.getPreLaunchCommand(),
null,
modpackDescription,
null,
vs.getJavaArgs(),
vs.isFullscreen(),
vs.getWidth(),
vs.getHeight(),
vs.getMaxMemory(),
vs.getMinMemory(),
vs.isShowLogs(),
/* showConsoleOnError */ true,
/* autoCloseConsole */ false,
/* overrideMemory */ true,
/* overrideJavaLocation */ false,
/* overrideJavaArgs */ true,
/* overrideConsole */ true,
/* overrideCommands */ true,
/* overrideWindow */ true
), modpackFile);
}
@Override
public Collection<Task<?>> getDependencies() {
return Collections.singleton(dependency);
}
};
}
@Override @Override
public Node createPage(WizardController controller, int step, Map<String, Object> settings) { public Node createPage(WizardController controller, int step, Map<String, Object> settings) {
switch (step) { switch (step) {
case 0: return new ModpackInfoPage(controller, version); case 0: return new ModpackInfoPage(controller, version);
case 1: return new ModpackFileSelectionPage(controller, profile, version, HMCLModpackManager::suggestMod); case 1: return new ModpackFileSelectionPage(controller, profile, version, ModAdviser::suggestMod);
case 2: return new ModpackTypeSelectionPage(controller);
default: throw new IllegalArgumentException("step"); default: throw new IllegalArgumentException("step");
} }
} }

View File

@ -25,7 +25,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.game.ModAdviser; import org.jackhuang.hmcl.mod.ModAdviser;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel; import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel;
@ -146,7 +146,7 @@ public final class ModpackFileSelectionPage extends StackPane implements WizardP
LinkedList<String> list = new LinkedList<>(); LinkedList<String> list = new LinkedList<>();
getFilesNeeded(rootNode, "minecraft", list); getFilesNeeded(rootNode, "minecraft", list);
controller.getSettings().put(MODPACK_FILE_SELECTION, list); controller.getSettings().put(MODPACK_FILE_SELECTION, list);
controller.onFinish(); controller.onNext();
} }
@Override @Override

View File

@ -0,0 +1,66 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.export;
import com.jfoenix.controls.JFXButton;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import java.util.Map;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ModpackTypeSelectionPage extends StackPane implements WizardPage {
private final WizardController controller;
@FXML
private JFXButton btnHMCL;
@FXML
private JFXButton btnMultiMC;
public ModpackTypeSelectionPage(WizardController controller) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/modpack/type.fxml");
JFXButton[] buttons = new JFXButton[]{btnHMCL, btnMultiMC};
String[] types = new String[]{MODPACK_TYPE_HMCL, MODPACK_TYPE_MULTIMC};
for (int i = 0; i < types.length; ++i) {
String type = types[i];
buttons[i].setOnMouseClicked(e -> {
controller.getSettings().put(MODPACK_TYPE, type);
controller.onFinish();
});
}
}
@Override
public void cleanup(Map<String, Object> settings) {
}
@Override
public String getTitle() {
return i18n("modpack.wizard.step.3.title");
}
public static final String MODPACK_TYPE = "modpack.type";
public static final String MODPACK_TYPE_MULTIMC = "multimc";
public static final String MODPACK_TYPE_HMCL = "hmcl";
}

View File

@ -17,7 +17,7 @@
<bottom> <bottom>
<HBox alignment="CENTER_RIGHT" style="-fx-padding: 16 16 16 0;"> <HBox alignment="CENTER_RIGHT" style="-fx-padding: 16 16 16 0;">
<JFXButton fx:id="btnNext" onMouseClicked="#onNext" prefWidth="100" prefHeight="40" buttonType="RAISED" <JFXButton fx:id="btnNext" onMouseClicked="#onNext" prefWidth="100" prefHeight="40" buttonType="RAISED"
text="%wizard.finish" styleClass="jfx-button-raised"/> text="%wizard.next" styleClass="jfx-button-raised"/>
</HBox> </HBox>
</bottom> </bottom>
</BorderPane> </BorderPane>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.TwoLineListItem?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<fx:define>
<Insets fx:id="insets" topRightBottomLeft="8" />
</fx:define>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<Label padding="${insets}" text="%modpack.export.as" />
<JFXButton fx:id="btnHMCL" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.type.hmcl" subtitle="%modpack.type.hmcl.export" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnMultiMC" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.type.multimc" subtitle="%modpack.type.multimc.export" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</fx:root>

View File

@ -219,6 +219,7 @@ modpack.choose=Choose a modpack zip file which you want to install.
modpack.desc=Describe your modpack, including precautions, changlog, supporting Markdown(also supporting online pictures). modpack.desc=Describe your modpack, including precautions, changlog, supporting Markdown(also supporting online pictures).
modpack.enter_name=Enter your desired name for this game. modpack.enter_name=Enter your desired name for this game.
modpack.export=Export Modpack modpack.export=Export Modpack
modpack.export.as=Export Modpack As...
modpack.files.blueprints=BuildCraft blueprints modpack.files.blueprints=BuildCraft blueprints
modpack.files.config=Mod configs modpack.files.config=Mod configs
modpack.files.dumps=NEI debug output modpack.files.dumps=NEI debug output
@ -248,7 +249,9 @@ modpack.type.curse.tolerable_error=But we cannot complete downloading all files
modpack.type.curse.error=Unable to complete this Curse modpack. Please retry. modpack.type.curse.error=Unable to complete this Curse modpack. Please retry.
modpack.type.curse.not_found=Some of required resources are deleted and cannot be downloaded. Please consider the latest version or other modpacks. modpack.type.curse.not_found=Some of required resources are deleted and cannot be downloaded. Please consider the latest version or other modpacks.
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.hmcl.export=Can be imported by Hello Minecraft! Launcher
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.type.multimc.export=Can be imported by Hello Minecraft! Launcher and MultiMC
modpack.unsupported=Unsupported modpack, only HMCL, MultiMC, Curse modpacks are supported. modpack.unsupported=Unsupported modpack, only HMCL, MultiMC, Curse modpacks are supported.
modpack.update=Upgrading game modpack.update=Upgrading game
modpack.wizard=Exporting the modpack wizard modpack.wizard=Exporting the modpack wizard
@ -256,7 +259,8 @@ modpack.wizard.step.1=Basic options
modpack.wizard.step.1.title=Set the basic options to the modpack. modpack.wizard.step.1.title=Set the basic options to the modpack.
modpack.wizard.step.2=Files selection modpack.wizard.step.2=Files selection
modpack.wizard.step.2.title=Choose the files you want to put into the modpack. modpack.wizard.step.2.title=Choose the files you want to put into the modpack.
modpack.wizard.step.3=Description modpack.wizard.step.3=Modpack Type
modpack.wizard.step.3.title=Choose the format of the modpack.
modpack.wizard.step.initialization.exported_version=The exported game version modpack.wizard.step.initialization.exported_version=The exported game version
modpack.wizard.step.initialization.include_launcher=Include the launcher modpack.wizard.step.initialization.include_launcher=Include the launcher
modpack.wizard.step.initialization.save=Choose a path to export the game files to modpack.wizard.step.initialization.save=Choose a path to export the game files to

View File

@ -217,6 +217,7 @@ modpack.choose=選擇要安裝的遊戲整合包檔案
modpack.desc=描述你要製作的整合包,比如整合包注意事項和更新記錄,支援 Markdown圖片請上傳至網路 modpack.desc=描述你要製作的整合包,比如整合包注意事項和更新記錄,支援 Markdown圖片請上傳至網路
modpack.enter_name=給遊戲取個你喜歡的名字 modpack.enter_name=給遊戲取個你喜歡的名字
modpack.export=匯出整合包 modpack.export=匯出整合包
modpack.export.as=請選擇整合包類型。若你無法決定,請選擇 HMCL 類型。
modpack.files.blueprints=BuildCraft 藍圖 modpack.files.blueprints=BuildCraft 藍圖
modpack.files.config=Mod 模組設定檔案 modpack.files.config=Mod 模組設定檔案
modpack.files.dumps=NEI 調校輸出 modpack.files.dumps=NEI 調校輸出
@ -246,7 +247,9 @@ modpack.type.curse.tolerable_error=但未能完成 Curse 整合包文件的下
modpack.type.curse.error=無法完成 Curse 整合包的下載,請多次重試或設定代理 modpack.type.curse.error=無法完成 Curse 整合包的下載,請多次重試或設定代理
modpack.type.curse.not_found=部分必需檔案已經從網路中被刪除並且再也無法下載,請嘗試該整合包的最新版本或者安裝其他整合包。 modpack.type.curse.not_found=部分必需檔案已經從網路中被刪除並且再也無法下載,請嘗試該整合包的最新版本或者安裝其他整合包。
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.hmcl.export=可以被 Hello Minecraft! Launcher (HMCL) 導入
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.type.multimc.export=可以被 Hello Minecraft! Launcher (HMCL) 和 MultiMC 導入
modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。 modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。
modpack.update=正在升級整合包 modpack.update=正在升級整合包
modpack.wizard=匯出整合包引導 modpack.wizard=匯出整合包引導
@ -254,7 +257,8 @@ modpack.wizard.step.1=基本設定
modpack.wizard.step.1.title=設定整合包的主要訊息 modpack.wizard.step.1.title=設定整合包的主要訊息
modpack.wizard.step.2=檔案選擇 modpack.wizard.step.2=檔案選擇
modpack.wizard.step.2.title=選中你想加到整合包中的檔案或資料夾 modpack.wizard.step.2.title=選中你想加到整合包中的檔案或資料夾
modpack.wizard.step.3=整合包描述 modpack.wizard.step.3=整合包類型
modpack.wizard.step.3.title=選擇整合包導出類型
modpack.wizard.step.initialization.exported_version=要匯出的遊戲版本 modpack.wizard.step.initialization.exported_version=要匯出的遊戲版本
modpack.wizard.step.initialization.include_launcher=包含啟動器 modpack.wizard.step.initialization.include_launcher=包含啟動器
modpack.wizard.step.initialization.save=選擇要匯出到的遊戲整合包位置 modpack.wizard.step.initialization.save=選擇要匯出到的遊戲整合包位置

View File

@ -218,6 +218,7 @@ modpack.choose=选择要安装的游戏整合包文件
modpack.desc=描述你要制作的整合包,比如整合包注意事项和更新记录,支持 Markdown图片请用网络图 modpack.desc=描述你要制作的整合包,比如整合包注意事项和更新记录,支持 Markdown图片请用网络图
modpack.enter_name=给游戏起个你喜欢的名字 modpack.enter_name=给游戏起个你喜欢的名字
modpack.export=导出整合包 modpack.export=导出整合包
modpack.export.as=请选择整合包类型。若你无法决定,请选择 HMCL 类型。
modpack.files.blueprints=BuildCraft 蓝图 modpack.files.blueprints=BuildCraft 蓝图
modpack.files.config=Mod 配置文件 modpack.files.config=Mod 配置文件
modpack.files.dumps=NEI 调试输出 modpack.files.dumps=NEI 调试输出
@ -247,7 +248,9 @@ modpack.type.curse.tolerable_error=但未能完成 Curse 整合包文件的下
modpack.type.curse.error=未能完成 Curse 整合包的下载,请多次重试或设置代理 modpack.type.curse.error=未能完成 Curse 整合包的下载,请多次重试或设置代理
modpack.type.curse.not_found=部分必需文件已经在网络中被删除并且再也无法下载,请尝试该整合包的最新版本或者安装其他整合包。 modpack.type.curse.not_found=部分必需文件已经在网络中被删除并且再也无法下载,请尝试该整合包的最新版本或者安装其他整合包。
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.hmcl.export=可以被 Hello Minecraft! Launcher (HMCL) 导入
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.type.multimc.export=可以被 Hello Minecraft! Launcher (HMCL) 和 MultiMC 导入
modpack.unsupported=该整合包不被支持。仅 HMCL、MultiMC、Curse 整合包受支持。 modpack.unsupported=该整合包不被支持。仅 HMCL、MultiMC、Curse 整合包受支持。
modpack.update=正在升级整合包 modpack.update=正在升级整合包
modpack.wizard=导出整合包向导 modpack.wizard=导出整合包向导
@ -255,7 +258,8 @@ modpack.wizard.step.1=基本设置
modpack.wizard.step.1.title=设置整合包的主要信息 modpack.wizard.step.1.title=设置整合包的主要信息
modpack.wizard.step.2=文件选择 modpack.wizard.step.2=文件选择
modpack.wizard.step.2.title=选中你想加到整合包中的文件或文件夹 modpack.wizard.step.2.title=选中你想加到整合包中的文件或文件夹
modpack.wizard.step.3=整合包描述 modpack.wizard.step.3=整合包类型
modpack.wizard.step.3.title=选择整合包导出类型
modpack.wizard.step.initialization.exported_version=要导出的游戏版本 modpack.wizard.step.initialization.exported_version=要导出的游戏版本
modpack.wizard.step.initialization.include_launcher=包含启动器 modpack.wizard.step.initialization.include_launcher=包含启动器
modpack.wizard.step.initialization.save=选择要导出到的游戏整合包位置 modpack.wizard.step.initialization.save=选择要导出到的游戏整合包位置

View File

@ -0,0 +1,75 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.mod;
import org.jackhuang.hmcl.util.Lang;
import java.util.List;
/**
* @author huangyuhui
*/
public interface ModAdviser {
ModSuggestion advise(String fileName, boolean isDirectory);
enum ModSuggestion {
SUGGESTED,
NORMAL,
HIDDEN
}
List<String> MODPACK_BLACK_LIST = Lang.immutableListOf(
"usernamecache.json", "usercache.json", // Minecraft
"launcher_profiles.json", "launcher.pack.lzma", // Minecraft Launcher
"pack.json", "launcher.jar", "hmclmc.log", "cache", // HMCL
"manifest.json", "minecraftinstance.json", ".curseclient", // Curse
"minetweaker.log", // Mods
".fabric", ".mixin.out", // Fabric
"jars", "logs", "versions", "assets", "libraries", "crash-reports", "NVIDIA", "AMD", "screenshots", "natives", "native", "$native", "server-resource-packs", // Minecraft
"downloads", // Curse
"asm", "backups", "TCNodeTracker", "CustomDISkins", "data" // Mods
);
List<String> MODPACK_SUGGESTED_BLACK_LIST = Lang.immutableListOf(
"fonts", // BetterFonts
"saves", "servers.dat", "options.txt", // Minecraft
"blueprints" /* BuildCraft */,
"optionsof.txt" /* OptiFine */,
"journeymap" /* JourneyMap */,
"optionsshaders.txt",
"mods/VoxelMods");
static ModAdviser.ModSuggestion suggestMod(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;
}
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;
}
}

View File

@ -36,6 +36,7 @@ import java.util.Properties;
*/ */
public final class MultiMCInstanceConfiguration { public final class MultiMCInstanceConfiguration {
private final String instanceType; // InstanceType
private final String name; // name private final String name; // name
private final String gameVersion; // IntendedVersion private final String gameVersion; // IntendedVersion
private final Integer permGen; // PermGen private final Integer permGen; // PermGen
@ -68,6 +69,7 @@ public final class MultiMCInstanceConfiguration {
this.mmcPack = mmcPack; this.mmcPack = mmcPack;
instanceType = p.getProperty("InstanceType");
autoCloseConsole = Boolean.parseBoolean(p.getProperty("AutoCloseConsole")); autoCloseConsole = Boolean.parseBoolean(p.getProperty("AutoCloseConsole"));
gameVersion = mmcPack != null ? mmcPack.getComponents().stream().filter(e -> "net.minecraft".equals(e.getUid())).findAny() gameVersion = mmcPack != null ? mmcPack.getComponents().stream().filter(e -> "net.minecraft".equals(e.getUid())).findAny()
.orElseThrow(() -> new IOException("Malformed mmc-pack.json")).getVersion() : p.getProperty("IntendedVersion"); .orElseThrow(() -> new IOException("Malformed mmc-pack.json")).getVersion() : p.getProperty("IntendedVersion");
@ -94,6 +96,38 @@ public final class MultiMCInstanceConfiguration {
notes = Optional.ofNullable(p.getProperty("notes")).orElse(""); notes = Optional.ofNullable(p.getProperty("notes")).orElse("");
} }
public MultiMCInstanceConfiguration(String instanceType, String name, String gameVersion, Integer permGen, String wrapperCommand, String preLaunchCommand, String postExitCommand, String notes, String javaPath, String jvmArgs, boolean fullscreen, Integer width, Integer height, Integer maxMemory, Integer minMemory, boolean showConsole, boolean showConsoleOnError, boolean autoCloseConsole, boolean overrideMemory, boolean overrideJavaLocation, boolean overrideJavaArgs, boolean overrideConsole, boolean overrideCommands, boolean overrideWindow) {
this.instanceType = instanceType;
this.name = name;
this.gameVersion = gameVersion;
this.permGen = permGen;
this.wrapperCommand = wrapperCommand;
this.preLaunchCommand = preLaunchCommand;
this.postExitCommand = postExitCommand;
this.notes = notes;
this.javaPath = javaPath;
this.jvmArgs = jvmArgs;
this.fullscreen = fullscreen;
this.width = width;
this.height = height;
this.maxMemory = maxMemory;
this.minMemory = minMemory;
this.showConsole = showConsole;
this.showConsoleOnError = showConsoleOnError;
this.autoCloseConsole = autoCloseConsole;
this.overrideMemory = overrideMemory;
this.overrideJavaLocation = overrideJavaLocation;
this.overrideJavaArgs = overrideJavaArgs;
this.overrideConsole = overrideConsole;
this.overrideCommands = overrideCommands;
this.overrideWindow = overrideWindow;
this.mmcPack = null;
}
public String getInstanceType() {
return instanceType;
}
/** /**
* The instance's name. * The instance's name.
*/ */
@ -260,6 +294,35 @@ public final class MultiMCInstanceConfiguration {
return overrideWindow; return overrideWindow;
} }
public Properties toProperties() {
Properties p = new Properties();
if (instanceType != null) p.setProperty("InstanceType", instanceType);
p.setProperty("AutoCloseConsole", Boolean.toString(autoCloseConsole));
if (gameVersion != null) p.setProperty("IntendedVersion", gameVersion);
if (javaPath != null) p.setProperty("JavaPath", javaPath);
if (jvmArgs != null) p.setProperty("JvmArgs", jvmArgs);
p.setProperty("LaunchMaximized", Boolean.toString(fullscreen));
if (maxMemory != null) p.setProperty("MaxMemAlloc", Integer.toString(maxMemory));
if (minMemory != null) p.setProperty("MinMemAlloc", Integer.toString(minMemory));
if (height != null) p.setProperty("MinecraftWinHeight", Integer.toString(height));
if (width != null) p.setProperty("MinecraftWinWidth", Integer.toString(width));
p.setProperty("OverrideCommands", Boolean.toString(overrideCommands));
p.setProperty("OverrideConsole", Boolean.toString(overrideConsole));
p.setProperty("OverrideJavaArgs", Boolean.toString(overrideJavaArgs));
p.setProperty("OverrideJavaLocation", Boolean.toString(overrideJavaLocation));
p.setProperty("OverrideMemory", Boolean.toString(overrideMemory));
p.setProperty("OverrideWindow", Boolean.toString(overrideWindow));
if (permGen != null) p.setProperty("PermGen", Integer.toString(permGen));
if (postExitCommand != null) p.setProperty("PostExitCommand", postExitCommand);
if (preLaunchCommand != null) p.setProperty("PreLaunchCommand", preLaunchCommand);
p.setProperty("ShowConsole", Boolean.toString(showConsole));
p.setProperty("ShowConsoleOnError", Boolean.toString(showConsoleOnError));
if (wrapperCommand != null) p.setProperty("WrapperCommand", wrapperCommand);
if (name != null) p.setProperty("name", name);
if (notes != null) p.setProperty("notes", notes);
return p;
}
public MultiMCManifest getMmcPack() { public MultiMCManifest getMmcPack() {
return mmcPack; return mmcPack;
} }

View File

@ -113,17 +113,25 @@ public final class MultiMCManifest {
@SerializedName("important") @SerializedName("important")
private final boolean important; private final boolean important;
@SerializedName("dependencyOnly")
private final boolean dependencyOnly;
@SerializedName("uid") @SerializedName("uid")
private final String uid; private final String uid;
@SerializedName("version") @SerializedName("version")
private final String version; private final String version;
public MultiMCManifestComponent(String cachedName, List<MultiMCManifestCachedRequires> cachedRequires, String cachedVersion, boolean important, String uid, String version) { public MultiMCManifestComponent(boolean important, boolean dependencyOnly, String uid, String version) {
this(null, null, null, important, dependencyOnly, uid, version);
}
public MultiMCManifestComponent(String cachedName, List<MultiMCManifestCachedRequires> cachedRequires, String cachedVersion, boolean important, boolean dependencyOnly, String uid, String version) {
this.cachedName = cachedName; this.cachedName = cachedName;
this.cachedRequires = cachedRequires; this.cachedRequires = cachedRequires;
this.cachedVersion = cachedVersion; this.cachedVersion = cachedVersion;
this.important = important; this.important = important;
this.dependencyOnly = dependencyOnly;
this.uid = uid; this.uid = uid;
this.version = version; this.version = version;
} }
@ -144,6 +152,10 @@ public final class MultiMCManifest {
return important; return important;
} }
public boolean isDependencyOnly() {
return dependencyOnly;
}
public String getUid() { public String getUid() {
return uid; return uid;
} }

View File

@ -0,0 +1,101 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> and contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.mod;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.GameVersion;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.Zipper;
import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
/**
* Export the game to a mod pack file.
*/
public class MultiMCModpackExportTask extends Task<Void> {
private final DefaultGameRepository repository;
private final String versionId;
private final List<String> whitelist;
private final MultiMCInstanceConfiguration configuration;
private final File output;
/**
* @param output mod pack file.
* @param versionId to locate version.json
*/
public MultiMCModpackExportTask(DefaultGameRepository repository, String versionId, List<String> whitelist, MultiMCInstanceConfiguration configuration, File output) {
this.repository = repository;
this.versionId = versionId;
this.whitelist = whitelist;
this.configuration = configuration;
this.output = output;
onDone().register(event -> {
if (event.isFailed()) output.delete();
});
}
@Override
public void execute() throws Exception {
ArrayList<String> blackList = new ArrayList<>(ModAdviser.MODPACK_BLACK_LIST);
blackList.add(versionId + ".jar");
blackList.add(versionId + ".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 (Zipper zip = new Zipper(output.toPath())) {
zip.putDirectory(repository.getRunDirectory(versionId).toPath(), ".minecraft", path -> {
if (path.isEmpty())
return true;
for (String s : blackList)
if (path.equals(s))
return false;
for (String s : whitelist)
if (path.equals(s))
return true;
return false;
});
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedVersion(versionId));
String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(versionId))
.orElseThrow(() -> new IllegalStateException("Cannot parse the version of " + versionId));
List<MultiMCManifest.MultiMCManifestComponent> components = new ArrayList<>();
components.add(new MultiMCManifest.MultiMCManifestComponent(true, false, "net.minecraft", gameVersion));
analyzer.getVersion(FORGE).ifPresent(forgeVersion ->
components.add(new MultiMCManifest.MultiMCManifestComponent(false, false, "net.minecraftforge", forgeVersion)));
analyzer.getVersion(LITELOADER).ifPresent(liteLoaderVersion ->
components.add(new MultiMCManifest.MultiMCManifestComponent(false, false, "com.mumfrey.liteloader", liteLoaderVersion)));
analyzer.getVersion(FABRIC).ifPresent(fabricVersion ->
components.add(new MultiMCManifest.MultiMCManifestComponent(false, false, "net.fabricmc.fabric-loader", fabricVersion)));
MultiMCManifest mmcPack = new MultiMCManifest(1, components);
zip.putTextFile(JsonUtils.GSON.toJson(mmcPack), "mmc-pack.json");
StringWriter writer = new StringWriter();
configuration.toProperties().store(writer, "Auto generated by Hello Minecraft! Launcher");
zip.putTextFile(writer.toString(), "instance.cfg");
zip.putTextFile("", ".packignore");
}
}
}