Compare commits

...
Author SHA1 Message Date
liuhao 040dceb9ed fix: report per-file progress while downloading Mojang Java
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Publish TDLM launcher / publish (push) Skipped
Publish TDLM launcher / noop (push) Successful in 2s
Java CI / build (push) Successful in 8m46s
MojangJavaDownloadTask never called updateProgress, so its progress bar stayed
indeterminate while the hidden LZMA-decompress and cache-copy steps wrote files
to disk. Players saw 0KB speed and a frozen-looking bar and restarted the
launcher. Append a progress callback after each file completes so the bar
advances through download/decompress/copy phases; the download logic is unchanged.
2026-11-10 11:15:06 +00:00
liuhao c905b49102 fix: mirror Prism maven (log4j-fixed) to self-hosted VPS for CN clients
Publish TDLM launcher / publish (push) Skipped
Publish TDLM launcher / noop (push) Successful in 2s
Java CI / build (push) Successful in 9m29s
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
files.prismlauncher.org resets the TLS handshake from mainland China and
BMCLAPI does not mirror its repackaged log4j-fixed artifacts, aborting TDLM
installs at Lwjgl3ifyApplyTask. Redirect that maven to the self-hosted client
mirror (fileApi root + /maven), keeping Prism as fallback. The log4j-api/core
2.0-beta9-fixed jars are hosted on the VPS with matching SHA-1.
2026-11-10 11:00:47 +00:00
liuhao 23ded32db1 docs: rewrite consume path section 4 for self-hosted VPS fileApi + rsync publish
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Publish TDLM launcher / publish (push) Skipped
Publish TDLM launcher / noop (push) Successful in 2s
Java CI / build (push) Successful in 8m54s
2026-11-10 10:21:55 +00:00
liuhao 9e66c9dbc7 docs: release note client fileApi default now self-hosted VPS
Java CI / build (push) Canceled after 43s
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Publish TDLM launcher / publish (push) Skipped
Publish TDLM launcher / noop (push) Successful in 3s
2026-11-10 10:21:09 +00:00
liuhao 07fffc4b01 fix: point default client fileApi at self-hosted VPS mirror
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Java CI / build (push) Canceled after 6m30s
Migrate client downloads off the external dandanton.com Nexus/CDN onto
http://159.75.5.225:19527/tdlm-client (nginx static, SHA-1 verified).
2026-11-10 10:14:44 +00:00
layue13 141df8c7b8 ci: delete the old generic package file right before re-uploading it (#21)
Publish TDLM launcher / publish (push) Skipped
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Publish TDLM launcher / noop (push) Successful in 2s
Java CI / build (push) Successful in 8m10s
Co-authored-by: Layue13 <layue13@icloud.com>
2026-11-10 08:46:54 +00:00
layue13 f5d739711d fix: default client fileApi is the Nexus raw tdlm-client (#20)
Mirror Repository / Mirror to CNB (push) Skipped
Mirror Repository / Mirror to Gitee (push) Skipped
Java CI / build (push) Successful in 8m14s
Co-authored-by: Layue13 <layue13@icloud.com>
2026-11-10 08:28:39 +00:00
6 changed files with 63 additions and 11 deletions

No files matched your search

+12 -1
View File
@@ -138,6 +138,17 @@ jobs:
def put(name: str, data: bytes):
url = upload_root + "/" + urllib.parse.quote(name, safe="")
# Gitea refuses to overwrite a generic package file (HTTP 409), so the previous copy of this one
# file is deleted right before it is uploaded again (keeps the gap without a file as short as possible).
delete = urllib.request.Request(url, method="DELETE")
delete.add_header("Authorization", "token " + token)
delete.add_header("User-Agent", "tdlm-hmcl-publish")
try:
with urllib.request.urlopen(delete, timeout=300) as response:
response.read()
except urllib.error.HTTPError as exc:
if exc.code != 404:
raise SystemExit("HTTP %s deleting the old %s: %s" % (exc.code, name, exc.read()[:300]))
request = urllib.request.Request(url, data=data, method="PUT")
request.add_header("Authorization", "token " + token)
request.add_header("Content-Type", "application/octet-stream")
@@ -204,7 +215,7 @@ jobs:
"- %s/HMCL.jar\n\n"
"TDLMPack does not Maven-resolve this launcher; point the pack README / install docs at these URLs "
"instead of hand-copying exe/jar.\n"
"Client pack fileApi default: https://packages.dandanton.com/tdlm-client/latest\n"
"Client pack fileApi default: http://159.75.5.225:19527/tdlm-client\n"
"(Pack must publish/mirror the same layout; see docs/TDLM_CONSUME.md).\n"
) % (package_root, package_root)
@@ -141,9 +141,9 @@ public final class Metadata {
return null;
}
/// Default client Server Modpack fileApi (CDN mirror of Pack's `tdlm-client/latest` layout).
/// Default client Server Modpack fileApi: self-hosted static mirror on the TDLM VPS (nginx, port 19527).
public static final String DEFAULT_CLIENT_FILE_API =
"https://packages.dandanton.com/tdlm-client/latest";
"http://159.75.5.225:19527/tdlm-client";
/// Stable client update root (`server-manifest.json` and `overrides/` live under this URL).
///
@@ -3,6 +3,7 @@
package org.jackhuang.hmcl.download;
import org.glavo.url.WebURL;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.download.cleanroom.CleanroomRemoteVersion;
import org.jackhuang.hmcl.download.fabric.FabricRemoteVersion;
import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion;
@@ -183,6 +184,11 @@ public final class HMCLDownloadProvider extends DownloadProvider {
new SimpleRule("https://hmcl.glavo.site/metadata/fmllibs", "https://alist.8mi.tech/d/mirror/HMCL-Metadata/Auto/fmllibs"),
new SimpleRule("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto"),
// files.prismlauncher.org is unreachable from mainland China (TLS handshake reset) and BMCLAPI
// does not mirror its repackaged log4j-fixed artifacts. Serve them from the self-hosted client
// mirror (alongside the fileApi root); Prism stays as the fallback for reachable networks.
new SimpleRule("https://files.prismlauncher.org/maven", Metadata.getClientFileApi() + "/maven"),
// https://github.com/mcmod-info-mirror/mcim-rust-api
new SimpleRule("https://api.modrinth.com", null, "https://mod.mcimirror.top/modrinth"),
new SimpleRule("https://cdn.modrinth.com", null, "https://mod.mcimirror.top"),
@@ -398,12 +398,22 @@ public final class Controllers {
.whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception != null) {
LOG.warning("Failed to fetch client Server Modpack manifest", exception);
Controllers.dialog(
manifestUrl + "\n" + exception.getMessage(),
i18n("message.error"),
MessageType.ERROR);
Instances.importModpack();
return;
}
ServerModpackManifest manifest =
JsonUtils.fromMaybeMalformedJson(result, ServerModpackManifest.class);
if (manifest == null) {
LOG.warning("Malformed client Server Modpack manifest from " + manifestUrl);
Controllers.dialog(
i18n("modpack.type.server.malformed"),
i18n("message.error"),
MessageType.ERROR);
Instances.importModpack();
return;
}
Controllers.getDecorator().startWizard(
@@ -25,6 +25,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@@ -37,6 +38,8 @@ public final class MojangJavaDownloadTask extends Task<MojangJavaDownloadTask.Re
private final Path tempDir;
private final Task<MojangJavaRemoteFiles> javaDownloadsTask;
private final List<Task<?>> dependencies = new ArrayList<>();
private final AtomicInteger completedFiles = new AtomicInteger();
private volatile int totalFiles;
private volatile MojangJavaDownloads.JavaDownload download;
@@ -147,6 +150,21 @@ public final class MojangJavaDownloadTask extends Task<MojangJavaDownloadTask.Re
Files.createSymbolicLink(dest, Paths.get(link.getTarget()));
}
}
// Report per-file progress so the bar advances through the download, LZMA decompress and
// cache-copy phases; otherwise it stays indeterminate while files appear on disk and players
// assume the install is frozen. The callbacks run after each file completes and never touch
// the download/decompress logic above.
totalFiles = dependencies.size();
if (totalFiles > 0) {
List<Task<?>> tracked = new ArrayList<>(totalFiles);
for (Task<?> dependency : dependencies) {
tracked.add(dependency.thenRunAsync(() -> updateProgress(completedFiles.incrementAndGet(), totalFiles)));
}
dependencies.clear();
dependencies.addAll(tracked);
updateProgress(0, totalFiles);
}
}
@Override
+15 -8
View File
@@ -46,26 +46,33 @@ Assets on each tag: `HMCL.exe`, `HMCL.jar`, plus `.sha256` files.
In `TDLM/TDLMPack` README §启动, replace the repo-only “安装 TDLM/HMCL” step with one of the URLs above.
**Do not** add HMCL as a Gradle/Maven dependency of the pack — pack CI stays pack-only.
### 4. Client pack fileApi (CDN)
### 4. Client pack fileApi (self-hosted VPS)
HMCL default (`Metadata.DEFAULT_CLIENT_FILE_API`):
```text
https://packages.dandanton.com/tdlm-client/latest
http://159.75.5.225:19527/tdlm-client
```
First install / updates fetch `{fileApi}/server-manifest.json` (and `overrides/**` under that root).
Override at runtime: `-Dhmcl.client.fileApi=…` or jar attribute `hmcl.client.fileApi`.
The fileApi is a read-only nginx static mirror on the TDLM VPS (`159.75.5.225`, port `19527`,
root `/var/www/tdlm-dl`). Players read it anonymously; integrity is verified by the SHA-1 hashes
in `server-manifest.json`.
**TDLMPack must use the same URL** so `server-manifest.json` embeds it:
```text
TDLM_CLIENT_FILE_API=https://packages.dandanton.com/tdlm-client/latest
TDLM_CLIENT_FILE_API=http://159.75.5.225:19527/tdlm-client
```
Set that as the Gitea Actions **variable** on `TDLM/TDLMPack` (pack.yml already passes `vars.TDLM_CLIENT_FILE_API`).
Set that as the Gitea Actions **variable** on `TDLM/TDLMPack` (pack.yml passes `vars.TDLM_CLIENT_FILE_API`;
`PackBuild.DEFAULT_FILE_API` is the build-time fallback).
**Publish caveat:** Pack’s current workflow PUTs the client tree to whatever `TDLM_CLIENT_FILE_API` is (upload root = fileApi). Today that defaults to Gitea generic
`https://git.nest.potatolab.uk:8443/api/packages/TDLM/generic/tdlm-client/latest`.
If you only change the HMCL default to the CDN and leave Pack publishing to Gitea, players will 404 unless you **mirror/sync** Gitea → `packages.dandanton.com/tdlm-client/latest`.
If you set `TDLM_CLIENT_FILE_API` to the CDN URL, Pack CI must be able to PUT to that CDN (or you must split “upload origin” from “public fileApi” in Pack — not implemented today). Do not point HMCL at the CDN without one of those two ops paths.
**Publish path (upload origin split from public fileApi):** Pack CI no longer PUTs to the read URL.
The `pack.yml` "Publish the client Server Modpack to fileApi" step rsyncs `build/pack/client/overrides/`
then `server-manifest.json` (manifest last) over SSH to `ubuntu@159.75.5.225:/var/www/tdlm-dl/tdlm-client`.
Auth is the repo secret `TDLM_VPS_SSH_KEY`, an ed25519 deploy key confined on the VPS by
`command="/usr/bin/rrsync /var/www/tdlm-dl/tdlm-client"` (rsync-only, no shell, no forwarding).
The public port 19527 serves GET/HEAD only — there is no public write surface.