Files
packwiz-to-sms/README.md
T
claude-timemachine 8651b076d3 initial: packwiz → simple-mod-sync manifest converter
Reads packwiz pack (pack.toml + index.toml + per-file .pw.toml) and
emits a simple-mod-sync sync_version=3 manifest. Drops server-only
mods, skips CurseForge metadata-mode entries with a warning, maps
content type from the parent directory of each metafile.

Optional --bundle-non-mods zips config/, options.txt etc into one
archive served as a 'packed' entry — covers the gap where simple-mod-sync
only ships zip-extractable content for non-mods.

15 tests, includes integration against upstream packwiz-example-pack.
2026-06-02 11:44:20 +02:00

82 lines
3.4 KiB
Markdown

# packwiz-to-sms
Convert a [packwiz](https://github.com/packwiz/packwiz) pack to a [simple-mod-sync](https://github.com/oxydien/simple-mod-sync) manifest (`sync_version: 3`).
## Why
Use **packwiz** to author the modpack (Modrinth/CurseForge integration, git-friendly TOML, optional/side-aware mods, `.mrpack` export for free), and **simple-mod-sync** for delivery to clients that can't or won't use Prism/MMC pre-launch hooks (vanilla launcher, TLauncher, cracked players).
One source of truth, two distribution channels — `.mrpack` export and simple-mod-sync manifest are both produced from the same packwiz repo.
## Install
Requires Python 3.11+ (uses `tomllib`). Zero runtime deps.
```bash
git clone https://git.timemachine.center/Timemachine/packwiz-to-sms.git
cd packwiz-to-sms
python3 packwiz_to_sms.py --help
```
## Usage
```bash
# Minimal — emit manifest to stdout
python3 packwiz_to_sms.py /path/to/packwiz/pack
# Write to file
python3 packwiz_to_sms.py /path/to/packwiz/pack -o manifest.json
# Bundle non-mod files (config/, options.txt, servers.dat) into a zip
# and add a 'packed' entry pointing at where you'll host it
python3 packwiz_to_sms.py /path/to/packwiz/pack \
-o manifest.json \
--bundle-non-mods overrides.zip \
--bundle-url https://packs.example.com/overrides.zip
```
## What gets emitted
| Packwiz path | Becomes simple-mod-sync `type` |
|---|---|
| `mods/*.pw.toml` (side=client or both) | `mod` |
| `mods/*.pw.toml` (side=server) | dropped |
| `resourcepacks/*.pw.toml` | `resourcepack` |
| `shaderpacks/*.pw.toml` | `shader` |
| `**/datapacks/*.pw.toml` | `datapack` |
| Any non-metafile (e.g. `options.txt`, `config/*`) | bundled into zip via `--bundle-non-mods`, emitted as one `packed` entry pointing at `directory: "."` |
CurseForge mods that use `mode = "metadata:curseforge"` (no direct URL) are skipped with a warning. Either switch to Modrinth equivalents or run `packwiz cf reexport` first to inline resolved URLs.
## What's not handled
- **Optional mods** — simple-mod-sync has no per-client toggle UI. All non-server mods are emitted unconditionally. Ship two manifests (with/without optional) if you need this.
- **Mod removal** — simple-mod-sync's `modify`/`remove` is not auto-populated. Convert by hand if you're dropping mods.
- **Rename / regex transforms** — packwiz has no equivalent concept, so we don't generate `modify.rename` entries.
## How it works
1. Reads `pack.toml` + `index.toml`.
2. For each entry marked `metafile = true`: reads the `.pw.toml`, pulls `download.url`, picks the simple-mod-sync `type` from the parent directory.
3. Drops `side = "server"`.
4. Drops entries where `download.url` is missing (CF metadata mode).
5. Optionally zips non-metafile files into a single archive for `packed` distribution.
Output schema matches `sync_version: 3` exactly (see [simple-mod-sync DOCS.md](https://github.com/oxydien/simple-mod-sync/blob/main/DOCS.md)).
## Tests
```bash
python3 -m pytest tests/
```
Covers conversion logic + CLI + bundle pipeline + a network integration test that converts the official [`packwiz-example-pack`](https://github.com/packwiz/packwiz-example-pack) (auto-skipped if offline).
## Upstream contribution
This tool fits the model used by other [simple-mod-sync translators](https://github.com/oxydien/simple-mod-sync/tree/main/translators). It can be PR'd upstream as `translators/packwiz.py`.
## License
MIT.