Skip to content

Commit

Permalink
Support Neoforge (#2548)
Browse files Browse the repository at this point in the history
* Support #2376

* Add necessary @nullable annotations

* Display different types of dependencies in different sections.

* Fix checkstyle

* Add I18N for different types of dependencies.

* Enhance UI

* Code cleanup

* Enhance UI

* Manually sort the result from curseforge when searching mods by name.

* Render the search results from remote mod repositories in several pages.

* Fix merge

* Fix

* Add a button which navigates to the modpack download page in the modpack installl page

* Fix I18N

* Render the mod loaders supported by the version in mod info page.

* Fix #2104

* Enhance TwoLineListItem

* Render the mod loader supported by this mod file on the ModListPage

* Fix chinese searching and curseforge searching

* Update I18N

* Fix

* Fix

* Select the specific game version when clicking the 'download' button on ModListPage

* Support HMCL to update mod_data and mod_pack data from https://github.com/huanghongxun/HMCL/raw/javafx/data-json/dynamic-remote-resources.json

* Enhance :HMCL:build.gradle.kts

* Revert parse_mcmod_data.py

* Abstract 'new Image' to FXUtils.newBuiltinImage and FXUtils.newRemoteImage

FXUtils.newBuiltinImage is used to load image which is supposed to be correct definitely and is a file within the jar. Or, it will throw ResourceNotFoundError.

FXUtils.newRemoteImage is used to load image from the internet. It will cache the data of images for the further usage. The cached data will be deleted when HMCL is closed or hidden.

* Add javadoc for FXUtils.newBuiltinImage and FXUtils.newRemoteImage.

* Fix checkstyle

* Fix

* Fix

* Fix

* Add license for RemoteResourceManager

* Remove TODO

* Enhance Chinese searching

* Support to decode metadata for local quilt mod.

* Enhance ModManager

* Fix checkstyle

* Refactor

* Fix

* Fix

* Refactor DownloadPage

* Fix

* Revert "Refactor DownloadPage"

This reverts commit 953558d.

* Refactor DownloadPage

* Refactor

* Fix

* Fix checkstyle

* Set org.jackhuang.hmcl.ui.construct.TwoLineListItem.TagChangeListener as a private static inner class.

* Fix

* Fix

* Fix

* Enhance SimpleMultimap

* Revert TwoLineListItem

* Fix

* Code cleanup

* Code cleanup

* Fix

* Code cleanup

* Add license for IModMetadataReader

* Add prefix 'Minecraft' at the supported minecrft version list in DownloadPage

* Fix #2498

* Update README_cn.md

* Opti ModMananger

* Log a warning message when 'hmcl.update_source.override' is used.

* Fix chinese searching

* Enhance chinese searching.

* Enhance memory usage

* Add basic support for NeoForge.

* Enable HMCl to show the version list of NeoForged.

* Fix checkstyle

* Enable HMCL to download and install NeoForged from BMCL. Fix some bugs.

* Close the mod version dialog window after clicking the downloading / save as button if the dependency list is empty.

* Fix

* Enable HMCL to install NeoForge from modpacks.

* Fix the dirty implememtation

* Fix UI

* Cache builtin images.

* Enhance FXUtils (Make tooltip installer faster).

* Fix

* Fix

* Fix #2560

* Fix typo

* Fix remote image cache.

* Fix javadoc

* Fix checkstyle

* Optimize FXUtils::shutdown

* Support NeoForged 1.20.2

* Fix merge

* I have no idea on why the sha1 was matched.

* Revert "Enhance FXUtils (Make tooltip installer faster)."

This reverts commit 0a49eb2.

* Support multi download source in order balance the traffic of hmcl.huangyuhui.net and the download speed in China Mainland.

* Modify dynamic remote resource urls.

* Optimize codes with StringUtils.DynamicCommonSubsequence.

* Prevent unofficial HMCL to access HMCL Resource Update URL.

* Zip the dynamic-remote-resources json by Gradle automatically.

* Remove unnecessary getters.

* Fix

* Fix LibraryAnalyzer: Cannot analyze the version number of NeoForge correctly.

* Support to choose the NeoForge icon if a game is installed with NeoForge.

* Fix checkstyle

* Fix: The version number on DownloadPage of NeoForge is incorrect, which has leading string 'neoforge-'.

* Fix.

* Rename references. Fix: Invalid spaces in VersionIconType.

---------

Co-authored-by: Burning_TNT <[email protected]“>
  • Loading branch information
burningtnt and Burning_TNT authored Jan 8, 2024
1 parent e6e4e36 commit 4149876
Show file tree
Hide file tree
Showing 31 changed files with 881 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ else if (LibraryAnalyzer.isModded(this, version)) {
return newBuiltinImage("/assets/img/fabric.png");
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE))
return newBuiltinImage("/assets/img/forge.png");
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE))
return newBuiltinImage("/assets/img/neoforge.png");
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT))
return newBuiltinImage("/assets/img/quilt.png");
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,7 @@ private static Task<JavaVersion> checkGameState(Profile profile, VersionSetting
break;
case MODDED_JAVA_16:
// Minecraft<=1.17.1+Forge[37.0.0,37.0.60) not compatible with Java 17
String forgePatchVersion = analyzer.getVersion(LibraryAnalyzer.LibraryType.FORGE)
.map(LibraryAnalyzer.LibraryType.FORGE::patchVersion)
.orElse(null);
String forgePatchVersion = analyzer.getVersion(LibraryAnalyzer.LibraryType.FORGE).orElse(null);
if (forgePatchVersion != null && VersionNumber.VERSION_COMPARATOR.compare(forgePatchVersion, "37.0.60") < 0)
suggestions.add(i18n("launch.advice.forge37_0_60"));
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum VersionIconType {
CRAFT_TABLE("/assets/img/craft_table.png"),
FABRIC("/assets/img/fabric.png"),
FORGE("/assets/img/forge.png"),
NEO_FORGE("/assets/img/neoforge.png"),
FURNACE("/assets/img/furnace.png"),
QUILT("/assets/img/quilt.png");

Expand Down
28 changes: 22 additions & 6 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public InstallerItem(String id) {
case "quilt-api":
imageUrl = "/assets/img/quilt.png";
break;
case "neoforge":
imageUrl = "/assets/img/neoforge.png";
break;
default:
imageUrl = null;
break;
Expand Down Expand Up @@ -122,6 +125,7 @@ public static class InstallerItemGroup {
public final InstallerItem fabric = new InstallerItem(FABRIC);
public final InstallerItem fabricApi = new InstallerItem(FABRIC_API);
public final InstallerItem forge = new InstallerItem(FORGE);
public final InstallerItem neoForge = new InstallerItem(NEO_FORGE);
public final InstallerItem liteLoader = new InstallerItem(LITELOADER);
public final InstallerItem optiFine = new InstallerItem(OPTIFINE);
public final InstallerItem quilt = new InstallerItem(QUILT);
Expand All @@ -131,30 +135,41 @@ public InstallerItemGroup() {
forge.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
if (quilt.libraryVersion.get() != null) return QUILT.getPatchId();
if (neoForge.libraryVersion.get() != null) return NEO_FORGE.getPatchId();
return null;
}, fabric.libraryVersion, quilt.libraryVersion, neoForge.libraryVersion));

neoForge.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
if (quilt.libraryVersion.get() != null) return QUILT.getPatchId();
if (forge.libraryVersion.get() != null) return FORGE.getPatchId();
return null;
}, fabric.libraryVersion, quilt.libraryVersion));
}, fabric.libraryVersion, quilt.libraryVersion, forge.libraryVersion));

liteLoader.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
if (quilt.libraryVersion.get() != null) return QUILT.getPatchId();
if (neoForge.libraryVersion.get() != null) return NEO_FORGE.getPatchId();
return null;
}, fabric.libraryVersion, quilt.libraryVersion));
}, fabric.libraryVersion, quilt.libraryVersion, neoForge.libraryVersion));

optiFine.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
if (quilt.libraryVersion.get() != null) return QUILT.getPatchId();
if (neoForge.libraryVersion.get() != null) return NEO_FORGE.getPatchId();
return null;
}, fabric.libraryVersion, quilt.libraryVersion));
}, fabric.libraryVersion, quilt.libraryVersion, neoForge.libraryVersion));

for (InstallerItem fabric : new InstallerItem[]{fabric, fabricApi}) {
fabric.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
if (forge.libraryVersion.get() != null) return FORGE.getPatchId();
if (neoForge.libraryVersion.get() != null) return NEO_FORGE.getPatchId();
if (liteLoader.libraryVersion.get() != null) return LITELOADER.getPatchId();
if (optiFine.libraryVersion.get() != null) return OPTIFINE.getPatchId();
if (quilt.libraryVersion.get() != null) return QUILT.getPatchId();
if (quiltApi.libraryVersion.get() != null) return QUILT_API.getPatchId();
return null;
}, forge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion, quilt.libraryVersion, quiltApi.libraryVersion));
}, forge.libraryVersion, neoForge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion, quilt.libraryVersion, quiltApi.libraryVersion));
}

fabricApi.dependencyName.bind(Bindings.createStringBinding(() -> {
Expand All @@ -167,10 +182,11 @@ public InstallerItemGroup() {
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
if (fabricApi.libraryVersion.get() != null) return FABRIC_API.getPatchId();
if (forge.libraryVersion.get() != null) return FORGE.getPatchId();
if (neoForge.libraryVersion.get() != null) return NEO_FORGE.getPatchId();
if (liteLoader.libraryVersion.get() != null) return LITELOADER.getPatchId();
if (optiFine.libraryVersion.get() != null) return OPTIFINE.getPatchId();
return null;
}, fabric.libraryVersion, fabricApi.libraryVersion, forge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion));
}, fabric.libraryVersion, fabricApi.libraryVersion, forge.libraryVersion, neoForge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion));
}

quiltApi.dependencyName.bind(Bindings.createStringBinding(() -> {
Expand All @@ -180,7 +196,7 @@ public InstallerItemGroup() {
}

public InstallerItem[] getLibraries() {
return new InstallerItem[]{game, forge, liteLoader, optiFine, fabric, fabricApi, quilt, quiltApi};
return new InstallerItem[]{game, forge, neoForge, liteLoader, optiFine, fabric, fabricApi, quilt, quiltApi};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.jackhuang.hmcl.download.game.GameInstallTask;
import org.jackhuang.hmcl.download.java.JavaDownloadTask;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
import org.jackhuang.hmcl.download.neoforge.NeoForgeInstallTask;
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
import org.jackhuang.hmcl.download.quilt.QuiltAPIInstallTask;
import org.jackhuang.hmcl.download.quilt.QuiltInstallTask;
Expand Down Expand Up @@ -123,6 +124,8 @@ public void onRunning(Task<?> task) {
task.setName(i18n("install.installer.install", i18n("install.installer.game")));
} else if (task instanceof ForgeNewInstallTask || task instanceof ForgeOldInstallTask) {
task.setName(i18n("install.installer.install", i18n("install.installer.forge")));
} else if (task instanceof NeoForgeInstallTask) {
task.setName(i18n("install.installer.install", i18n("install.installer.neoforge")));
} else if (task instanceof LiteLoaderInstallTask) {
task.setName(i18n("install.installer.install", i18n("install.installer.liteloader")));
} else if (task instanceof OptiFineInstallTask) {
Expand Down Expand Up @@ -248,6 +251,7 @@ public StageNode(String stage) {
case "hmcl.install.assets": message = i18n("assets.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.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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.ui.Controllers;
Expand Down Expand Up @@ -72,9 +70,9 @@ public InstallersPage(WizardController controller, HMCLGameRepository repository

for (InstallerItem library : group.getLibraries()) {
String libraryId = library.getLibraryId();
if (libraryId.equals("game")) continue;
if (libraryId.equals(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId())) continue;
library.action.set(e -> {
if ("fabric-api".equals(libraryId)) {
if (LibraryAnalyzer.LibraryType.FABRIC_API.getPatchId().equals(libraryId)) {
Controllers.dialog(i18n("install.installer.fabric-api.warning"), i18n("message.warning"), MessageDialogPane.MessageType.WARNING);
}

Expand Down Expand Up @@ -155,10 +153,13 @@ protected InstallersPageSkin(InstallersPage control) {

{
FlowPane libraryPane = new FlowPane(control.group.getLibraries());
BorderPane.setMargin(libraryPane, new Insets(16, 0, 16, 0));
libraryPane.setVgap(16);
libraryPane.setHgap(16);
root.setCenter(libraryPane);
ScrollPane scrollPane = new ScrollPane(libraryPane);
scrollPane.setFitToWidth(true);
scrollPane.setFitToHeight(true);
BorderPane.setMargin(scrollPane, new Insets(16, 0, 16, 0));
root.setCenter(scrollPane);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion;
import org.jackhuang.hmcl.download.game.GameRemoteVersion;
import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion;
import org.jackhuang.hmcl.download.neoforge.NeoForgeRemoteVersion;
import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltAPIRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
Expand Down Expand Up @@ -335,6 +336,8 @@ else if (remoteVersion instanceof OptiFineRemoteVersion)
iconType = VersionIconType.COMMAND;
else if (remoteVersion instanceof ForgeRemoteVersion)
iconType = VersionIconType.FORGE;
else if (remoteVersion instanceof NeoForgeRemoteVersion)
iconType = VersionIconType.NEO_FORGE;
else if (remoteVersion instanceof FabricRemoteVersion || remoteVersion instanceof FabricAPIRemoteVersion)
iconType = VersionIconType.FABRIC;
else if (remoteVersion instanceof QuiltRemoteVersion || remoteVersion instanceof QuiltAPIRemoteVersion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ private static final class ModItem extends StackPane {
case FORGE:
content.getTags().add(i18n("install.installer.forge"));
break;
case NEO_FORGED:
content.getTags().add(i18n("install.installer.neoforge"));
break;
case FABRIC:
content.getTags().add(i18n("install.installer.fabric"));
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void loadVersion(Profile profile, String versionId) {

InstallerItem.InstallerItemGroup group = new InstallerItem.InstallerItemGroup();

// Conventional libraries: game, fabric, forge, liteloader, optifine
// Conventional libraries: game, fabric, forge, neoforge, liteloader, optifine
for (InstallerItem installerItem : group.getLibraries()) {
String libraryId = installerItem.getLibraryId();
String libraryVersion = analyzer.getVersion(libraryId).orElse(null);
Expand All @@ -96,7 +96,7 @@ public void loadVersion(Profile profile, String versionId) {
installerItem.action.set(e -> {
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
});
boolean removable = !"game".equals(libraryId) && libraryVersion != null;
boolean removable = !LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(libraryId) && libraryVersion != null;
installerItem.removable.set(removable);
if (removable) {
Runnable action = removeAction.apply(libraryId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,28 @@ class ModInfoDialog extends JFXDialogLayout {
RemoteMod remoteMod = remoteModRepository.getModById(versionOptional.get().getModid());
FXUtils.runInFX(() -> {
for (ModLoaderType modLoaderType : versionOptional.get().getLoaders()) {
String loaderName;
switch (modLoaderType) {
case FABRIC:
case FORGE:
loaderName = i18n("install.installer.forge");
break;
case NEO_FORGED:
loaderName = i18n("install.installer.neoforge");
break;
case FABRIC:
loaderName = i18n("install.installer.fabric");
break;
case LITE_LOADER:
case QUILT: {
if (!title.getTags().contains(modLoaderType.getLoaderName())) {
title.getTags().add(modLoaderType.getLoaderName());
}
}
loaderName = i18n("install.installer.liteloader");
break;
case QUILT:
loaderName = i18n("install.installer.quilt");
break;
default:
continue;
}
if (!title.getTags().contains(loaderName)) {
title.getTags().add(loaderName);
}
}

Expand Down Expand Up @@ -457,7 +470,23 @@ protected void updateControl(ModInfoObject dataItem, boolean empty) {
if (empty) return;
content.setTitle(dataItem.getTitle());
content.getTags().clear();
content.getTags().add(dataItem.getModInfo().getModLoaderType().getLoaderName());
switch (dataItem.getModInfo().getModLoaderType()) {
case FORGE:
content.getTags().add(i18n("install.installer.forge"));
break;
case NEO_FORGED:
content.getTags().add(i18n("install.installer.neoforge"));
break;
case FABRIC:
content.getTags().add(i18n("install.installer.fabric"));
break;
case LITE_LOADER:
content.getTags().add(i18n("install.installer.liteloader"));
break;
case QUILT:
content.getTags().add(i18n("install.installer.quilt"));
break;
}
if (dataItem.getMod() != null) {
if (I18n.getCurrentLocale().getLocale() == Locale.CHINA) {
content.getTags().add(dataItem.getMod().getDisplayName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public VersionIconDialog(Profile profile, String versionId, Runnable onFinish) {
createIcon(VersionIconType.CRAFT_TABLE),
createIcon(VersionIconType.FABRIC),
createIcon(VersionIconType.FORGE),
createIcon(VersionIconType.NEO_FORGE),
createIcon(VersionIconType.FURNACE),
createIcon(VersionIconType.QUILT)
);
Expand Down
Binary file added HMCL/src/main/resources/assets/img/neoforge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N.properties
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ install.installer.fabric=Fabric
install.installer.fabric-api=Fabric API
install.installer.fabric-api.warning=Warning: Fabric API 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 Fabric API will not work. If you do want to change these settings, you should reinstall it.
install.installer.forge=Forge
install.installer.neoforge=NeoForge
install.installer.game=Minecraft
install.installer.incompatible=Incompatible with %s
install.installer.install=Install %s
Expand Down Expand Up @@ -838,6 +839,7 @@ modrinth.category.misc=Misc
modrinth.category.mobs=Mobs
modrinth.category.modloader=Modloader
modrinth.category.multiplayer=Multiplayer
modrinth.category.neoforge=NeoForge
modrinth.category.optimization=Optimization
modrinth.category.paper=Paper
modrinth.category.purpur=Purpur
Expand Down
Loading

0 comments on commit 4149876

Please sign in to comment.