|
| 1 | +#!/usr/bin/env sh |
| 2 | +set -eu |
| 3 | + |
| 4 | +# Downloads the vanilla Minecraft assets used by the HTTPD live inventory view |
| 5 | +# into src/main/resources/httpd/assets for local development. |
| 6 | +# |
| 7 | +# Usage: |
| 8 | +# ./scripts/download-minecraft-assets.sh # latest release |
| 9 | +# ./scripts/download-minecraft-assets.sh 1.21.10 # specific version |
| 10 | + |
| 11 | +VERSION="${1:-}" |
| 12 | +PROJECT_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" |
| 13 | +ASSET_ROOT="$PROJECT_ROOT/src/main/resources/httpd/assets" |
| 14 | + |
| 15 | +python3 - "$VERSION" "$ASSET_ROOT" <<'PY' |
| 16 | +import json |
| 17 | +import shutil |
| 18 | +import sys |
| 19 | +import tempfile |
| 20 | +import urllib.request |
| 21 | +import zipfile |
| 22 | +from pathlib import Path |
| 23 | +
|
| 24 | +version_arg = sys.argv[1].strip() |
| 25 | +asset_root = Path(sys.argv[2]) |
| 26 | +manifest_url = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" |
| 27 | +
|
| 28 | +
|
| 29 | +def get_json(url): |
| 30 | + with urllib.request.urlopen(url, timeout=30) as response: |
| 31 | + return json.loads(response.read().decode("utf-8")) |
| 32 | +
|
| 33 | +
|
| 34 | +manifest = get_json(manifest_url) |
| 35 | +version = version_arg or manifest["latest"]["release"] |
| 36 | +version_entry = next((v for v in manifest["versions"] if v["id"] == version), None) |
| 37 | +if version_entry is None: |
| 38 | + raise SystemExit(f"Minecraft version {version!r} was not found in Mojang's manifest") |
| 39 | +
|
| 40 | +version_json = get_json(version_entry["url"]) |
| 41 | +client_url = version_json["downloads"]["client"]["url"] |
| 42 | +
|
| 43 | +print(f"Downloading Minecraft {version} client assets...") |
| 44 | +with tempfile.TemporaryDirectory() as tmp: |
| 45 | + jar_path = Path(tmp) / f"minecraft-{version}.jar" |
| 46 | + with urllib.request.urlopen(client_url, timeout=300) as response, jar_path.open("wb") as out: |
| 47 | + shutil.copyfileobj(response, out) |
| 48 | +
|
| 49 | + for directory in ("textures", "models", "items"): |
| 50 | + shutil.rmtree(asset_root / directory, ignore_errors=True) |
| 51 | + (asset_root / directory).mkdir(parents=True, exist_ok=True) |
| 52 | +
|
| 53 | + prefixes = ( |
| 54 | + "assets/minecraft/textures/item/", |
| 55 | + "assets/minecraft/textures/block/", |
| 56 | + "assets/minecraft/textures/entity/shield/shield_base_nopattern.png", |
| 57 | + "assets/minecraft/models/item/", |
| 58 | + "assets/minecraft/models/block/", |
| 59 | + "assets/minecraft/items/", |
| 60 | + ) |
| 61 | +
|
| 62 | + extracted = 0 |
| 63 | + with zipfile.ZipFile(jar_path) as jar: |
| 64 | + for info in jar.infolist(): |
| 65 | + if info.is_dir() or not info.filename.startswith(prefixes): |
| 66 | + continue |
| 67 | + relative = info.filename[len("assets/minecraft/"):] |
| 68 | + target = asset_root / relative |
| 69 | + target.parent.mkdir(parents=True, exist_ok=True) |
| 70 | + with jar.open(info) as source, target.open("wb") as out: |
| 71 | + shutil.copyfileobj(source, out) |
| 72 | + extracted += 1 |
| 73 | +
|
| 74 | +(asset_root / ".minecraft-version").write_text(version + "\n", encoding="utf-8") |
| 75 | +print(f"Extracted {extracted} files to {asset_root}") |
| 76 | +PY |
0 commit comments