Commit ab9788d6 authored by aleksana's avatar aleksana
Browse files

hmcl: add patch jar to fix terracotta

parent 5f0c96fb
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
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
+27 −0
Original line number Diff line number Diff line
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
Original line number Diff line number Diff line
@@ -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 doesn’t work on NixOS.
  # - Building from source isn’t feasible because HMCL’s code relies on
  #   Microsoft OAuth, CurseForge, and other API keys that upstream doesn’t
  #   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 jar’s 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 −0
Original line number Diff line number Diff line
@@ -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
  '';
}