# 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-.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-.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.