mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-08-04 03:46:57 -04:00
Merge e1e9cf930be0d47ac48f6fbc9dcd897ab2e86ef5 into 9969dc60c5278340b6b9a4d7facdde620e99d1f5
This commit is contained in:
commit
46ecd12eb8
@ -25,6 +25,7 @@ import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCInstanceConfiguration;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.server.ServerModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.modrinth.ModrinthModpackExportTask;
|
||||
import org.jackhuang.hmcl.setting.Config;
|
||||
import org.jackhuang.hmcl.setting.FontManager;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
@ -100,6 +101,9 @@ public final class ExportWizardProvider implements WizardProvider {
|
||||
case ModpackTypeSelectionPage.MODPACK_TYPE_SERVER:
|
||||
exportTask = exportAsServer(exportInfo, dest);
|
||||
break;
|
||||
case ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH:
|
||||
exportTask = exportAsModrinth(exportInfo, dest);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unrecognized modpack type " + modpackType);
|
||||
}
|
||||
@ -233,6 +237,27 @@ public final class ExportWizardProvider implements WizardProvider {
|
||||
};
|
||||
}
|
||||
|
||||
private Task<?> exportAsModrinth(ModpackExportInfo exportInfo, File modpackFile) {
|
||||
return new Task<Void>() {
|
||||
Task<?> dependency;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
dependency = new ModrinthModpackExportTask(
|
||||
profile.getRepository(),
|
||||
version,
|
||||
exportInfo,
|
||||
modpackFile
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task<?>> getDependencies() {
|
||||
return Collections.singleton(dependency);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node createPage(WizardController controller, int step, Map<String, Object> settings) {
|
||||
switch (step) {
|
||||
|
@ -53,6 +53,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.jfxListCellFactory;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE;
|
||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH;
|
||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER;
|
||||
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
|
||||
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||
@ -80,6 +81,8 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
||||
private final SimpleStringProperty launchArguments = new SimpleStringProperty("");
|
||||
private final SimpleStringProperty javaArguments = new SimpleStringProperty("");
|
||||
private final SimpleStringProperty mcbbsThreadId = new SimpleStringProperty("");
|
||||
private final SimpleBooleanProperty noCreateRemoteFiles = new SimpleBooleanProperty();
|
||||
private final SimpleBooleanProperty skipCurseForgeRemoteFiles = new SimpleBooleanProperty();
|
||||
|
||||
public ModpackInfoPage(WizardController controller, HMCLGameRepository gameRepository, String version) {
|
||||
this.controller = controller;
|
||||
@ -102,7 +105,13 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
||||
private void onNext() {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle(i18n("modpack.wizard.step.initialization.save"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
|
||||
if (controller.getSettings().get(MODPACK_TYPE) == ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH) {
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.mrpack"));
|
||||
fileChooser.setInitialFileName(name.get() + ".mrpack");
|
||||
} else {
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
|
||||
fileChooser.setInitialFileName(name.get() + ".zip");
|
||||
}
|
||||
File file = fileChooser.showSaveDialog(Controllers.getStage());
|
||||
if (file == null) {
|
||||
controller.onEnd();
|
||||
@ -122,6 +131,8 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
||||
exportInfo.setLaunchArguments(launchArguments.get());
|
||||
exportInfo.setJavaArguments(javaArguments.get());
|
||||
exportInfo.setAuthlibInjectorServer(authlibInjectorServer.get());
|
||||
exportInfo.setNoCreateRemoteFiles(noCreateRemoteFiles.get());
|
||||
exportInfo.setSkipCurseForgeRemoteFiles(skipCurseForgeRemoteFiles.get());
|
||||
|
||||
if (StringUtils.isNotBlank(mcbbsThreadId.get())) {
|
||||
exportInfo.setOrigins(Collections.singletonList(new McbbsModpackManifest.Origin(
|
||||
@ -178,6 +189,10 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
||||
Hyperlink hyperlink = new Hyperlink(i18n("modpack.wizard.step.initialization.server"));
|
||||
hyperlink.setOnAction(e -> FXUtils.openLink(Metadata.DOCS_URL + "/modpack/serverpack.html"));
|
||||
borderPane.setTop(hyperlink);
|
||||
} if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_MODRINTH) {
|
||||
HintPane pane = new HintPane(MessageDialogPane.MessageType.INFO);
|
||||
pane.setText(i18n("modpack.wizard.step.initialization.modrinth.info"));
|
||||
borderPane.setTop(pane);
|
||||
} else {
|
||||
HintPane pane = new HintPane(MessageDialogPane.MessageType.INFO);
|
||||
pane.setText(i18n("modpack.wizard.step.initialization.warning"));
|
||||
@ -366,6 +381,32 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
||||
button.setMaxHeight(16);
|
||||
pane.setRight(button);
|
||||
}
|
||||
|
||||
if (skinnable.options.isRequireNoCreateRemoteFiles()) {
|
||||
BorderPane noCreateRemoteFiles = new BorderPane();
|
||||
noCreateRemoteFiles.setLeft(new Label(i18n("modpack.wizard.step.initialization.no_create_remote_files")));
|
||||
list.getContent().add(noCreateRemoteFiles);
|
||||
|
||||
JFXToggleButton noCreateRemoteFilesButton = new JFXToggleButton();
|
||||
noCreateRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.noCreateRemoteFiles);
|
||||
noCreateRemoteFilesButton.setSize(8);
|
||||
noCreateRemoteFilesButton.setMinHeight(16);
|
||||
noCreateRemoteFilesButton.setMaxHeight(16);
|
||||
noCreateRemoteFiles.setRight(noCreateRemoteFilesButton);
|
||||
}
|
||||
|
||||
if (skinnable.options.isRequireSkipCurseForgeRemoteFiles()) {
|
||||
BorderPane skipCurseForgeRemoteFiles = new BorderPane();
|
||||
skipCurseForgeRemoteFiles.setLeft(new Label(i18n("modpack.wizard.step.initialization.skip_curseforge_remote_files")));
|
||||
list.getContent().add(skipCurseForgeRemoteFiles);
|
||||
|
||||
JFXToggleButton skipCurseForgeRemoteFilesButton = new JFXToggleButton();
|
||||
skipCurseForgeRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.skipCurseForgeRemoteFiles);
|
||||
skipCurseForgeRemoteFilesButton.setSize(8);
|
||||
skipCurseForgeRemoteFilesButton.setMinHeight(16);
|
||||
skipCurseForgeRemoteFilesButton.setMaxHeight(16);
|
||||
skipCurseForgeRemoteFiles.setRight(skipCurseForgeRemoteFilesButton);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ import org.jackhuang.hmcl.mod.ModpackExportInfo;
|
||||
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.server.ServerModpackExportTask;
|
||||
import org.jackhuang.hmcl.mod.modrinth.ModrinthModpackExportTask;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||
@ -56,7 +57,8 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage {
|
||||
title,
|
||||
createButton(MODPACK_TYPE_MCBBS, McbbsModpackExportTask.OPTION),
|
||||
createButton(MODPACK_TYPE_MULTIMC, MultiMCModpackExportTask.OPTION),
|
||||
createButton(MODPACK_TYPE_SERVER, ServerModpackExportTask.OPTION)
|
||||
createButton(MODPACK_TYPE_SERVER, ServerModpackExportTask.OPTION),
|
||||
createButton(MODPACK_TYPE_MODRINTH, ModrinthModpackExportTask.OPTION)
|
||||
);
|
||||
}
|
||||
|
||||
@ -100,4 +102,5 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage {
|
||||
public static final String MODPACK_TYPE_MCBBS = "mcbbs";
|
||||
public static final String MODPACK_TYPE_MULTIMC = "multimc";
|
||||
public static final String MODPACK_TYPE_SERVER = "server";
|
||||
public static final String MODPACK_TYPE_MODRINTH = "modrinth";
|
||||
}
|
||||
|
@ -904,6 +904,7 @@ modpack.type.manual.warning=The modpack is manually packaged by the publisher, w
|
||||
modpack.type.mcbbs=MCBBS
|
||||
modpack.type.mcbbs.export=Can be imported by Hello Minecraft! Launcher
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=Can be imported by popular third-party launchers
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=Can be imported by Hello Minecraft! Launcher and MultiMC
|
||||
modpack.type.server=Auto-Update Modpack from Server
|
||||
@ -921,7 +922,10 @@ modpack.wizard.step.3.title=Choose modpack type you wanted to export as.
|
||||
modpack.wizard.step.initialization.exported_version=Game Instance to Export
|
||||
modpack.wizard.step.initialization.force_update=Force updating the modpack to the latest version (you will need a file-hosting server)
|
||||
modpack.wizard.step.initialization.include_launcher=Include the launcher
|
||||
modpack.wizard.step.initialization.modrinth.info=The launcher will match CurseForge/Modrinth remote resources instead of local files (including mods, resource packs, and shader packs) during modpack creation to reduce the modpack size, and mark files with ".disabled" extension as optional for installation.
|
||||
modpack.wizard.step.initialization.no_create_remote_files=Do not match remote files
|
||||
modpack.wizard.step.initialization.save=Export to...
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=Do not match CurseForge remote resources
|
||||
modpack.wizard.step.initialization.warning=Before making a modpack, please make sure the game can be launched normally and Minecraft is a release version instead of a snapshot. The launcher will save your download settings.\n\
|
||||
\n\
|
||||
Keep in mind that you are not allowed to add mods and resource packs that explicitly state they could not to be distributed or put in a modpack.
|
||||
|
@ -909,6 +909,7 @@ modpack.type.manual.warning=Este archivo contiene una copia completa de una inst
|
||||
modpack.type.mcbbs=Tipo MCBBS
|
||||
modpack.type.mcbbs.export=Puede ser importado por Hello Minecraft! Launcher
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=Puede ser importado por los principales lanzadores de terceros
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=Puede ser importado por Hello Minecraft! Launcher y MultiMC
|
||||
modpack.type.server=Actualización automática del modpack desde el servidor
|
||||
@ -926,7 +927,10 @@ modpack.wizard.step.3.title=Elija el tipo de modpack que desea exportar.
|
||||
modpack.wizard.step.initialization.exported_version=Instancia del juego a exportar
|
||||
modpack.wizard.step.initialization.force_update=Forzar la actualización del modpack a la última versión (necesitarás un servicio de alojamiento de archivos)
|
||||
modpack.wizard.step.initialization.include_launcher=Incluir el launcher
|
||||
modpack.wizard.step.initialization.modrinth.info=El lanzador comparará los recursos remotos de CurseForge/Modrinth en lugar de los archivos locales (incluidos mods, paquetes de recursos y paquetes de shaders) durante la creación del modpack para reducir su tamaño, y marcará los archivos con extensión «.disabled» como opcionales para la instalación.
|
||||
modpack.wizard.step.initialization.no_create_remote_files=No utilice recursos remotos para sustituir archivos locales
|
||||
modpack.wizard.step.initialization.save=Exportar a...
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=No utilice los recursos remotos de CurseForge para sustituir archivos locales
|
||||
modpack.wizard.step.initialization.warning=Antes de hacer un modpack, por favor asegúrate de que el juego puede ser lanzado normalmente y Minecraft es una versión de lanzamiento en lugar de una snapshot. El launcher guardará tu configuración de descarga.\n\
|
||||
\n\
|
||||
Ten en cuenta que no se te permite añadir mods y paquetes de recursos que se digan explícitamente que no se pueden distribuir o poner en un modpack.
|
||||
|
@ -624,6 +624,8 @@ modpack.type.curse.not_found=必要なリソースの一部が欠落している
|
||||
modpack.type.manual.warning=このmodpackをインポートする代わりに、おそらくこのmodpackファイルを直接解凍する必要があります。そして、バンドルされたランチャーを使用してゲームを起動します。このmodpackは、ランチャーによってエクスポートされるのではなく、.minecraftディレクトリを圧縮することによって手動で作成されます。HMCLはこのmodpackのインポートを試みることができます、続行しますか?
|
||||
modpack.type.mcbbs=MCBBS標準
|
||||
modpack.type.mcbbs.export=Hello Minecraftでインポートできます!ランチャー
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=メインストリームのサードパーティ製イニシエータでインポート可能
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=Hello Minecraftでインポートできます!ランチャーとMultiMC
|
||||
modpack.type.server=サーバー自動更新Modpack
|
||||
@ -641,7 +643,10 @@ modpack.wizard.step.3.title=modpackの形式を選択します。
|
||||
modpack.wizard.step.initialization.exported_version=エクスポートされたゲームバージョン
|
||||
modpack.wizard.step.initialization.force_update=可能であればmodpackを強制的に更新します
|
||||
modpack.wizard.step.initialization.include_launcher=ランチャーを含める
|
||||
modpack.wizard.step.initialization.modrinth.info=モッドパック作成プロセスにおいて、CurseForge/Modrinth のリモートリソースと一致するローカルファイルを置換して容量を削減し、.disabledサフィックス付きファイルをインストール時オプションとしてマーク
|
||||
modpack.wizard.step.initialization.no_create_remote_files=リモートファイルとの一致を行わない
|
||||
modpack.wizard.step.initialization.save=エクスポート先...
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=CurseForge リモートリソースのマッチングをスキップ
|
||||
modpack.wizard.step.initialization.warning=modpackを作成する前に、ゲームが正常に起動できること、および\nMinecraftがリリースバージョンであることを確認する必要があります。\n再配布できないmodを追加しないでください。
|
||||
modpack.wizard.step.initialization.server=サーバーの自動更新modpackの詳細については、ここをクリックしてください
|
||||
|
||||
|
@ -908,6 +908,7 @@ modpack.type.manual.warning=Возможно, вам нужно напрямую
|
||||
modpack.type.mcbbs=MCBBS
|
||||
modpack.type.mcbbs.export=Может быть импортирован Hello Minecraft! Launcher
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=Может быть импортирован популярными сторонними лаунчеры
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=Может быть импортирован Hello Minecraft! Launcher и MultiMC
|
||||
modpack.type.server=Сервер автообновления модпака
|
||||
@ -925,7 +926,10 @@ modpack.wizard.step.3.title=Выберите тип модпака, которы
|
||||
modpack.wizard.step.initialization.exported_version=Сборка игры для экспорта
|
||||
modpack.wizard.step.initialization.force_update=Принудительное обновление модпака до последней версии (вам понадобится служба хостинга файлов)
|
||||
modpack.wizard.step.initialization.include_launcher=Включать лаунчер
|
||||
modpack.wizard.step.initialization.modrinth.info=Лаунчер будет использовать удаленные ресурсы CurseForge/Modrinth вместо локальных файлов (включая моды, пакеты ресурсов и пакеты шейдеров) при создании модпака, чтобы уменьшить размер модпака, и помечать файлы с расширением «.disabled» как необязательные для установки.
|
||||
modpack.wizard.step.initialization.no_create_remote_files=Не используйте удаленные файлы
|
||||
modpack.wizard.step.initialization.save=Экспортировать в...
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=Не используйте удаленные файлы CurseForge
|
||||
modpack.wizard.step.initialization.warning=Перед созданием модпака убедитесь, что игра запускается нормально и Minecraft является релизной версией, а не снапшотом. Пусковая установка сохранит ваши настройки скачивания.\n\
|
||||
\n\
|
||||
Помните, что вам не разрешается добавлять моды и пакет ресурсов, в которых явно указано, что они не подлежат распространению или помещению в модпак.
|
||||
|
@ -720,6 +720,7 @@ modpack.type.manual.warning=該模組包由發佈者手動打包,其中可能
|
||||
modpack.type.mcbbs=MCBBS 模組包
|
||||
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 匯入
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=可以被主流第三方啟動器匯入
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=可以被 Hello Minecraft! Launcher 和 MultiMC 匯入
|
||||
modpack.type.server=伺服器自動更新模組包
|
||||
@ -737,7 +738,10 @@ modpack.wizard.step.3.title=選取模組包匯出類型
|
||||
modpack.wizard.step.initialization.exported_version=要匯出的遊戲實例
|
||||
modpack.wizard.step.initialization.force_update=強制升級模組包至最新版本 (需要自建伺服器)
|
||||
modpack.wizard.step.initialization.include_launcher=包含啟動器
|
||||
modpack.wizard.step.initialization.modrinth.info=在模組包建立過程中,啟動器將匹配 CurseForge/Modrinth 遠端資源替代本機檔案(包括模組、資源包和光影包)以縮減模組包大小,並將副檔名為「.disabled」的檔案標註為「安裝時可選項」。
|
||||
modpack.wizard.step.initialization.no_create_remote_files=不匹配遠端檔案
|
||||
modpack.wizard.step.initialization.save=選取要匯出到的遊戲模組包位置
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=不匹配 CurseForge 遠端資源
|
||||
modpack.wizard.step.initialization.warning=在製作模組包前,請你確認你選取的實例可以正常啟動,\n並保證你的 Minecraft 是正式版而非快照,\n而且不應將不允許非官方途徑傳播的模組、資源 (紋理) 包等納入模組包。\n模組包會儲存你目前的下載來源設定。
|
||||
modpack.wizard.step.initialization.server=點選此處查看有關伺服器自動更新模組包的製作教學
|
||||
|
||||
|
@ -730,6 +730,7 @@ modpack.type.manual.warning=该整合包由发布者手动打包,其中可能
|
||||
modpack.type.mcbbs=MCBBS 整合包 (推荐)
|
||||
modpack.type.mcbbs.export=可以被 Hello Minecraft! Launcher 导入
|
||||
modpack.type.modrinth=Modrinth
|
||||
modpack.type.modrinth.export=可以被主流第三方启动器导入
|
||||
modpack.type.multimc=MultiMC
|
||||
modpack.type.multimc.export=可以被 Hello Minecraft! Launcher 和 MultiMC 导入
|
||||
modpack.type.server=服务器自动更新整合包
|
||||
@ -747,7 +748,10 @@ modpack.wizard.step.3.title=选择整合包导出类型
|
||||
modpack.wizard.step.initialization.exported_version=要导出的游戏版本
|
||||
modpack.wizard.step.initialization.force_update=强制升级整合包至最新版本 (需要自建服务器)
|
||||
modpack.wizard.step.initialization.include_launcher=包含启动器
|
||||
modpack.wizard.step.initialization.modrinth.info=在整合包创建过程中,启动器将匹配 CurseForge/Modrinth 远程资源替代本地文件(包括模组、资源包和光影包)以缩减整合包体积,并将扩展名为“.disabled”的文件标注为“安装时可选项”。
|
||||
modpack.wizard.step.initialization.no_create_remote_files=不匹配远程文件
|
||||
modpack.wizard.step.initialization.save=选择要导出到的游戏整合包位置
|
||||
modpack.wizard.step.initialization.skip_curseforge_remote_files=不匹配 CurseForge 远程资源
|
||||
modpack.wizard.step.initialization.warning=在制作整合包前,请你确认你选择的版本可以正常启动,\n并保证你的 Minecraft 是正式版而非快照,\n而且不应当将不允许非官方途径传播的模组、资源 (纹理) 包等纳入整合包。\n整合包会保存你目前的下载源设置。\n如遇到问题,你可以点击右上角帮助按钮进行求助。
|
||||
modpack.wizard.step.initialization.server=点击此处查看有关服务器自动更新整合包的制作教程
|
||||
|
||||
|
@ -42,17 +42,29 @@ public interface ModAdviser {
|
||||
}
|
||||
|
||||
List<String> MODPACK_BLACK_LIST = Lang.immutableListOf(
|
||||
"regex:(.*?)\\.log",
|
||||
"usernamecache.json", "usercache.json", // Minecraft
|
||||
"launcher_profiles.json", "launcher.pack.lzma", // Old Minecraft Launcher
|
||||
"launcher_accounts.json", "launcher_cef_log.txt", "launcher_log.txt", "launcher_msa_credentials.bin", "launcher_settings.json", "launcher_ui_state.json", "realms_persistence.json", "webcache2", "treatment_tags.json", // New Minecraft Launcher
|
||||
"clientId.txt", "PCL.ini", // Plain Craft Launcher
|
||||
"backup", "pack.json", "launcher.jar", "cache", "modpack.cfg", // HMCL
|
||||
"manifest.json", "minecraftinstance.json", ".curseclient", // Curse
|
||||
".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", "CustomSkinLoader/caches" // Mods
|
||||
"regex:(.*?)\\.log",
|
||||
"regex:.*\\.dat_old$", "regex:.*\\.old$", // Backup files
|
||||
"regex:.*\\.BakaCoreInfo$", // BakaXL
|
||||
"regex:.*-natives",
|
||||
"usernamecache.json", "usercache.json", // Minecraft
|
||||
"launcher_profiles.json", "launcher.pack.lzma", // Old Minecraft Launcher
|
||||
"launcher_accounts.json", "launcher_cef_log.txt", "launcher_log.txt", "launcher_msa_credentials.bin", "launcher_settings.json", "launcher_ui_state.json", "realms_persistence.json", "webcache2", "treatment_tags.json", // New Minecraft Launcher
|
||||
"clientId.txt", "PCL.ini", // Plain Craft Launcher
|
||||
"backup", "pack.json", "launcher.jar", "cache", "modpack.cfg", "log4j2.xml", "hmclversion.cfg", // HMCL
|
||||
"manifest.json", "minecraftinstance.json", ".curseclient", // Curse
|
||||
"modrinth.index.json", // Modrinth
|
||||
".fabric", ".mixin.out", ".optifine", // Fabric/OptiFine
|
||||
"jars", "logs", "versions", "assets", "libraries", "crash-reports", "NVIDIA", "AMD", "screenshots", "natives", "native", "$native", "$natives", "server-resource-packs", "command_history.txt", // Minecraft
|
||||
"downloads", "essential", // Downloads and Essential
|
||||
"asm", "backups", "TCNodeTracker", "CustomDISkins", "data", "CustomSkinLoader/caches", // Mods
|
||||
"debug", // Debug files
|
||||
".replay_cache", "replay_recordings", "replay_videos", // ReplayMod
|
||||
"irisUpdateInfo.json", // Iris
|
||||
"modernfix", // ModernFix
|
||||
"modtranslations", // Mod translations
|
||||
"schematics", // Schematics mod
|
||||
"journeymap/data", // JourneyMap
|
||||
"mods/.connector" // Sinytra Connector
|
||||
);
|
||||
|
||||
List<String> MODPACK_SUGGESTED_BLACK_LIST = Lang.immutableListOf(
|
||||
|
@ -29,6 +29,9 @@ public class ModpackExportInfo {
|
||||
|
||||
private List<McbbsModpackManifest.Origin> origins = new ArrayList<>();
|
||||
|
||||
private boolean noCreateRemoteFiles;
|
||||
private boolean skipCurseForgeRemoteFiles;
|
||||
|
||||
public ModpackExportInfo() {}
|
||||
|
||||
public List<String> getWhitelist() {
|
||||
@ -186,6 +189,22 @@ public class ModpackExportInfo {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isNoCreateRemoteFiles() {
|
||||
return noCreateRemoteFiles;
|
||||
}
|
||||
|
||||
public void setNoCreateRemoteFiles(boolean noCreateRemoteFiles) {
|
||||
this.noCreateRemoteFiles = noCreateRemoteFiles;
|
||||
}
|
||||
|
||||
public boolean isSkipCurseForgeRemoteFiles() {
|
||||
return skipCurseForgeRemoteFiles;
|
||||
}
|
||||
|
||||
public void setSkipCurseForgeRemoteFiles(boolean skipCurseForgeRemoteFiles) {
|
||||
this.skipCurseForgeRemoteFiles = skipCurseForgeRemoteFiles;
|
||||
}
|
||||
|
||||
public ModpackExportInfo validate() throws NullPointerException {
|
||||
return this;
|
||||
}
|
||||
@ -200,6 +219,8 @@ public class ModpackExportInfo {
|
||||
private boolean requireLaunchArguments;
|
||||
private boolean requireJavaArguments;
|
||||
private boolean requireOrigins;
|
||||
private boolean requireNoCreateRemoteFiles;
|
||||
private boolean requireSkipCurseForgeRemoteFiles;
|
||||
|
||||
public Options() {
|
||||
}
|
||||
@ -240,6 +261,14 @@ public class ModpackExportInfo {
|
||||
return requireOrigins;
|
||||
}
|
||||
|
||||
public boolean isRequireNoCreateRemoteFiles() {
|
||||
return requireNoCreateRemoteFiles;
|
||||
}
|
||||
|
||||
public boolean isRequireSkipCurseForgeRemoteFiles() {
|
||||
return requireSkipCurseForgeRemoteFiles;
|
||||
}
|
||||
|
||||
public Options requireUrl() {
|
||||
requireUrl = true;
|
||||
return this;
|
||||
@ -281,5 +310,14 @@ public class ModpackExportInfo {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options requireNoCreateRemoteFiles() {
|
||||
requireNoCreateRemoteFiles = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options requireSkipCurseForgeRemoteFiles() {
|
||||
requireSkipCurseForgeRemoteFiles = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,182 @@
|
||||
package org.jackhuang.hmcl.mod.modrinth;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.mod.ModAdviser;
|
||||
import org.jackhuang.hmcl.mod.Modpack;
|
||||
import org.jackhuang.hmcl.mod.ModpackExportInfo;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.DigestUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.Zipper;
|
||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public class ModrinthModpackExportTask extends Task<Void> {
|
||||
private final DefaultGameRepository repository;
|
||||
private final String version;
|
||||
private final ModpackExportInfo info;
|
||||
private final File modpackFile;
|
||||
|
||||
public ModrinthModpackExportTask(DefaultGameRepository repository, String version, ModpackExportInfo info, File modpackFile) {
|
||||
this.repository = repository;
|
||||
this.version = version;
|
||||
this.info = info.validate();
|
||||
this.modpackFile = modpackFile;
|
||||
|
||||
onDone().register(event -> {
|
||||
if (event.isFailed()) modpackFile.delete();
|
||||
});
|
||||
}
|
||||
|
||||
private ModrinthManifest.File tryGetRemoteFile(Path file, String relativePath) throws IOException {
|
||||
if (info.isNoCreateRemoteFiles()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isDisabled = repository.getModManager(version).isDisabled(file);
|
||||
if (isDisabled) {
|
||||
relativePath = repository.getModManager(version).enableMod(Paths.get(relativePath)).toString();
|
||||
}
|
||||
|
||||
LocalModFile localModFile = null;
|
||||
Optional<RemoteMod.Version> modrinthVersion = Optional.empty();
|
||||
Optional<RemoteMod.Version> curseForgeVersion = Optional.empty();
|
||||
|
||||
try {
|
||||
modrinthVersion = ModrinthRemoteModRepository.MODS.getRemoteVersionByLocalFile(localModFile, file);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to get remote file from Modrinth for: " + file, e);
|
||||
}
|
||||
|
||||
if (!info.isSkipCurseForgeRemoteFiles() && CurseForgeRemoteModRepository.isAvailable()) {
|
||||
try {
|
||||
curseForgeVersion = CurseForgeRemoteModRepository.MODS.getRemoteVersionByLocalFile(localModFile, file);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to get remote file from CurseForge for: " + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!modrinthVersion.isPresent() && !curseForgeVersion.isPresent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, String> hashes = new HashMap<>();
|
||||
hashes.put("sha1", DigestUtils.digestToString("SHA-1", file));
|
||||
hashes.put("sha512", DigestUtils.digestToString("SHA-512", file));
|
||||
|
||||
Map<String, String> env = null;
|
||||
if (isDisabled) {
|
||||
env = new HashMap<>();
|
||||
env.put("client", "optional");
|
||||
}
|
||||
|
||||
List<URL> downloads = new ArrayList<>();
|
||||
if (modrinthVersion.isPresent())
|
||||
downloads.add(new URL(modrinthVersion.get().getFile().getUrl()));
|
||||
if (curseForgeVersion.isPresent())
|
||||
downloads.add(new URL(curseForgeVersion.get().getFile().getUrl()));
|
||||
|
||||
long fileSize = Files.size(file);
|
||||
if (fileSize > Integer.MAX_VALUE) {
|
||||
LOG.warning("File " + relativePath + " is too large (size: " + fileSize + " bytes), precision may be lost when converting to int");
|
||||
}
|
||||
return new ModrinthManifest.File(
|
||||
relativePath,
|
||||
hashes,
|
||||
env,
|
||||
downloads,
|
||||
(int) fileSize
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
ArrayList<String> blackList = new ArrayList<>(ModAdviser.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");
|
||||
try (Zipper zip = new Zipper(modpackFile.toPath())) {
|
||||
Path runDirectory = repository.getRunDirectory(version).toPath();
|
||||
List<ModrinthManifest.File> files = new ArrayList<>();
|
||||
Set<String> filesInManifest = new HashSet<>();
|
||||
|
||||
String[] resourceDirs = {"resourcepacks", "shaderpacks", "mods"};
|
||||
for (String dir : resourceDirs) {
|
||||
Path dirPath = runDirectory.resolve(dir);
|
||||
if (Files.exists(dirPath)) {
|
||||
Files.walk(dirPath)
|
||||
.filter(Files::isRegularFile)
|
||||
.forEach(file -> {
|
||||
try {
|
||||
String relativePath = runDirectory.relativize(file).normalize().toString().replace(File.separatorChar, '/');
|
||||
|
||||
if (!info.getWhitelist().contains(relativePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModrinthManifest.File fileEntry = tryGetRemoteFile(file, relativePath);
|
||||
if (fileEntry != null) {
|
||||
files.add(fileEntry);
|
||||
filesInManifest.add(relativePath);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to process file: " + file, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
zip.putDirectory(runDirectory, "client-overrides", path -> {
|
||||
String relativePath = path.toString().replace(File.separatorChar, '/');
|
||||
if (filesInManifest.contains(relativePath)) {
|
||||
return false;
|
||||
}
|
||||
return Modpack.acceptFile(path, blackList, info.getWhitelist());
|
||||
});
|
||||
|
||||
String gameVersion = repository.getGameVersion(version)
|
||||
.orElseThrow(() -> new IOException("Cannot parse the version of " + version));
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(version), gameVersion);
|
||||
|
||||
Map<String, String> dependencies = new HashMap<>();
|
||||
dependencies.put("minecraft", gameVersion);
|
||||
|
||||
analyzer.getVersion(FORGE).ifPresent(forgeVersion ->
|
||||
dependencies.put("forge", forgeVersion));
|
||||
analyzer.getVersion(NEO_FORGE).ifPresent(neoForgeVersion ->
|
||||
dependencies.put("neoforge", neoForgeVersion));
|
||||
analyzer.getVersion(FABRIC).ifPresent(fabricVersion ->
|
||||
dependencies.put("fabric-loader", fabricVersion));
|
||||
analyzer.getVersion(QUILT).ifPresent(quiltVersion ->
|
||||
dependencies.put("quilt-loader", quiltVersion));
|
||||
|
||||
ModrinthManifest manifest = new ModrinthManifest(
|
||||
"minecraft",
|
||||
1,
|
||||
info.getVersion(),
|
||||
info.getName(),
|
||||
info.getDescription(),
|
||||
files,
|
||||
dependencies
|
||||
);
|
||||
|
||||
zip.putTextFile(JsonUtils.GSON.toJson(manifest), "modrinth.index.json");
|
||||
}
|
||||
}
|
||||
|
||||
public static final ModpackExportInfo.Options OPTION = new ModpackExportInfo.Options()
|
||||
.requireNoCreateRemoteFiles()
|
||||
.requireSkipCurseForgeRemoteFiles();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user