hmcl: add patch jar to fix terracotta

This commit is contained in:
aleksana
2025-11-26 23:45:14 +08:00
parent 5f0c96fbe5
commit ab9788d65b
4 changed files with 146 additions and 13 deletions
@@ -0,0 +1,43 @@
From 541d055bf55703aa9e2c5a5e04a397f1d25efe28 Mon Sep 17 00:00:00 2001
From: Moraxyc <i@qaq.li>
Date: Wed, 29 Oct 2025 00:09:56 +0800
Subject: [PATCH 2/3] nix: use terracotta from nix
---
.../org/jackhuang/hmcl/terracotta/TerracottaNative.java | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaNative.java b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaNative.java
index 079537978..68954b09e 100644
--- a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaNative.java
+++ b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaNative.java
@@ -47,7 +47,7 @@ public final class TerracottaNative {
public TerracottaNative(List<URI> links, Path path, FileDownloadTask.IntegrityCheck checking) {
this.links = links;
- this.path = path;
+ this.path = Path.of("@TERRACOTTA_BIN@");
this.checking = checking;
}
@@ -130,9 +130,7 @@ public final class TerracottaNative {
public ITerracottaProvider.Status status() throws IOException {
if (Files.exists(path)) {
- if (DigestUtils.digestToString(checking.getAlgorithm(), path).equalsIgnoreCase(checking.getChecksum())) {
- return ITerracottaProvider.Status.READY;
- }
+ return ITerracottaProvider.Status.READY;
}
try {
@@ -144,4 +142,4 @@ public final class TerracottaNative {
}
return ITerracottaProvider.Status.NOT_EXIST;
}
-}
+}
\ No newline at end of file
--
2.51.0
@@ -0,0 +1,27 @@
From bcf95a23380424f2ca82649d93e9e0bdf8274b74 Mon Sep 17 00:00:00 2001
From: Moraxyc <i@qaq.li>
Date: Fri, 31 Oct 2025 14:23:54 +0800
Subject: [PATCH 3/3] nix: skip terracotta existence check on darwin
---
.../org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java | 4 ----
1 file changed, 4 deletions(-)
diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java
index 00626f8b6..59125962d 100644
--- a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java
+++ b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java
@@ -45,10 +45,6 @@ public final class MacOSProvider implements ITerracottaProvider {
public Status status() throws IOException {
assert binary != null;
- if (!Files.exists(Path.of("/Applications/terracotta.app"))) {
- return Status.NOT_EXIST;
- }
-
return binary.status();
}
--
2.51.0
+74 -13
View File
@@ -2,18 +2,25 @@
lib,
stdenv,
fetchurl,
replaceVars,
terracotta,
makeDesktopItem,
wrapGAppsHook3,
copyDesktopItems,
imagemagick,
jdk,
jdk17,
jdk21,
hmclJdk ? jdk,
hmclJdk ? jdk.override {
# Required by jar file
enableJavaFX = true;
},
buildPackages,
hmclJdkBuild ? buildPackages.jdk.override {
enableJavaFX = true;
},
minecraftJdks ? [
jdk
hmclJdk
jdk17
jdk21
],
xorg,
glib,
@@ -45,8 +52,63 @@ stdenv.mkDerivation (finalAttrs: {
hash = "sha256-1OVq4ujA2ZHboB7zEk7004kYgl9YcoM4qLq154MZMGo=";
};
# - HMCL prompts users to download prebuilt Terracotta binary for
# multi-user functionality, which is messy and doesnt work on NixOS.
# - Building from source isnt feasible because HMCLs code relies on
# Microsoft OAuth, CurseForge, and other API keys that upstream doesnt
# allow in custom builds, causing features to break.
# - Our workaround is to compile only the Java files that handle
# Terracotta downloads, package them into a patch jar that overrides
# the original classes, and have it load the original jar. This preserves
# the original jars integrity check and avoids modifying the upstream jar.
terracottaNativeJava = fetchurl {
name = "hmcl-terracotta-native-java-${finalAttrs.version}";
url = "https://raw.githubusercontent.com/HMCL-dev/HMCL/v${finalAttrs.version}/${finalAttrs.terracottaNativeJavaPath}";
hash = "sha256-sg8gBOMNdITmHeYByYriYp05ja1vtWPF/wuqdGmkgiA=";
};
macOSProviderJava = fetchurl {
name = "hmcl-macos-provider-java-${finalAttrs.version}";
url = "https://raw.githubusercontent.com/HMCL-dev/HMCL/v${finalAttrs.version}/${finalAttrs.macOSProviderJavaPath}";
hash = "sha256-V8FNPPkq6/P3/HKcqKkAy6Ya1kUI3oEMfjEc8XdExgo=";
};
terracottaNativeJavaPath = "HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaNative.java";
macOSProviderJavaPath = "HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java";
dontUnpack = true;
prePatch = ''
install -Dm644 $terracottaNativeJava $terracottaNativeJavaPath
install -Dm644 $macOSProviderJava $macOSProviderJavaPath
'';
patches = [
(replaceVars ./0002-nix-use-terracotta-from-nix.patch {
TERRACOTTA_BIN = lib.getExe terracotta;
})
./0003-nix-skip-terracotta-existence-check-on-darwin.patch
];
buildPhase = ''
runHook preBuild
# Build only classes we modified
javac -cp $src -d out $terracottaNativeJavaPath $macOSProviderJavaPath
# Extract MANIFEST.MF from original jar
# We need Main-Class, Add-Opens, etc
jar xf $src META-INF/MANIFEST.MF
# Remove last empty line; otherwise file is invalid
sed -i '/^[[:space:]]*$/d' META-INF/MANIFEST.MF
# Let our patch jar be the entrace and load hmcl.jar
echo "Class-Path: $out/lib/hmcl/hmcl.jar" >> META-INF/MANIFEST.MF
# Package our patch jar
# Reserve link to terracotta by not applying zip; nix cannot detect path from zipped jar
jar cvf0m patch.jar META-INF/MANIFEST.MF -C out .
runHook postBuild
'';
dontWrapGApps = true;
desktopItems = [
@@ -65,6 +127,7 @@ stdenv.mkDerivation (finalAttrs: {
wrapGAppsHook3
copyDesktopItems
imagemagick
hmclJdkBuild
];
installPhase = ''
@@ -72,6 +135,7 @@ stdenv.mkDerivation (finalAttrs: {
mkdir -p $out/{bin,lib/hmcl}
cp $src $out/lib/hmcl/hmcl.jar
cp patch.jar $out/lib/hmcl/hmcl-terracotta-patch.jar
for n in 16 32 48 64 96 128 256
do
@@ -106,15 +170,12 @@ stdenv.mkDerivation (finalAttrs: {
alsa-lib
]
);
hmclJdk' = hmclJdk.override {
enableJavaFX = true; # Necessary for hardware acceleration.
};
in
''
runHook preFixup
makeBinaryWrapper ${hmclJdk'}/bin/java $out/bin/hmcl \
--add-flags "-jar $out/lib/hmcl/hmcl.jar" \
makeBinaryWrapper ${hmclJdk}/bin/java $out/bin/hmcl \
--add-flags "-jar $out/lib/hmcl/hmcl-terracotta-patch.jar" \
--set LD_LIBRARY_PATH ${libpath} \
--prefix PATH : "${lib.makeBinPath minecraftJdks}"\
''${gappsWrapperArgs[@]}
@@ -129,15 +190,15 @@ stdenv.mkDerivation (finalAttrs: {
description = "Minecraft Launcher which is multi-functional, cross-platform and popular";
changelog = "https://docs.hmcl.net/changelog/stable.html";
mainProgram = "hmcl";
sourceProvenance = with lib.sourceTypes; [ binaryBytecode ];
sourceProvenance = with lib.sourceTypes; [
fromSource # Our patch jar is built from source
binaryBytecode
];
license = lib.licenses.gpl3Only;
longDescription = ''
Hello Minecraft! Launcher (HMCL) is a free, open-source, and cross-platform Minecraft launcher.
It provides comprehensive support for managing multiple game versions and mod loaders,
including Forge, NeoForge, Fabric, Quilt, LiteLoader, and OptiFine.
Note: HMCL manages the Terracotta binary internally. On NixOS, Terracotta-related features
require `programs.nix-ld` to be enabled, as the runtime-downloaded binary is not patched.
'';
maintainers = with lib.maintainers; [
daru-san
+2
View File
@@ -36,5 +36,7 @@ writeShellApplication {
nix-update hmcl --version="$version"
update-source-version hmcl --source-key=icon --ignore-same-version
update-source-version hmcl --source-key=terracottaNativeJava --ignore-same-version
update-source-version hmcl --source-key=macOSProviderJava --ignore-same-version
'';
}