Initial: MPQ patch packager (Gitea Action, StormLib-based)
A BigWigs-style CI packager for WoW MPQ patch archives. Reads an mpq.yaml manifest, stages files, builds a vanilla-1.12-compatible patch-X.mpq via StormLib, and (in the example workflow) attaches it to a Gitea release on tag.
This commit is contained in:
@@ -1,2 +1,120 @@
|
||||
# mpq-packager
|
||||
|
||||
A CI packager for World of Warcraft **MPQ patch archives** — the MPQ equivalent
|
||||
of [BigWigsMods/packager](https://github.com/BigWigsMods/packager). Point it at a
|
||||
WoW interface repo and it produces a vanilla-1.12-compatible `patch-X.mpq`,
|
||||
ready to attach to a Gitea release.
|
||||
|
||||
It runs as a **Gitea Action** on a Linux runner. MPQs are built with
|
||||
[StormLib](https://github.com/ladislav-zezula/StormLib) (the MoPaQ library
|
||||
Ladik's MPQ Editor is itself built on) so no Windows host or Wine is needed.
|
||||
|
||||
## What it does
|
||||
|
||||
1. Reads a manifest (`mpq.yaml`) describing what to pack and where it lands
|
||||
inside the archive.
|
||||
2. Stages the selected files, honouring ignore globs.
|
||||
3. Optionally substitutes `@project-version@` / `@project-revision@` /
|
||||
`@project-date-iso@` tokens in text files.
|
||||
4. Names the output `patch-<letter>.mpq` — vanilla 1.12's loader only accepts a
|
||||
**single-character** suffix (`patch-Z.mpq` ✅, `patch-myproject.mpq` ❌).
|
||||
5. Builds the archive as **MPQ format v1** with zlib-compressed sectors and a
|
||||
`(listfile)`.
|
||||
|
||||
## Usage in a consuming repo
|
||||
|
||||
Add a manifest at the repo root (`mpq.yaml`):
|
||||
|
||||
```yaml
|
||||
name: GlueXML
|
||||
patch-letter: Z # high letters sort last → win on conflict
|
||||
substitute:
|
||||
enabled: true
|
||||
extensions: [".lua", ".xml", ".toc"]
|
||||
contents:
|
||||
- src: . # repo root
|
||||
dest: Interface/GlueXML # in-MPQ path (slashes become backslashes)
|
||||
ignore:
|
||||
- ".git/**"
|
||||
- ".gitea/**"
|
||||
- "mpq.yaml"
|
||||
- "*.md"
|
||||
```
|
||||
|
||||
Add a release workflow at `.gitea/workflows/release.yml` (see
|
||||
[`examples/release.yml`](examples/release.yml)). Pushing a tag like `v1.0.0`
|
||||
builds the MPQ and attaches it to a matching Gitea release:
|
||||
|
||||
```yaml
|
||||
- uses: paste/mpq-packager@v1
|
||||
id: pack
|
||||
with:
|
||||
manifest: mpq.yaml
|
||||
version: ${{ github.ref_name }}
|
||||
# steps.pack.outputs.mpq-path / mpq-name point at the built archive
|
||||
```
|
||||
|
||||
Working examples for the GlueXML repo live in [`examples/`](examples/).
|
||||
|
||||
## Manifest reference
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|-----------------|--------------------|----------------------------------------------------------------|
|
||||
| `name` | — | Cosmetic, used in logs. |
|
||||
| `patch-letter` | `Z` | Single char; becomes `patch-<letter>.mpq`. |
|
||||
| `max-files` | file count + 16 | Hash-table sizing hint (StormLib rounds up to a power of two). |
|
||||
| `substitute` | disabled | `enabled` + `extensions` list for `@token@` replacement. |
|
||||
| `contents[].src` | `.` | Repo-relative file or directory to pack. |
|
||||
| `contents[].dest` | — | In-MPQ destination path (forward slashes; converted to `\`). |
|
||||
| `contents[].ignore` | `[]` | Glob patterns matched against repo-relative paths. |
|
||||
|
||||
## Action inputs / outputs
|
||||
|
||||
| Input | Default | Description |
|
||||
|------------|------------|----------------------------------------------------------|
|
||||
| `manifest` | `mpq.yaml` | Manifest path, relative to repo root. |
|
||||
| `version` | ref name | Stamped into `@project-version@`. |
|
||||
| `out-dir` | `dist` | Where the `.mpq` is written. |
|
||||
|
||||
| Output | Description |
|
||||
|------------|--------------------------------------|
|
||||
| `mpq-path` | Filesystem path of the built `.mpq`. |
|
||||
| `mpq-name` | Filename, e.g. `patch-Z.mpq`. |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Actions enabled** on the consuming repo (repo Settings → Actions).
|
||||
- An **`act_runner`** registered to your Gitea instance advertising a label your
|
||||
workflow's `runs-on` uses (e.g. `ubuntu-latest`), with Docker available.
|
||||
|
||||
## Local build & test
|
||||
|
||||
```bash
|
||||
docker build -t mpq-packager .
|
||||
docker run --rm \
|
||||
-e INPUT_MANIFEST=mpq.yaml -e INPUT_VERSION=v0.0.0 \
|
||||
-e INPUT_OUT_DIR=/work/dist -e GITHUB_WORKSPACE=/work \
|
||||
-v "$PWD/test:/work" mpq-packager
|
||||
# -> test/dist/patch-Z.mpq
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Role |
|
||||
|---------------------|-----------------------------------------------------------|
|
||||
| `src/mpqpack.c` | StormLib-based packer: staging dir → MPQ v1. |
|
||||
| `package.py` | Orchestration: manifest, staging, ignores, substitution. |
|
||||
| `entrypoint.sh` | Action entrypoint wiring `INPUT_*` env to `package.py`. |
|
||||
| `Dockerfile` | Builds StormLib + `mpqpack`; ships the runtime image. |
|
||||
| `action.yml` | Gitea/GitHub Docker action definition. |
|
||||
| `examples/` | Manifest + release workflow for a consuming repo. |
|
||||
| `test/` | Fixture + manifest exercised by CI. |
|
||||
|
||||
## Notes & caveats
|
||||
|
||||
- **`Blizzard_*` addons** still go through the engine's `.toc.sig` check
|
||||
regardless of MPQ residency — packaging them here does not bypass it.
|
||||
- Compression is zlib, which vanilla 1.12.1 decompresses. The output is MPQ v1
|
||||
specifically; v2+ headers are not read by the 1.12 loader.
|
||||
- See ClassicAPI `docs/MPQBuilding.md` for the empirical background on the
|
||||
naming constraint and load-order behaviour.
|
||||
|
||||
Reference in New Issue
Block a user