summaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/hm/hmcl/package.nix
blob: dff64f097b785dc6c959787fdfca9382554b1549 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
{
  lib,
  stdenv,
  fetchurl,
  replaceVars,
  terracotta,
  makeDesktopItem,
  makeWrapper,
  wrapGAppsHook3,
  copyDesktopItems,
  desktopToDarwinBundle,
  jdk,
  jdk25,
  hmclJdk ? jdk.override {
    # Required by jar file
    enableJavaFX = true;
  },
  buildPackages,
  hmclJdkBuild ? buildPackages.jdk.override {
    enableJavaFX = true;
  },
  minecraftJdks ? [
    hmclJdk
    jdk25
  ],
  libxxf86vm,
  libxtst,
  libxrandr,
  libxext,
  libxcursor,
  libxkbcommon,
  libx11,
  xrandr,
  glib,
  libGL,
  glfw3,
  glfw3-minecraft,
  openal,
  libglvnd,
  alsa-lib,
  wayland,
  vulkan-loader,
  libpulseaudio,
  gobject-introspection,
  callPackage,
  gtk3,
}:
let
  glfw3' = if stdenv.hostPlatform.isLinux then glfw3-minecraft else glfw3;
in
stdenv.mkDerivation (finalAttrs: {
  pname = "hmcl";
  version = "3.16.3";

  src = fetchurl {
    # HMCL has built-in keys, such as the Microsoft OAuth secret and the CurseForge API key.
    # See https://github.com/HMCL-dev/HMCL/blob/refs/tags/release-3.6.12/.github/workflows/gradle.yml#L26-L28
    url = "https://github.com/HMCL-dev/HMCL/releases/download/v${finalAttrs.version}/HMCL-${finalAttrs.version}.jar";
    hash = "sha256-XQL00E2UQhFjVOz8z2eZEMyjcdAKI81daxZVjCCnPdM=";
  };

  # - 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.
  terracottaBundleJava = fetchurl {
    name = "hmcl-terracotta-bundle-java-${finalAttrs.version}";
    url = "https://raw.githubusercontent.com/HMCL-dev/HMCL/v${finalAttrs.version}/${finalAttrs.terracottaBundleJavaPath}";
    hash = "sha256-dZHRim/7VNW0/nA6I8r3t5zGfzIMxG2lzdZ//dzv2Gs=";
  };
  macOSProviderJava = fetchurl {
    name = "hmcl-macos-provider-java-${finalAttrs.version}";
    url = "https://raw.githubusercontent.com/HMCL-dev/HMCL/v${finalAttrs.version}/${finalAttrs.macOSProviderJavaPath}";
    hash = "sha256-7vI2U8vx3GYwlshoHJF/J8n2RS6TZ/cvoAivqYtW23Q=";
  };
  terracottaBundleJavaPath = "HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaBundle.java";
  macOSProviderJavaPath = "HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java";

  dontUnpack = true;

  prePatch = ''
    install -Dm644 $terracottaBundleJava $terracottaBundleJavaPath
    install -Dm644 $macOSProviderJava $macOSProviderJavaPath
  '';

  patches = [
    (replaceVars ./0001-nix-use-terracotta-from-nix.patch {
      TERRACOTTA_BIN = lib.getExe terracotta;
    })
    ./0002-nix-skip-terracotta-existence-check-on-darwin.patch
  ];

  buildPhase = ''
    runHook preBuild

    # Build only classes we modified
    javac -cp $src -d out $terracottaBundleJavaPath $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 = [
    (makeDesktopItem {
      name = "HMCL";
      exec = "hmcl";
      icon = "hmcl";
      comment = finalAttrs.meta.description;
      desktopName = "HMCL";
      categories = [ "Game" ];
    })
  ];

  nativeBuildInputs = [
    gobject-introspection
    makeWrapper
    wrapGAppsHook3
    copyDesktopItems
    hmclJdkBuild
  ]
  ++ lib.optionals stdenv.hostPlatform.isDarwin [
    desktopToDarwinBundle
  ];

  runtimeDeps = [
    libGL
    glfw3'
    glib
    openal
    libglvnd
    vulkan-loader
  ]
  ++ lib.optionals stdenv.hostPlatform.isLinux [
    libx11
    libxxf86vm
    libxext
    libxcursor
    libxkbcommon
    libxrandr
    libxtst
    libpulseaudio
    wayland
    alsa-lib
    gtk3
  ];

  installPhase = ''
    runHook preInstall

    install -Dm444 $src $out/lib/hmcl/hmcl.jar
    install -Dm444 patch.jar $out/lib/hmcl/hmcl-terracotta-patch.jar

    jar xf $src assets/img
  ''
  + lib.optionalString stdenv.hostPlatform.isLinux ''
    install -Dm444 assets/img/icon-title.png $out/share/icons/hicolor/24x24/apps/hmcl.png
    install -Dm444 assets/img/icon.png $out/share/icons/hicolor/32x32/apps/hmcl.png
    install -Dm444 assets/img/icon-title@2x.png $out/share/icons/hicolor/48x48/apps/hmcl.png
    install -Dm444 assets/img/icon@2x.png $out/share/icons/hicolor/64x64/apps/hmcl.png
    install -Dm444 assets/img/icon@4x.png $out/share/icons/hicolor/128x128/apps/hmcl.png
    install -Dm444 assets/img/icon@8x.png $out/share/icons/hicolor/256x256/apps/hmcl.png
  ''
  + lib.optionalString stdenv.hostPlatform.isDarwin ''
    install -Dm444 assets/img/icon-mac.png $out/share/icons/hicolor/512x512/apps/hmcl.png
  ''
  + ''
    runHook postInstall
  '';

  postFixup = ''
    makeShellWrapper ${hmclJdk}/bin/java $out/bin/hmcl \
      --add-flags "-jar $out/lib/hmcl/hmcl-terracotta-patch.jar" \
      --add-flags "-Djdk.gtk.version=3" \
      --set LD_LIBRARY_PATH ${lib.makeLibraryPath finalAttrs.runtimeDeps} \
      --prefix PATH : "${
        lib.makeBinPath (minecraftJdks ++ lib.optional stdenv.hostPlatform.isLinux xrandr)
      }" \
      --run 'cd $HOME' \
      ''${gappsWrapperArgs[@]}
  '';

  passthru.updateScript = lib.getExe (callPackage ./update.nix { });

  meta = {
    homepage = "https://hmcl.huangyuhui.net";
    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; [
      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.

      Starting with Minecraft 26.1, Wayland support can be enabled
      by adding the JDK arguments -DMC_DEBUG_ENABLED and
      -DMC_DEBUG_PREFER_WAYLAND. If needed, configure them in
      HMCL -> Advanced Settings -> JVM Options -> JVM Arguments.

      Users who are still on an older version and want to use Wayland should
      enable HMCL -> Advanced Settings -> Workaround -> Use System GLFW.
      Otherwise, keep it disabled.
    '';
    maintainers = with lib.maintainers; [
      daru-san
      Misaka13514
      moraxyc
    ];
    inherit (hmclJdk.meta) platforms;
  };
})