115 lines
5.2 KiB
Markdown
115 lines
5.2 KiB
Markdown
# Assets mirror — offline Minecraft asset objects for clients
|
||
|
||
## Summary
|
||
|
||
Guest launchers (FjordLauncherUnlocked, a Prism soft-fork) download ~400–600 MB of
|
||
**asset objects** (textures, sounds, lang) from `resources.download.minecraft.net`
|
||
on first instance launch. For an air-gapped party that's the single biggest
|
||
client-side download. Fjord/Prism expose an **"Assets Server"** override, so we
|
||
mirror the objects onto our host and point guests at it.
|
||
|
||
`tooling/mirror-assets.sh` downloads + verifies every asset object for the pinned
|
||
Minecraft version and lays them out so Caddy can serve them in the exact path
|
||
shape the launcher expects.
|
||
|
||
## Fjord/Prism override fields (confirmed)
|
||
|
||
Settings → APIs → **Services** tab:
|
||
|
||
| Field | Setting key | Default | What it overrides |
|
||
|---|---|---|---|
|
||
| **Assets Server** | `ResourceURL` | `https://resources.download.minecraft.net/` | asset **objects only** |
|
||
| **Metadata Server** | (meta URL) | `https://meta.prismlauncher.org/v1/` | Prism-format version meta |
|
||
|
||
- Added in Prism 10.0.0 (PR #3875); inherited by Fjord.
|
||
- **There is NO libraries-URL field.** Library + client.jar URLs live inside the
|
||
version/meta JSON; only a meta mirror (or DNS spoof) can redirect them.
|
||
|
||
### ⚠️ HTTPS is forced
|
||
|
||
PR #3875 validates the Assets Server URL as **HTTPS and auto-rewrites `http://`
|
||
→ `https://`**. So the assets mirror **must be served over TLS** — plain `:80`
|
||
Caddy will not work for this endpoint. This pulls local TLS forward for one
|
||
subdomain ahead of the rest of the stack.
|
||
|
||
Options to satisfy it:
|
||
1. Caddy TLS on `assets.${BASE_DOMAIN}` with a cert from a local CA
|
||
(step-ca); guests import the CA root once. Cleanest, matches homelab.
|
||
2. Caddy `internal` CA / self-signed — guests must trust it (more friction, per
|
||
machine).
|
||
3. Sidestep entirely with **pre-seed** (below) and skip the Assets Server override.
|
||
|
||
## What this mirror does and does NOT cover
|
||
|
||
| Client download | Host | Covered here? |
|
||
|---|---|---|
|
||
| asset objects (bulk) | resources.download.minecraft.net | ✅ this mirror + Assets Server field |
|
||
| asset index json | meta/piston | ⚠️ fetched here for completeness; launcher still pulls it from meta unless meta is also mirrored |
|
||
| libraries | libraries.minecraft.net | ❌ no override field |
|
||
| client.jar | piston-data.mojang.com | ❌ |
|
||
| version/meta json | meta.prismlauncher.org | ❌ (separate Metadata Server field) |
|
||
|
||
**Full client air-gap therefore needs more than this.** For the uncovered, small
|
||
(~150 MB) remainder, the pragmatic fallback is **pre-seed**: each guest launches
|
||
the instance once while online (on arrival, before air-gapping); Prism caches
|
||
libraries/jar/meta locally. The assets mirror still saves the heavy 400 MB+ per
|
||
guest. A full meta+libraries mirror (mcm-style / PrismLauncher-meta gen) is the
|
||
heavyweight alternative, deferred.
|
||
|
||
## tooling/mirror-assets.sh — design
|
||
|
||
Input: `MC_VERSION` (default `1.21.1`, or read from the pre-baked server's
|
||
`version.json`). Cautious: verifies SHA1 on every file, halts on mismatch,
|
||
idempotent (skips already-valid files).
|
||
|
||
```
|
||
1. GET https://piston-meta.mojang.com/mc/game/version_manifest_v2.json
|
||
→ find entry for $MC_VERSION → version-json URL
|
||
2. GET version-json → read .assetIndex { id, url, sha1 }
|
||
3. GET asset index → mirror/assets/indexes/<id>.json (verify sha1)
|
||
4. For each object in index .objects{}:
|
||
hash=<sha1>; rel="${hash:0:2}/${hash}"
|
||
dest="mirror/assets/objects/${rel}"
|
||
[ -f "$dest" ] && sha1 ok → skip
|
||
else GET https://resources.download.minecraft.net/${rel} → $dest ; verify sha1
|
||
5. Report counts; non-zero exit on any failure.
|
||
```
|
||
|
||
Layout served by Caddy:
|
||
```
|
||
mirror/assets/
|
||
├── indexes/<id>.json # e.g. 17.json / 1.21.json (for pre-seed/meta use)
|
||
└── objects/<2hex>/<sha1> # launcher requests <ResourceURL>/<2hex>/<sha1>
|
||
```
|
||
|
||
### Caddy wiring
|
||
|
||
Serve the **objects** dir at the web root of an HTTPS vhost so the launcher's
|
||
`<ResourceURL>/<2hex>/<hash>` resolves directly:
|
||
|
||
```
|
||
https://assets.{$BASE_DOMAIN} {
|
||
tls <local-ca-cert> <key> # or `tls internal`
|
||
root * /srv/assets/objects
|
||
file_server
|
||
}
|
||
```
|
||
Mount `./mirror/assets/objects:/srv/assets/objects:ro`. Add network alias
|
||
`assets.${BASE_DOMAIN}` to Caddy (same trick as auth/packwiz).
|
||
Fjord "Assets Server" = `https://assets.${BASE_DOMAIN}/`.
|
||
|
||
## Tasks
|
||
|
||
- [ ] Write `tooling/mirror-assets.sh` (above); `chmod +x`; deps `curl` + `jq` + `sha1sum`
|
||
- [ ] Decide MC_VERSION source: hardcode `1.21.1` vs read pre-baked `version.json`
|
||
- [ ] Run pre-party while online; verify `mirror/assets/objects/` populated + sha1 clean
|
||
- [ ] Stand up TLS for `assets.${BASE_DOMAIN}` (step-ca or `tls internal`) — REQUIRED (HTTPS forced)
|
||
- [ ] Add `assets.` Caddy vhost + network alias + mount
|
||
- [ ] Document guest step: Settings → APIs → Assets Server = `https://assets.${BASE_DOMAIN}/`
|
||
- [ ] Document guest CA-trust step (import local CA root) if not using a publicly-trusted cert
|
||
- [ ] Confirm in Fjord's actual UI that the field exists + HTTPS-forcing behavior matches Prism
|
||
- [ ] Fallback path: pre-seed instructions (launch once online) for libraries/jar/meta
|
||
- [ ] Defer decision: full meta+libraries mirror (mcm / PrismLauncher-meta) vs pre-seed
|
||
- [ ] `.gitignore` already covers `mirror/`
|
||
```
|