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;
};
})
|