From 8077b0bae157317a89b90b81f8358b415514a3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+CiiLu@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:35:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Legacy=20Fabric=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20(#5090)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/game/HMCLGameRepository.java | 2 + .../hmcl/setting/VersionIconType.java | 4 +- .../org/jackhuang/hmcl/ui/InstallerItem.java | 63 ++++----- .../hmcl/ui/construct/TaskListPane.java | 39 +++--- .../ui/download/AbstractInstallersPage.java | 3 +- .../hmcl/ui/download/InstallersPage.java | 40 ++---- .../hmcl/ui/download/VersionsPage.java | 4 + .../hmcl/ui/versions/InstallerListPage.java | 6 +- .../hmcl/ui/versions/ModListPage.java | 4 + .../hmcl/ui/versions/ModListPageSkin.java | 60 +++----- .../hmcl/ui/versions/VersionIconDialog.java | 1 + .../resources/assets/img/legacyfabric.png | Bin 0 -> 2404 bytes .../resources/assets/img/legacyfabric@2x.png | Bin 0 -> 3575 bytes .../resources/assets/lang/I18N.properties | 3 + .../resources/assets/lang/I18N_zh.properties | 3 + .../assets/lang/I18N_zh_CN.properties | 3 + .../download/BMCLAPIDownloadProvider.java | 46 +++---- .../hmcl/download/LibraryAnalyzer.java | 31 ++++- .../hmcl/download/MojangDownloadProvider.java | 45 +++--- .../download/fabric/FabricAPIInstallTask.java | 2 +- .../download/fabric/FabricInstallTask.java | 4 + .../LegacyFabricAPIInstallTask.java | 61 ++++++++ .../LegacyFabricAPIRemoteVersion.java | 67 +++++++++ .../LegacyFabricAPIVersionList.java | 53 +++++++ .../legacyfabric/LegacyFabricInstallTask.java | 130 ++++++++++++++++++ .../LegacyFabricRemoteVersion.java | 44 ++++++ .../legacyfabric/LegacyFabricVersionList.java | 106 ++++++++++++++ .../download/quilt/QuiltAPIInstallTask.java | 2 +- .../hmcl/download/quilt/QuiltInstallTask.java | 4 + .../hmcl/launch/DefaultLauncher.java | 3 + .../org/jackhuang/hmcl/mod/ModLoaderType.java | 3 +- .../mod/mcbbs/McbbsModpackExportTask.java | 2 + 32 files changed, 657 insertions(+), 181 deletions(-) create mode 100644 HMCL/src/main/resources/assets/img/legacyfabric.png create mode 100644 HMCL/src/main/resources/assets/img/legacyfabric@2x.png create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIInstallTask.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIRemoteVersion.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIVersionList.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricInstallTask.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricRemoteVersion.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricVersionList.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index f77a236a4..5d01934f2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -321,6 +321,8 @@ public final class HMCLGameRepository extends DefaultGameRepository { return VersionIconType.FABRIC.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT)) return VersionIconType.QUILT.getIcon(); + else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LEGACY_FABRIC)) + return VersionIconType.LEGACY_FABRIC.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE)) return VersionIconType.NEO_FORGE.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE)) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java index 09675738c..dd19336b8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java @@ -36,7 +36,9 @@ public enum VersionIconType { FURNACE("/assets/img/furnace.png"), QUILT("/assets/img/quilt.png"), APRIL_FOOLS("/assets/img/april_fools.png"), - CLEANROOM("/assets/img/cleanroom.png"); + CLEANROOM("/assets/img/cleanroom.png"), + LEGACY_FABRIC("/assets/img/legacyfabric.png") + ; // Please append new items at last diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java index f16c09715..435a9c19c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java @@ -92,37 +92,18 @@ public class InstallerItem extends Control { this.id = id; this.style = style; - switch (id) { - case "game": - iconType = VersionIconType.GRASS; - break; - case "fabric": - case "fabric-api": - iconType = VersionIconType.FABRIC; - break; - case "forge": - iconType = VersionIconType.FORGE; - break; - case "cleanroom": - iconType = VersionIconType.CLEANROOM; - break; - case "liteloader": - iconType = VersionIconType.CHICKEN; - break; - case "optifine": - iconType = VersionIconType.OPTIFINE; - break; - case "quilt": - case "quilt-api": - iconType = VersionIconType.QUILT; - break; - case "neoforge": - iconType = VersionIconType.NEO_FORGE; - break; - default: - iconType = null; - break; - } + iconType = switch (id) { + case "game" -> VersionIconType.GRASS; + case "fabric", "fabric-api" -> VersionIconType.FABRIC; + case "legacyfabric", "legacyfabric-api" -> VersionIconType.LEGACY_FABRIC; + case "forge" -> VersionIconType.FORGE; + case "cleanroom" -> VersionIconType.CLEANROOM; + case "liteloader" -> VersionIconType.CHICKEN; + case "optifine" -> VersionIconType.OPTIFINE; + case "quilt", "quilt-api" -> VersionIconType.QUILT; + case "neoforge" -> VersionIconType.NEO_FORGE; + default -> null; + }; } public String getLibraryId() { @@ -201,6 +182,8 @@ public class InstallerItem extends Control { InstallerItem fabricApi = new InstallerItem(FABRIC_API, style); InstallerItem forge = new InstallerItem(FORGE, style); InstallerItem cleanroom = new InstallerItem(CLEANROOM, style); + InstallerItem legacyfabric = new InstallerItem(LEGACY_FABRIC, style); + InstallerItem legacyfabricApi = new InstallerItem(LEGACY_FABRIC_API, style); InstallerItem neoForge = new InstallerItem(NEO_FORGE, style); InstallerItem liteLoader = new InstallerItem(LITELOADER, style); InstallerItem optiFine = new InstallerItem(OPTIFINE, style); @@ -208,11 +191,11 @@ public class InstallerItem extends Control { InstallerItem quiltApi = new InstallerItem(QUILT_API, style); Map> incompatibleMap = new HashMap<>(); - mutualIncompatible(incompatibleMap, forge, fabric, quilt, neoForge, cleanroom); - addIncompatibles(incompatibleMap, liteLoader, fabric, quilt, neoForge, cleanroom); - addIncompatibles(incompatibleMap, optiFine, fabric, quilt, neoForge, cleanroom); - addIncompatibles(incompatibleMap, fabricApi, forge, quiltApi, neoForge, liteLoader, optiFine, cleanroom); - addIncompatibles(incompatibleMap, quiltApi, forge, fabric, fabricApi, neoForge, liteLoader, optiFine, cleanroom); + mutualIncompatible(incompatibleMap, forge, fabric, quilt, neoForge, cleanroom, legacyfabric); + addIncompatibles(incompatibleMap, liteLoader, fabric, quilt, neoForge, cleanroom, legacyfabric); + addIncompatibles(incompatibleMap, optiFine, fabric, quilt, neoForge, cleanroom, liteLoader, legacyfabric); + addIncompatibles(incompatibleMap, fabricApi, forge, quiltApi, neoForge, liteLoader, optiFine, cleanroom, legacyfabricApi, legacyfabricApi); + addIncompatibles(incompatibleMap, quiltApi, forge, fabric, fabricApi, neoForge, liteLoader, optiFine, cleanroom, legacyfabric, legacyfabricApi); for (Map.Entry> entry : incompatibleMap.entrySet()) { InstallerItem item = entry.getKey(); @@ -246,7 +229,7 @@ public class InstallerItem extends Control { game.versionProperty.set(new InstalledState(gameVersion, false, false)); } - InstallerItem[] all = {game, forge, neoForge, liteLoader, optiFine, fabric, fabricApi, quilt, quiltApi, cleanroom}; + InstallerItem[] all = {game, forge, neoForge, liteLoader, optiFine, fabric, fabricApi, quilt, quiltApi, legacyfabric, legacyfabricApi, cleanroom}; for (InstallerItem item : all) { if (!item.resolvedStateProperty.isBound()) { @@ -263,9 +246,9 @@ public class InstallerItem extends Control { if (gameVersion == null) { this.libraries = all; } else if (gameVersion.equals("1.12.2")) { - this.libraries = new InstallerItem[]{game, forge, cleanroom, liteLoader, optiFine}; - } else if (GameVersionNumber.compare(gameVersion, "1.13") < 0) { - this.libraries = new InstallerItem[]{game, forge, liteLoader, optiFine}; + this.libraries = new InstallerItem[]{game, forge, cleanroom, liteLoader, legacyfabric, legacyfabricApi, optiFine}; + } else if (GameVersionNumber.compare(gameVersion, "1.13.2") <= 0) { + this.libraries = new InstallerItem[]{game, forge, liteLoader, optiFine, legacyfabric, legacyfabricApi}; } else { this.libraries = new InstallerItem[]{game, forge, neoForge, optiFine, fabric, fabricApi, quilt, quiltApi}; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java index 06153282b..0eb62cbed 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java @@ -41,6 +41,7 @@ import org.jackhuang.hmcl.download.forge.ForgeOldInstallTask; import org.jackhuang.hmcl.download.game.GameAssetDownloadTask; import org.jackhuang.hmcl.download.game.GameInstallTask; import org.jackhuang.hmcl.download.java.mojang.MojangJavaDownloadTask; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricInstallTask; import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask; import org.jackhuang.hmcl.download.neoforge.NeoForgeInstallTask; import org.jackhuang.hmcl.download.neoforge.NeoForgeOldInstallTask; @@ -164,6 +165,8 @@ public final class TaskListPane extends StackPane { task.setName(i18n("install.installer.install", i18n("install.installer.game"))); } else if (task instanceof CleanroomInstallTask) { task.setName(i18n("install.installer.install", i18n("install.installer.cleanroom"))); + } else if (task instanceof LegacyFabricInstallTask) { + task.setName(i18n("install.installer.install", i18n("install.installer.legacyfabric"))); } else if (task instanceof ForgeNewInstallTask || task instanceof ForgeOldInstallTask) { task.setName(i18n("install.installer.install", i18n("install.installer.forge"))); } else if (task instanceof NeoForgeInstallTask || task instanceof NeoForgeOldInstallTask) { @@ -427,23 +430,25 @@ public final class TaskListPane extends StackPane { // CHECKSTYLE:OFF // @formatter:off - switch (stageKey) { - case "hmcl.modpack": message = i18n("install.modpack"); break; - case "hmcl.modpack.download": message = i18n("launch.state.modpack"); break; - case "hmcl.install.assets": message = i18n("assets.download"); break; - case "hmcl.install.libraries": message = i18n("libraries.download"); break; - case "hmcl.install.game": message = i18n("install.installer.install", i18n("install.installer.game") + " " + stageValue); break; - case "hmcl.install.forge": message = i18n("install.installer.install", i18n("install.installer.forge") + " " + stageValue); break; - case "hmcl.install.cleanroom": message = i18n("install.installer.install", i18n("install.installer.cleanroom") + " " + stageValue); break; - case "hmcl.install.neoforge": message = i18n("install.installer.install", i18n("install.installer.neoforge") + " " + stageValue); break; - case "hmcl.install.liteloader": message = i18n("install.installer.install", i18n("install.installer.liteloader") + " " + stageValue); break; - case "hmcl.install.optifine": message = i18n("install.installer.install", i18n("install.installer.optifine") + " " + stageValue); break; - case "hmcl.install.fabric": message = i18n("install.installer.install", i18n("install.installer.fabric") + " " + stageValue); break; - case "hmcl.install.fabric-api": message = i18n("install.installer.install", i18n("install.installer.fabric-api") + " " + stageValue); break; - case "hmcl.install.quilt": message = i18n("install.installer.install", i18n("install.installer.quilt") + " " + stageValue); break; - case "hmcl.install.quilt-api": message = i18n("install.installer.install", i18n("install.installer.quilt-api") + " " + stageValue); break; - default: message = i18n(stageKey); break; - } + message = switch (stageKey) { + case "hmcl.modpack" -> i18n("install.modpack"); + case "hmcl.modpack.download" -> i18n("launch.state.modpack"); + case "hmcl.install.assets" -> i18n("assets.download"); + case "hmcl.install.libraries" -> i18n("libraries.download"); + case "hmcl.install.game" -> i18n("install.installer.install", i18n("install.installer.game") + " " + stageValue); + case "hmcl.install.forge" -> i18n("install.installer.install", i18n("install.installer.forge") + " " + stageValue); + case "hmcl.install.cleanroom" -> i18n("install.installer.install", i18n("install.installer.cleanroom") + " " + stageValue); + case "hmcl.install.neoforge" -> i18n("install.installer.install", i18n("install.installer.neoforge") + " " + stageValue); + case "hmcl.install.liteloader" -> i18n("install.installer.install", i18n("install.installer.liteloader") + " " + stageValue); + case "hmcl.install.optifine" -> i18n("install.installer.install", i18n("install.installer.optifine") + " " + stageValue); + case "hmcl.install.fabric" -> i18n("install.installer.install", i18n("install.installer.fabric") + " " + stageValue); + case "hmcl.install.fabric-api" -> i18n("install.installer.install", i18n("install.installer.fabric-api") + " " + stageValue); + case "hmcl.install.legacyfabric" -> i18n("install.installer.install", i18n("install.installer.legacyfabric") + " " + stageValue); + case "hmcl.install.legacyfabric-api" -> i18n("install.installer.install", i18n("install.installer.legacyfabric-api") + " " + stageValue); + case "hmcl.install.quilt" -> i18n("install.installer.install", i18n("install.installer.quilt") + " " + stageValue); + case "hmcl.install.quilt-api" -> i18n("install.installer.install", i18n("install.installer.quilt-api") + " " + stageValue); + default -> i18n(stageKey); + }; // @formatter:on // CHECKSTYLE:ON diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java index 4ae6406f4..4c1d8919b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java @@ -60,7 +60,8 @@ public abstract class AbstractInstallersPage extends Control implements WizardPa library.setOnInstall(() -> { if (!Boolean.TRUE.equals(config().getShownTips().get(FABRIC_QUILT_API_TIP)) && (LibraryAnalyzer.LibraryType.FABRIC_API.getPatchId().equals(libraryId) - || LibraryAnalyzer.LibraryType.QUILT_API.getPatchId().equals(libraryId))) { + || LibraryAnalyzer.LibraryType.QUILT_API.getPatchId().equals(libraryId) + || LibraryAnalyzer.LibraryType.LEGACY_FABRIC_API.getPatchId().equals(libraryId))) { Controllers.dialog(new MessageDialogPane.Builder( i18n("install.installer.fabric-quilt-api.warning", i18n("install.installer." + libraryId)), i18n("message.warning"), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java index 3635a73d2..d0c4d7b36 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java @@ -121,32 +121,20 @@ public class InstallersPage extends AbstractInstallersPage { LibraryAnalyzer.LibraryType libraryType = LibraryAnalyzer.LibraryType.fromPatchId(libraryId); if (libraryType != null) { - String loaderName; - switch (libraryType) { - case FORGE: - loaderName = i18n("install.installer.forge"); - break; - case NEO_FORGE: - loaderName = i18n("install.installer.neoforge"); - break; - case CLEANROOM: - loaderName = i18n("install.installer.cleanroom"); - break; - case FABRIC: - loaderName = i18n("install.installer.fabric"); - break; - case LITELOADER: - loaderName = i18n("install.installer.liteloader"); - break; - case QUILT: - loaderName = i18n("install.installer.quilt"); - break; - case OPTIFINE: - loaderName = i18n("install.installer.optifine"); - break; - default: - continue; - } + String loaderName = switch (libraryType) { + case FORGE -> i18n("install.installer.forge"); + case NEO_FORGE -> i18n("install.installer.neoforge"); + case CLEANROOM -> i18n("install.installer.cleanroom"); + case LEGACY_FABRIC -> i18n("install.installer.legacyfabric").replace(" ", "_"); + case FABRIC -> i18n("install.installer.fabric"); + case LITELOADER -> i18n("install.installer.liteloader"); + case QUILT -> i18n("install.installer.quilt"); + case OPTIFINE -> i18n("install.installer.optifine"); + default -> null; + }; + + if (loaderName == null) + continue; nameBuilder.append("-").append(loaderName); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index 0e42b999e..795095089 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -38,6 +38,8 @@ import org.jackhuang.hmcl.download.fabric.FabricAPIRemoteVersion; import org.jackhuang.hmcl.download.fabric.FabricRemoteVersion; import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion; import org.jackhuang.hmcl.download.game.GameRemoteVersion; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricAPIRemoteVersion; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricRemoteVersion; import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion; import org.jackhuang.hmcl.download.neoforge.NeoForgeRemoteVersion; import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion; @@ -270,6 +272,8 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab iconType = VersionIconType.CLEANROOM; else if (remoteVersion instanceof NeoForgeRemoteVersion) iconType = VersionIconType.NEO_FORGE; + else if (remoteVersion instanceof LegacyFabricRemoteVersion || remoteVersion instanceof LegacyFabricAPIRemoteVersion) + iconType = VersionIconType.LEGACY_FABRIC; else if (remoteVersion instanceof FabricRemoteVersion || remoteVersion instanceof FabricAPIRemoteVersion) iconType = VersionIconType.FABRIC; else if (remoteVersion instanceof QuiltRemoteVersion || remoteVersion instanceof QuiltAPIRemoteVersion) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java index e1d14634d..a25ca1c77 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/InstallerListPage.java @@ -76,12 +76,12 @@ public class InstallerListPage extends ListPageBase implements Ve InstallerItem.InstallerItemGroup group = new InstallerItem.InstallerItemGroup(gameVersion, InstallerItem.Style.LIST_ITEM); - // Conventional libraries: game, fabric, forge, cleanroom, neoforge, liteloader, optifine + // Conventional libraries: game, fabric, legacyfabric, forge, cleanroom, neoforge, liteloader, optifine for (InstallerItem item : group.getLibraries()) { String libraryId = item.getLibraryId(); - // Skip fabric-api and quilt-api - if (libraryId.contains("fabric-api") || libraryId.contains("quilt-api")) { + // Skip fabric-api and quilt-api and legacyfabric-api + if (libraryId.endsWith("-api")) { continue; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java index 0ef9f01de..641133301 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java @@ -152,6 +152,10 @@ public final class ModListPage extends ListPageBase { RemoteMod remoteMod = repository.getModById(versionOptional.get().getModid()); FXUtils.runInFX(() -> { for (ModLoaderType modLoaderType : versionOptional.get().getLoaders()) { - String loaderName; - switch (modLoaderType) { - case FORGE: - loaderName = i18n("install.installer.forge"); - break; - case CLEANROOM: - loaderName = i18n("install.installer.cleanroom"); - break; - case NEO_FORGED: - loaderName = i18n("install.installer.neoforge"); - break; - case FABRIC: - loaderName = i18n("install.installer.fabric"); - break; - case LITE_LOADER: - loaderName = i18n("install.installer.liteloader"); - break; - case QUILT: - loaderName = i18n("install.installer.quilt"); - break; - default: - continue; - } + String loaderName = switch (modLoaderType) { + case FORGE -> i18n("install.installer.forge"); + case CLEANROOM -> i18n("install.installer.cleanroom"); + case LEGACY_FABRIC -> i18n("install.installer.legacyfabric"); + case NEO_FORGED -> i18n("install.installer.neoforge"); + case FABRIC -> i18n("install.installer.fabric"); + case LITE_LOADER -> i18n("install.installer.liteloader"); + case QUILT -> i18n("install.installer.quilt"); + default -> null; + }; + if (loaderName == null) + continue; if (title.getTags() .stream() .noneMatch(it -> it.getText().equals(loaderName))) { @@ -664,24 +653,13 @@ final class ModListPageSkin extends SkinBase { } else if (!ModListPageSkin.this.getSkinnable().supportedLoaders.contains(modLoaderType)) { warning.add(i18n("mods.warning.loader_mismatch")); switch (dataItem.getModInfo().getModLoaderType()) { - case FORGE: - content.addTagWarning(i18n("install.installer.forge")); - break; - case CLEANROOM: - content.addTagWarning(i18n("install.installer.cleanroom")); - break; - case NEO_FORGED: - content.addTagWarning(i18n("install.installer.neoforge")); - break; - case FABRIC: - content.addTagWarning(i18n("install.installer.fabric")); - break; - case LITE_LOADER: - content.addTagWarning(i18n("install.installer.liteloader")); - break; - case QUILT: - content.addTagWarning(i18n("install.installer.quilt")); - break; + case FORGE -> content.addTagWarning(i18n("install.installer.forge")); + case LEGACY_FABRIC -> content.addTagWarning(i18n("install.installer.legacyfabric")); + case CLEANROOM -> content.addTagWarning(i18n("install.installer.cleanroom")); + case NEO_FORGED -> content.addTagWarning(i18n("install.installer.neoforge")); + case FABRIC -> content.addTagWarning(i18n("install.installer.fabric")); + case LITE_LOADER -> content.addTagWarning(i18n("install.installer.liteloader")); + case QUILT -> content.addTagWarning(i18n("install.installer.quilt")); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java index 3c3521936..a48fc63a0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java @@ -64,6 +64,7 @@ public class VersionIconDialog extends DialogPane { createIcon(VersionIconType.OPTIFINE), createIcon(VersionIconType.CRAFT_TABLE), createIcon(VersionIconType.FABRIC), + createIcon(VersionIconType.LEGACY_FABRIC), createIcon(VersionIconType.FORGE), createIcon(VersionIconType.CLEANROOM), createIcon(VersionIconType.NEO_FORGE), diff --git a/HMCL/src/main/resources/assets/img/legacyfabric.png b/HMCL/src/main/resources/assets/img/legacyfabric.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc7d3a661a4cb9a653ed297bb87082326f97e19 GIT binary patch literal 2404 zcmZ8jc|6nqAOCEOIm*6?Epu)}O>%^WhBmdy6_avrG-p$2mAiiBC?YYD;#){_lp}IW z?z7w!`X)w>RcNH~oA3Ag`{(z1Jf838^L4&o|GnRFHdZHhiOPrq0I-WhB-rv z+5b%4>40SaGbx3ycMQy*1OB_x7JHPh{_WDz)ZEEh^feMy5=XKD04hl$n39QYkIsa~ zyW0P;-IE!_;XU4*3~>4|L3gTNs%RnmQBlNiAnzOm5m18e7xJ(;q7@C3N2O%%H)_J% zR*WT3ZxF2<<72KTkZkhyZcRZ>})ZyxT z^>!!rPO#P^RnWjog{r6-$ld;J=_nBZ_X}O~PASYN!$etET%};Qr?K7*T`_sFa3ev~ z0LSa=esio>>groC^twGD)aaghnilRRqVO(re{WQKL)iv$prPh)H`wMxyu>DE-qPo^ z_GKT4#Z5@Hjr2z^m_Y30Yi>;qr`~%3tv~r~=6$5`#Y?xweJRlB!6cc?kcJwpL)K8k zZc8K-@Kgu({>GVinmlhxc1*gSugR^kB_mGdvLjh~UCVyxTTg_vymBjI zGmC$9=vWX~tdJgWp_gVFY(HW9<~!#uEiIYP(ZGUVr7>-XdA|bvc2^<;UKlRih}|TF zQ`)kI$-aK@G~cqzSsT;?@6?e9WZ{U6z*9fT^MF8EO!61+x>+kdgF}9HlH<3WJONOO zBJ29AOW}{*D~uvYe+KY2rfS*mbSjP3x?+MTo4*1k>O+>ArQX6_Lwj1kZOjDMOA`qz8)iuQc(NKiX}Bp<>1B-4S=Xp2keV$zGV+&U zmQVNIf;Q3fYhO1%hvB9)Efgt8$7Du7s5v+N*6n7B^05d8Rt`&~U}V)v$G-@`B{43g zF4iqJQZT&aQa3J;;`a0&L-tMHrQgld694%CWEo+*I_m^@76gl_`eh+@sbOTuKu_gI z+7sv}vEm5##UQwrKvXR3-ue9VdmypuwXEH_6}B?|1+o|96qYgDzyFN!ch~NVTK)MG z?5!s=q49E~7)hREDoj<(FQnzjRq}4ZY11_8ntidseYLFdJ~+(O?Udu8yJV3ks#{^x z#I@I@aQNvAoxH!o<6?nQW?VZK1mv(XeDc()Qy$M!it=EWqV=2yyYI?o zjO!bOP++&lwvL_5GhE7ES@qyTTUZP_BctfR+Lv_kMm!$hbEZts!C}7Q)MUld3;C+9 zQ_!^I?jB}$fS>zUgq}l?hQ;*MXG+5-~+nG*gZnGr2WvJBzxsf{XCa8+!Wa{I_9pNn5iI)*npY1YEZD6(*PvOe%I@;yxa|s3GxF`xGNH<>0D7HvP|1{mgW)3Se=72cgbaryJ_tGSzqNf z;$)~gV$n)^I>5lEzM;SHEq6q{>01t2Umv_q4VX=o!`-DVX2vS}G!fKOR7l$<71KjS zGvv-a{mrdrAE)rqX+b4(;q^%YjO4c`?`lCzQx2zer#iTv*(W32(V2VQaCvl5#o=7$ z!^DADL)~cycy!+ES3A3y*0e-bQYQ9X3AH6)DtzcH+D7VCxG93+jG*yS1JPDi53XTI zl%vA4Cywdi6oQX`Z#ObjH3v0U7R0Pj6j4&h^8V^!M|AG(tRUg3W1~6-ul+ca9iJQh zi)Q!D1SVp+h1bDK<%{E%4=dW9gbfompiBWzxdPZx&l*WmG*)tplS+BTxG7oKfc z3DLyFYsmKGoKFv>)k1AdH0Urin_~3fk88pxO9OLHLTtM?Q&kFuFC=&t*$+`m#G#FP zF~mCCR*T>a{5~}RLLNGM@UeWp9u(h~&Q0eQJ~@E}uz|7&kE51$-#<5lK0beRQyW-l z5hIU1|LU`R!fR22nAuub2vbB;+W-@47)!9P`$^P6B>~_jP>45gw#jEa6D(k{G?5;N zC@xhz^e~vyf<(~JO@c!10+`-{5C{QuBVYLD^Daeq>z>Ymz*gz+sIB;2jngR$Dhs8J q7TQ_s%N5$`b|L^M=b)&{yGT%PF>N~C1vIzwRUnyJ5sHty-}o>6KQ+_< literal 0 HcmV?d00001 diff --git a/HMCL/src/main/resources/assets/img/legacyfabric@2x.png b/HMCL/src/main/resources/assets/img/legacyfabric@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc9bfcf719629ae03e4b628c8c8cbdc9b81b03f GIT binary patch literal 3575 zcmZ8jcRUpS|G(od`!YXB*>Wh3v&Xr^aVL8eGRsk9Wz=Plj1amb+mVv&J_aYbuJZ%yzt=tkqJ6>XWH~ZF_~iUx|(L2IOx@ zHBraPtuqA>gKJ5Ku zmGu?nvf*vbvUeO#>Ocz)dP_kgGS$BGJFa!_e*Kh+lC%NpvVg{At4EQxlvCpC?WC4P zE-zopjuUlK*Z4HW6a#B(csf2&nx5$hj|bij}NQIWRY!$WxxK=8AF`nyPa+T&<;V+i_@d%uiI6mps-oQC2|9ga>=& zrAHMPg_MvU+1cm~QVP&PVG354G5T;*1FfWp;LOxeoP)uWNB&PJyO!pf0bVAd!MIyJ zrx-i)r0#DCJ^RUhzvCz;;a#U5eLwB3l^oET9;TRU=*z~5FYQvY#KIrQtMYsHe!lfE zzNRGWileG`0?|lY$k0?lM2VkKkCV?vQr1KJdT8hkQyE=jC`5_zj5dpxCt3v~q;}su z=PBL-DXgO_W@#qFFUP2f5P(8iL7mZWMtY$Xd5zThBf{-N!>*N; zMny!L-NT#2#k$1B+dd(9LQ@m-@gLXu4t~AYTvoOb0;HYRmMcEdY}* z#?~JIfb{$YaKPuKD=o+ufVK&+^l=Ng=W-VZFmt)>9UyChwh~s7m6uh!<2{d{)imO4 zux?naG=P!jfC1-#U;vP&3~3PfpZ>dkP$2!kaXOlo2hsu9X>3Qs?KsfCaSxjQYtA(M z?f*aif0qJi3!KUT0MRO73UC;Z^xvs}JHVv>P9oCuU!$YVq5HSeLQR#X{?{cBgZ<4K zjZrWXDKjM6%NwwIC@Vhx=Utw@R$oFXpBAZF+xc}W6|!Gz=~(!I%4cpQwPf0fKaS~R ztcEwF8zpKG0tQ*@y}#dQefK$0TQSQ|0h{YbxQ|gNw3H;|SZ>^gVI&&4$)7#CX1n?P z3G52hC=$}NNn2M=z)_)wU3zkF@P0CR*7l>5Nh9iO-g2%+fBJt`qi08 z&1RltG4G4-QU~6sF|?fFOayN)dquohg1mSxEMFq+k?0sEtPsJ*G+ZOo_p*M)4({gU z25IsyIwJBTIV9!JFlUajS^HRD6#X=n_Waq9S}MaGof4 z@{+mFK4)6=-xEx=wp-Xw8A1{B)!K+}G;Nq~Rle5A9F}46A%k3o%KJmH9-@g5CAI~* znHx_&MW>m{t|xa`%?&5M-V&74KK3?%dgfYO_kSj+oa}uqEJ|@GyS6k5{yYI_w8bzRu18YaiyA7)f-W zJzqQ%ds+0OGac?|!)?#!p&#dIcmQb8ah$w)$Hysf)RyiyU{0sYSF_t!^X~HUpE1ms zZMOIJFBPv8acqqg`Up}a>vRlpQt$uZGqAMa>5_dcHO@T+@Wc3r4{EeM$+(FSGJFvf z;upu#-+#mI9@l~3X30`n#2x%67Flrc%$9=yez#P2v$dqX%-H|O6sGpMdubGlS!dnN zKU^`I#}=EpUj+{@s(k&t>xT^XthpWb^Ovqc#)V1*&tl4(Hh|Ti^UA1KVVzd7(Jb~y zb)MX_c*(dt21!Y6UA>^-TO^rdHhkgAQP+GcBfVbc=b#NP-Tl-4`+FstpSr_7;_dE2 zBs^r?W(c~+oPxSIDEjgHJCCHX7bUZ%-ymSlmOG;wJw@GyQqE_OkE*m=5C<*1yE}(3 z#%AooQ3x1dc0p06f)#4WSlZDeX(yJx^t=nOO6q zleM&n8=1wue9ZskX>X-n;ntSc!epnHh-YZ|4KJ8gs5wpU2hfDYnPkr*omJjD@EvLZMXq(9OR6b(t@> z)JX7x@|1xC2pet*0ox9HM1D19=&%*Ju-v6p)+l8Axga;N?ON#4@An0rJFiD_RKmYq z|L~O8e3DL!sCf*PIOx(%2zf}=f8f?fA9U0y$nfPPo7^~DKs|Xp5U(&=Gw&d^Fam38 z+GuYgq|P%wD=f=W{c{bmH}mwfVgd%@dv|oQ32`_e;?kG@BjKy-)`-d{7v`dI z0&a!77&@z#DFPScN&whaEOtvpHhMlych+iDIa}z7f;geq?lvMdp8F5Vz@2X9(XvIk4bb=;@ALISdwN3hae6uU-Ex zXZ_+Q5K#|lwM!=Wf1TWPIB}lu(RK`SoqC$Uc~gNIw-WK*v|curx~^Ll66QA3x~R2$ zHxFoZuk6I}g#)C$rszuXi)|6dtlXDb<+0>$+X0*_=;K3%Pdrzv#Fjk<#`-~HI`T?Z z@Q3sPqCUxOCdRW4hgWQ7hK9Cl@0EDN1?(Xue!#DDKzq1MUw^lj zf!1zi270Vu5CvJU{%I%qSNgTLc9!SZ;i$6i1~O&CPJ0zf>g57o(pwyNa;AECGURV$ zOtxHci`5n3T77=DHlpH>qKoKB=;pKZ&wHk&K1Is{l%jWIM1!H&x?-8BUZ0s#Qr$_* z-0%Dk^V8l()84CmD@1b`>pB#?HaBd1)iRWe=RK)r{Reyvci&t5!ss+>oLDo*Li4Kb zU1@c-f`f)sfL^g6{M}RGfak4cf%T^aVMdBY^YyklKZxfr1c4vi`+Sv}N}T4dgg<1It@ zNY9!22ze19kyQ3bk}+}#e~$j~u5P3}{;l9)MoE;^8a@Wf&U}fVfoU&er?C72pIIc7 zE|Ct6jARA@_aZh6r8uv+j}NaMfEoEj08U_$J%p+n#XLgw3`)$IZl^&%l5jJ7jb8Ad zLvCAOR5GX^xOnY}BxtpIS1Qd@*a*%j908Q4SjE#NGKoSdC6xUdaEPH|{J0UokCiJV z=B!Jm@YXT%jWAz@RCO);KGR#Z8$`ZGqI^i-ge6XJRD4bXupi1Tp+g)>;QJ?AI~6S2 z%Lv_LGQZKx!^TB4GF!D+wcrNdjR7!$R3Q8}xN-4Zx`U)6g6lHSPZ+{q31{3{td0Iy Uc{W@5;O}P+i#E}#)Nzjb4`9|-6aWAK literal 0 HcmV?d00001 diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index e34ee60f2..b0f28fcb5 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -719,6 +719,8 @@ install.installer.depend=Requires %s install.installer.do_not_install=Do not install install.installer.fabric=Fabric install.installer.fabric-api=Fabric API +install.installer.legacyfabric=Legacy Fabric +install.installer.legacyfabric-api=Legacy Fabric API install.installer.fabric-quilt-api.warning=%1$s is a mod and will be installed into the mod directory of the game instance. Please do not change the working directory of the game, or the %1$s will not function. If you do want to change the directory, you should reinstall it. install.installer.forge=Forge install.installer.neoforge=NeoForge @@ -1296,6 +1298,7 @@ settings.advanced.custom_commands.hint=The following environment variables are p \ · $INST_LITELOADER: set if LiteLoader is installed.\n\ \ · $INST_OPTIFINE: set if OptiFine is installed.\n\ \ · $INST_FABRIC: set if Fabric is installed.\n\ + \ · $INST_LEGACYFABRIC: set if Legacy Fabric is installed.\n\ \ · $INST_QUILT: set if Quilt is installed. settings.advanced.dont_check_game_completeness=Do not check game integrity settings.advanced.dont_check_jvm_validity=Do not check JVM compatibility diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 27be6ce69..7066f0d73 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -518,6 +518,8 @@ install.installer.depend=需要先安裝 %s install.installer.do_not_install=不安裝 install.installer.fabric=Fabric install.installer.fabric-api=Fabric API +install.installer.legacyfabric=Legacy Fabric +install.installer.legacyfabric-api=Legacy Fabric API install.installer.fabric-quilt-api.warning=%1$s 是一個模組,將會被安裝到新遊戲的模組目錄。請你在安裝遊戲後不要修改目前遊戲的「執行路徑」設定。如果你在之後修改了相關設定,則需要重新安裝 %1$s。 install.installer.forge=Forge install.installer.neoforge=NeoForge @@ -1080,6 +1082,7 @@ settings.advanced.custom_commands.hint=自訂指令被呼叫時將包含如下 \ · $INST_LITELOADER: 若安裝了 LiteLoader,將會存在本環境變數;\n\ \ · $INST_OPTIFINE: 若安裝了 OptiFine,將會存在本環境變數;\n\ \ · $INST_FABRIC: 若安裝了 Fabric,將會存在本環境變數;\n\ + \ · $INST_LEGACYFABRIC: 若安裝了 Legacy Fabric,將會存在本環境變數;\n\ \ · $INST_QUILT: 若安裝了 Quilt,將會存在本環境變數。 settings.advanced.dont_check_game_completeness=不檢查遊戲完整性 settings.advanced.dont_check_jvm_validity=不檢查 Java 虛擬機與遊戲的相容性 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index c3a5549d3..7bcaf8ce5 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -521,6 +521,8 @@ install.installer.cleanroom=Cleanroom install.installer.depend=需要先安装 %s install.installer.do_not_install=不安装 install.installer.fabric=Fabric +install.installer.legacyfabric=Legacy Fabric +install.installer.legacyfabric-api=Legacy Fabric API install.installer.fabric-api=Fabric API install.installer.fabric-quilt-api.warning=%1$s 是一个模组,将会被安装到新游戏的模组文件夹。请你在安装游戏后不要修改当前游戏的“版本隔离”设置。如果你在之后修改了相关设置,则需要重新安装 %1$s。 install.installer.forge=Forge @@ -1084,6 +1086,7 @@ settings.advanced.custom_commands.hint=自定义命令被调用时将包含如 \ · $INST_LITELOADER: 若安装了 LiteLoader,将会存在本环境变量;\n\ \ · $INST_OPTIFINE: 若安装了 OptiFine,将会存在本环境变量;\n\ \ · $INST_FABRIC: 若安装了 Fabric,将会存在本环境变量;\n\ + \ · $INST_LEGACYFABRIC: 若安装了 Legacy Fabric,将会存在本环境变量;\n\ \ · $INST_QUILT: 若安装了 Quilt,将会存在本环境变量。 settings.advanced.dont_check_game_completeness=不检查游戏完整性 settings.advanced.dont_check_jvm_validity=不检查 Java 虚拟机与游戏的兼容性 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java index 22b85cbf9..7042d3227 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java @@ -22,6 +22,8 @@ import org.jackhuang.hmcl.download.fabric.FabricAPIVersionList; import org.jackhuang.hmcl.download.fabric.FabricVersionList; import org.jackhuang.hmcl.download.forge.ForgeBMCLVersionList; import org.jackhuang.hmcl.download.game.GameVersionList; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricAPIVersionList; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricVersionList; import org.jackhuang.hmcl.download.liteloader.LiteLoaderBMCLVersionList; import org.jackhuang.hmcl.download.neoforge.NeoForgeBMCLVersionList; import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList; @@ -47,6 +49,8 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider { private final FabricAPIVersionList fabricApi; private final ForgeBMCLVersionList forge; private final CleanroomVersionList cleanroom; + private final LegacyFabricVersionList legacyFabric; + private final LegacyFabricAPIVersionList legacyFabricApi; private final NeoForgeBMCLVersionList neoforge; private final LiteLoaderBMCLVersionList liteLoader; private final OptiFineBMCLVersionList optifine; @@ -66,6 +70,9 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider { this.optifine = new OptiFineBMCLVersionList(apiRoot); this.quilt = new QuiltVersionList(this); this.quiltApi = new QuiltAPIVersionList(this); + this.legacyFabric = new LegacyFabricVersionList(this); + this.legacyFabricApi = new LegacyFabricAPIVersionList(this); + this.replacement = Arrays.asList( pair("https://bmclapi2.bangbang93.com", apiRoot), pair("https://launchermeta.mojang.com", apiRoot), @@ -112,30 +119,21 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider { @Override public VersionList getVersionListById(String id) { - switch (id) { - case "game": - return game; - case "fabric": - return fabric; - case "fabric-api": - return fabricApi; - case "forge": - return forge; - case "cleanroom": - return cleanroom; - case "neoforge": - return neoforge; - case "liteloader": - return liteLoader; - case "optifine": - return optifine; - case "quilt": - return quilt; - case "quilt-api": - return quiltApi; - default: - throw new IllegalArgumentException("Unrecognized version list id: " + id); - } + return switch (id) { + case "game" -> game; + case "fabric" -> fabric; + case "fabric-api" -> fabricApi; + case "forge" -> forge; + case "cleanroom" -> cleanroom; + case "neoforge" -> neoforge; + case "liteloader" -> liteLoader; + case "optifine" -> optifine; + case "quilt" -> quilt; + case "quilt-api" -> quiltApi; + case "legacyfabric" -> legacyFabric; + case "legacyfabric-api" -> legacyFabricApi; + default -> throw new IllegalArgumentException("Unrecognized version list id: " + id); + }; } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java index edbb735ef..f0c1b62ae 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java @@ -189,7 +189,35 @@ public final class LibraryAnalyzer implements Iterable libraries) { + if (!super.matchLibrary(library, libraries)) { + return false; + } + for (Library l : libraries) { + if ("net.legacyfabric".equals(l.getGroupId())) { + return true; + } + } + return false; + } + }, + LEGACY_FABRIC_API(false, "legacyfabric-api", "net\\.legacyfabric", "legacyfabric-api", null), + FABRIC(true, "fabric", "net\\.fabricmc", "fabric-loader", ModLoaderType.FABRIC) { + @Override + protected boolean matchLibrary(Library library, List libraries) { + if (!super.matchLibrary(library, libraries)) { + return false; + } + for (Library l : libraries) { + if ("net.legacyfabric".equals(l.getGroupId())) { + return false; + } + } + return true; + } + }, FABRIC_API(true, "fabric-api", "net\\.fabricmc", "fabric-api", null), FORGE(true, "forge", "net\\.minecraftforge", "(forge|fmlloader)", ModLoaderType.FORGE) { private final Pattern FORGE_VERSION_MATCHER = Pattern.compile("^([0-9.]+)-(?[0-9.]+)(-([0-9.]+))?$"); @@ -278,6 +306,7 @@ public final class LibraryAnalyzer implements Iterable PATCH_ID_MAP = new HashMap<>(); + static { for (LibraryType type : values()) { PATCH_ID_MAP.put(type.getPatchId(), type); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MojangDownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MojangDownloadProvider.java index df8424c1e..716acbcc3 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MojangDownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/MojangDownloadProvider.java @@ -22,6 +22,8 @@ import org.jackhuang.hmcl.download.fabric.FabricAPIVersionList; import org.jackhuang.hmcl.download.fabric.FabricVersionList; import org.jackhuang.hmcl.download.forge.ForgeVersionList; import org.jackhuang.hmcl.download.game.GameVersionList; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricAPIVersionList; +import org.jackhuang.hmcl.download.legacyfabric.LegacyFabricVersionList; import org.jackhuang.hmcl.download.liteloader.LiteLoaderVersionList; import org.jackhuang.hmcl.download.neoforge.NeoForgeOfficialVersionList; import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList; @@ -47,6 +49,8 @@ public class MojangDownloadProvider implements DownloadProvider { private final OptiFineBMCLVersionList optifine; private final QuiltVersionList quilt; private final QuiltAPIVersionList quiltApi; + private final LegacyFabricVersionList legacyFabric; + private final LegacyFabricAPIVersionList legacyFabricApi; public MojangDownloadProvider() { // If there is no official download channel available, fallback to BMCLAPI. @@ -62,6 +66,8 @@ public class MojangDownloadProvider implements DownloadProvider { this.optifine = new OptiFineBMCLVersionList(apiRoot); this.quilt = new QuiltVersionList(this); this.quiltApi = new QuiltAPIVersionList(this); + this.legacyFabric = new LegacyFabricVersionList(this); + this.legacyFabricApi = new LegacyFabricAPIVersionList(this); } @Override @@ -76,30 +82,21 @@ public class MojangDownloadProvider implements DownloadProvider { @Override public VersionList getVersionListById(String id) { - switch (id) { - case "game": - return game; - case "fabric": - return fabric; - case "fabric-api": - return fabricApi; - case "forge": - return forge; - case "cleanroom": - return cleanroom; - case "neoforge": - return neoforge; - case "liteloader": - return liteLoader; - case "optifine": - return optifine; - case "quilt": - return quilt; - case "quilt-api": - return quiltApi; - default: - throw new IllegalArgumentException("Unrecognized version list id: " + id); - } + return switch (id) { + case "game" -> game; + case "fabric" -> fabric; + case "fabric-api" -> fabricApi; + case "forge" -> forge; + case "cleanroom" -> cleanroom; + case "neoforge" -> neoforge; + case "liteloader" -> liteLoader; + case "optifine" -> optifine; + case "quilt" -> quilt; + case "quilt-api" -> quiltApi; + case "legacyfabric" -> legacyFabric; + case "legacyfabric-api" -> legacyFabricApi; + default -> throw new IllegalArgumentException("Unrecognized version list id: " + id); + }; } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java index 90c5f388a..e74c8bf62 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java @@ -59,7 +59,7 @@ public final class FabricAPIInstallTask extends Task { public void execute() throws IOException { dependencies.add(new FileDownloadTask( remote.getVersion().getFile().getUrl(), - dependencyManager.getGameRepository().getRunDirectory(version.getId()).resolve("mods").resolve("fabric-api-" + remote.getVersion().getVersion() + ".jar"), + dependencyManager.getGameRepository().getModsDirectory(version.getId()).resolve("fabric-api-" + remote.getVersion().getVersion() + ".jar"), remote.getVersion().getFile().getIntegrityCheck()) ); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java index 458d8dd9b..b21586201 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java @@ -28,6 +28,7 @@ import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.gson.JsonSerializable; import org.jackhuang.hmcl.util.gson.JsonUtils; import java.io.IOException; @@ -127,6 +128,7 @@ public final class FabricInstallTask extends Task { return new Version(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), loaderVersion, Version.PRIORITY_LOADER, arguments, mainClass, libraries); } + @JsonSerializable public static class FabricInfo { private final LoaderInfo loader; private final IntermediaryInfo intermediary; @@ -151,6 +153,7 @@ public final class FabricInstallTask extends Task { } } + @JsonSerializable public static class LoaderInfo { private final String separator; private final int build; @@ -187,6 +190,7 @@ public final class FabricInstallTask extends Task { } } + @JsonSerializable public static class IntermediaryInfo { private final String maven; private final String version; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIInstallTask.java new file mode 100644 index 000000000..1a9c2de6a --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIInstallTask.java @@ -0,0 +1,61 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.task.Task; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public final class LegacyFabricAPIInstallTask extends Task { + + private final DefaultDependencyManager dependencyManager; + private final Version version; + private final LegacyFabricAPIRemoteVersion remote; + private final List> dependencies = new ArrayList<>(1); + + public LegacyFabricAPIInstallTask(DefaultDependencyManager dependencyManager, Version version, LegacyFabricAPIRemoteVersion remoteVersion) { + this.dependencyManager = dependencyManager; + this.version = version; + this.remote = remoteVersion; + } + + @Override + public Collection> getDependencies() { + return dependencies; + } + + @Override + public boolean isRelyingOnDependencies() { + return false; + } + + @Override + public void execute() throws IOException { + dependencies.add(new FileDownloadTask( + remote.getVersion().getFile().getUrl(), + dependencyManager.getGameRepository().getModsDirectory(version.getId()).resolve("legacy-fabric-api-" + remote.getVersion().getVersion() + ".jar"), + remote.getVersion().getFile().getIntegrityCheck()) + ); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIRemoteVersion.java new file mode 100644 index 000000000..eb21c07aa --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIRemoteVersion.java @@ -0,0 +1,67 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2022 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.mod.RemoteMod; +import org.jackhuang.hmcl.task.Task; + +import java.time.Instant; +import java.util.List; + +public class LegacyFabricAPIRemoteVersion extends RemoteVersion { + private final String fullVersion; + private final RemoteMod.Version version; + + /** + * Constructor. + * + * @param gameVersion the Minecraft version that this remote version suits. + * @param selfVersion the version string of the remote version. + * @param urls the installer or universal jar original URL. + */ + LegacyFabricAPIRemoteVersion(String gameVersion, String selfVersion, String fullVersion, Instant datePublished, RemoteMod.Version version, List urls) { + super(LibraryAnalyzer.LibraryType.LEGACY_FABRIC_API.getPatchId(), gameVersion, selfVersion, datePublished, urls); + + this.fullVersion = fullVersion; + this.version = version; + } + + @Override + public String getFullVersion() { + return fullVersion; + } + + public RemoteMod.Version getVersion() { + return version; + } + + @Override + public Task getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) { + return new LegacyFabricAPIInstallTask(dependencyManager, baseVersion, this); + } + + @Override + public int compareTo(RemoteVersion o) { + if (!(o instanceof LegacyFabricAPIRemoteVersion)) return 0; + return -this.getReleaseDate().compareTo(o.getReleaseDate()); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIVersionList.java new file mode 100644 index 000000000..da21df24a --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricAPIVersionList.java @@ -0,0 +1,53 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2022 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.VersionList; +import org.jackhuang.hmcl.mod.RemoteMod; +import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.Lang; + +import java.util.Collections; + +public class LegacyFabricAPIVersionList extends VersionList { + + private final DownloadProvider downloadProvider; + + public LegacyFabricAPIVersionList(DownloadProvider downloadProvider) { + this.downloadProvider = downloadProvider; + } + + @Override + public boolean hasType() { + return false; + } + + @Override + public Task refreshAsync() { + return Task.runAsync(() -> { + for (RemoteMod.Version modVersion : Lang.toIterable(ModrinthRemoteModRepository.MODS.getRemoteVersionsById("legacy-fabric-api"))) { + for (String gameVersion : modVersion.getGameVersions()) { + versions.put(gameVersion, new LegacyFabricAPIRemoteVersion(gameVersion, modVersion.getVersion(), modVersion.getName(), modVersion.getDatePublished(), modVersion, + Collections.singletonList(modVersion.getFile().getUrl()))); + } + } + }); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricInstallTask.java new file mode 100644 index 000000000..7ef8cd122 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricInstallTask.java @@ -0,0 +1,130 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2022 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.download.UnsupportedInstallationException; +import org.jackhuang.hmcl.download.fabric.FabricInstallTask; +import org.jackhuang.hmcl.game.Arguments; +import org.jackhuang.hmcl.game.Artifact; +import org.jackhuang.hmcl.game.Library; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.task.GetTask; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.gson.JsonUtils; + +import java.util.*; + +import static org.jackhuang.hmcl.download.UnsupportedInstallationException.FABRIC_NOT_COMPATIBLE_WITH_FORGE; + +public final class LegacyFabricInstallTask extends Task { + + private final DefaultDependencyManager dependencyManager; + private final Version version; + private final LegacyFabricRemoteVersion remote; + private final GetTask launchMetaTask; + private final List> dependencies = new ArrayList<>(1); + + public LegacyFabricInstallTask(DefaultDependencyManager dependencyManager, Version version, LegacyFabricRemoteVersion remoteVersion) { + this.dependencyManager = dependencyManager; + this.version = version; + this.remote = remoteVersion; + + launchMetaTask = new GetTask(dependencyManager.getDownloadProvider().injectURLsWithCandidates(remoteVersion.getUrls())); + launchMetaTask.setCacheRepository(dependencyManager.getCacheRepository()); + } + + @Override + public boolean doPreExecute() { + return true; + } + + @Override + public void preExecute() throws Exception { + if (!Objects.equals("net.minecraft.client.main.Main", version.resolve(dependencyManager.getGameRepository()).getMainClass())) + throw new UnsupportedInstallationException(FABRIC_NOT_COMPATIBLE_WITH_FORGE); + } + + @Override + public Collection> getDependents() { + return Collections.singleton(launchMetaTask); + } + + @Override + public Collection> getDependencies() { + return dependencies; + } + + @Override + public boolean isRelyingOnDependencies() { + return false; + } + + @Override + public void execute() { + setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInstallTask.FabricInfo.class), remote.getGameVersion(), remote.getSelfVersion())); + + dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); + } + + private Version getPatch(FabricInstallTask.FabricInfo legacyFabricInfo, String gameVersion, String loaderVersion) { + JsonObject launcherMeta = legacyFabricInfo.getLauncherMeta(); + Arguments arguments = new Arguments(); + + String mainClass; + if (!launcherMeta.get("mainClass").isJsonObject()) { + mainClass = launcherMeta.get("mainClass").getAsString(); + } else { + mainClass = launcherMeta.get("mainClass").getAsJsonObject().get("client").getAsString(); + } + + if (launcherMeta.has("launchwrapper")) { + String clientTweaker = launcherMeta.get("launchwrapper").getAsJsonObject().get("tweakers").getAsJsonObject().get("client").getAsJsonArray().get(0).getAsString(); + arguments = arguments.addGameArguments("--tweakClass", clientTweaker); + } + + JsonObject librariesObject = launcherMeta.getAsJsonObject("libraries"); + List libraries = new ArrayList<>(); + + // "common, server" is hard coded in fabric installer. + // Don't know the purpose of ignoring client libraries. + for (String side : new String[]{"common", "server"}) { + for (JsonElement element : librariesObject.getAsJsonArray(side)) { + libraries.add(JsonUtils.GSON.fromJson(element, Library.class)); + } + } + + // libraries.add(new Library(Artifact.fromDescriptor(legacyFabricInfo.hashed.maven), getMavenRepositoryByGroup(legacyFabricInfo.hashed.maven), null)); + libraries.add(new Library(Artifact.fromDescriptor(legacyFabricInfo.getIntermediary().getMaven()), getMavenRepositoryByGroup(legacyFabricInfo.getIntermediary().getMaven()), null)); + libraries.add(new Library(Artifact.fromDescriptor(legacyFabricInfo.getLoader().getMaven()), getMavenRepositoryByGroup(legacyFabricInfo.getLoader().getMaven()), null)); + + return new Version(LibraryAnalyzer.LibraryType.LEGACY_FABRIC.getPatchId(), loaderVersion, Version.PRIORITY_LOADER, arguments, mainClass, libraries); + } + + private static String getMavenRepositoryByGroup(String maven) { + Artifact artifact = Artifact.fromDescriptor(maven); + return switch (artifact.getGroup()) { + case "net.fabricmc" -> "https://maven.fabricmc.net/"; + case "net.legacyfabric" -> "https://maven.legacyfabric.net/"; + default -> "https://maven.fabricmc.net/"; + }; + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricRemoteVersion.java new file mode 100644 index 000000000..cd29f0fdd --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricRemoteVersion.java @@ -0,0 +1,44 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2022 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.task.Task; + +import java.util.List; + +public class LegacyFabricRemoteVersion extends RemoteVersion { + /** + * Constructor. + * + * @param gameVersion the Minecraft version that this remote version suits. + * @param selfVersion the version string of the remote version. + * @param urls the installer or universal jar original URL. + */ + LegacyFabricRemoteVersion(String gameVersion, String selfVersion, List urls) { + super(LibraryAnalyzer.LibraryType.LEGACY_FABRIC.getPatchId(), gameVersion, selfVersion, null, urls); + } + + @Override + public Task getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) { + return new LegacyFabricInstallTask(dependencyManager, baseVersion, this); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricVersionList.java new file mode 100644 index 000000000..5533e9e5f --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/legacyfabric/LegacyFabricVersionList.java @@ -0,0 +1,106 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2022 huangyuhui 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 . + */ +package org.jackhuang.hmcl.download.legacyfabric; + +import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.VersionList; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.jackhuang.hmcl.util.gson.JsonUtils.listTypeOf; + +public final class LegacyFabricVersionList extends VersionList { + private final DownloadProvider downloadProvider; + + public LegacyFabricVersionList(DownloadProvider downloadProvider) { + this.downloadProvider = downloadProvider; + } + + @Override + public boolean hasType() { + return false; + } + + @Override + public Task refreshAsync() { + return Task.runAsync(() -> { + List gameVersions = getGameVersions(GAME_META_URL); + List loaderVersions = getGameVersions(LOADER_META_URL); + + lock.writeLock().lock(); + + try { + for (String gameVersion : gameVersions) + for (String loaderVersion : loaderVersions) + versions.put(gameVersion, new LegacyFabricRemoteVersion(gameVersion, loaderVersion, + Collections.singletonList(getLaunchMetaUrl(gameVersion, loaderVersion)))); + } finally { + lock.writeLock().unlock(); + } + }); + } + + private static final String LOADER_META_URL = "https://meta.legacyfabric.net/v2/versions/loader"; + private static final String GAME_META_URL = "https://meta.legacyfabric.net/v2/versions/game"; + + private List getGameVersions(String metaUrl) throws IOException { + String json = NetworkUtils.doGet(downloadProvider.injectURLWithCandidates(metaUrl)); + return JsonUtils.GSON.fromJson(json, listTypeOf(GameVersion.class)) + .stream().map(GameVersion::getVersion).collect(Collectors.toList()); + } + + private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) { + return String.format("https://meta.legacyfabric.net/v2/versions/loader/%s/%s", gameVersion, loaderVersion); + } + + private static class GameVersion { + private final String version; + private final String maven; + private final boolean stable; + + public GameVersion() { + this("", null, false); + } + + public GameVersion(String version, String maven, boolean stable) { + this.version = version; + this.maven = maven; + this.stable = stable; + } + + public String getVersion() { + return version; + } + + @Nullable + public String getMaven() { + return maven; + } + + public boolean isStable() { + return stable; + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java index b0d9eb2bf..5f06cccba 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java @@ -59,7 +59,7 @@ public final class QuiltAPIInstallTask extends Task { public void execute() throws IOException { dependencies.add(new FileDownloadTask( remote.getVersion().getFile().getUrl(), - dependencyManager.getGameRepository().getRunDirectory(version.getId()).resolve("mods").resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar"), + dependencyManager.getGameRepository().getModsDirectory(version.getId()).resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar"), remote.getVersion().getFile().getIntegrityCheck()) ); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java index c0bd51290..01642cecf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java @@ -28,6 +28,7 @@ import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.gson.JsonSerializable; import org.jackhuang.hmcl.util.gson.JsonUtils; import java.util.*; @@ -135,6 +136,7 @@ public final class QuiltInstallTask extends Task { } } + @JsonSerializable public static class QuiltInfo { private final LoaderInfo loader; private final IntermediaryInfo hashed; @@ -165,6 +167,7 @@ public final class QuiltInstallTask extends Task { } } + @JsonSerializable public static class LoaderInfo { private final String separator; private final int build; @@ -201,6 +204,7 @@ public final class QuiltInstallTask extends Task { } } + @JsonSerializable public static class IntermediaryInfo { private final String maven; private final String version; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 777be6b75..63b13f16c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -600,6 +600,9 @@ public class DefaultLauncher extends Launcher { if (analyzer.has(LibraryAnalyzer.LibraryType.QUILT)) { env.put("INST_QUILT", "1"); } + if (analyzer.has(LibraryAnalyzer.LibraryType.LEGACY_FABRIC)) { + env.put("INST_LEGACYFABRIC", "1"); + } env.putAll(options.getEnvironmentVariables()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModLoaderType.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModLoaderType.java index f4b8feacd..c1205803a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModLoaderType.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/ModLoaderType.java @@ -25,5 +25,6 @@ public enum ModLoaderType { FABRIC, QUILT, LITE_LOADER, - PACK; + LEGACY_FABRIC, + PACK } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java index 2429b1073..338695178 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackExportTask.java @@ -109,6 +109,8 @@ public class McbbsModpackExportTask extends Task { addons.add(new McbbsModpackManifest.Addon(FABRIC.getPatchId(), fabricVersion))); analyzer.getVersion(QUILT).ifPresent(quiltVersion -> addons.add(new McbbsModpackManifest.Addon(QUILT.getPatchId(), quiltVersion))); + analyzer.getVersion(LEGACY_FABRIC).ifPresent(legacyfabricVersion -> + addons.add(new McbbsModpackManifest.Addon(LEGACY_FABRIC.getPatchId(), legacyfabricVersion))); List libraries = new ArrayList<>(); // TODO libraries