Switch the library naming convention from "Pokemon - <Name> (Hack)" to "Pokemon - <Name> [Hack][version][tags]", and place hacks in the platform root (roms/<plat>/) instead of a Hacks/ subfolder. Applied across the live valhalla library (272 hack/fan-game files) via scripts/standardize-names.py. - romhack-import.py / romhack-fetch.py: emit [Hack], write to roms/<plat>/ - romhack-pc-migrate.py: emit [Hack] - build-romhack-vault.py (archived): update documented library_path - standardize-names.py: new one-shot, self-fetching standardizer (idempotent; pipes \n-only bytes over SSH to avoid Windows CRLF corrupting filenames) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
102 lines
6.1 KiB
Markdown
102 lines
6.1 KiB
Markdown
# Pokémon ROM Hacks — tooling
|
|
|
|
Acquisition + patching pipeline for the Pokémon ROM-hack collection in the
|
|
valhalla homelab library. Spun off from the `homelabstack` repo on 2026-06-06.
|
|
|
|
> **The catalog (the notes) lives in the self-hosted Obsidian vault**, not in this
|
|
> repo — under `Pokémon ROM Hacks/`: one note per hack, plus `Index`, `Types`,
|
|
> `Play Queue`, `Bases/`, `Platforms/`, a `Wanted` acquisition list, and a
|
|
> `_Claude.md` ops reference. Access it via the Obsidian MCP (`mcp__obsidian__*`)
|
|
> or the `vault` skill. New hacks are added there **manually** (see the vault's
|
|
> `_Claude.md` checklist). This repo is just the tooling.
|
|
|
|
The ROMs live on valhalla under `/storage1/Emulation/roms/<platform>/`,
|
|
served by the RomM stack (`roms.ginnoir.com`) — deployed from `homelabstack`
|
|
(`stacks/roms/`).
|
|
|
|
## Layout
|
|
|
|
| Path | What |
|
|
|---|---|
|
|
| `scripts/romhack-import.py` | Import a drop folder of mixed ROMs/patches/docs into the valhalla library (validate, clean-name, apply patches, archive). Runs on valhalla. |
|
|
| `scripts/romhack-fetch.py` | Acquire + patch + place worthwhile hacks from direct (non-gated) sources. Manifest-driven. Runs on valhalla. |
|
|
| `scripts/romhack-apply.py` | Apply a single IPS/BPS/UPS patch to a base ROM with checksum verification. |
|
|
| `scripts/romhack-pc-migrate.py` | Place the PC/Windows fan-games (RPG-Maker/Essentials) from the scrape staging tree into RomM's `windows` platform so RomM catalogs + serves them like the console hacks. Dry-run default; `--apply` copies, repackaging `.rar`→`.zip`. Runs on valhalla. |
|
|
| `scripts/launch-pc-hack.ps1` | Playnite custom-emulator launcher for the PC hacks: finds `Game.exe` in the RomM-downloaded folder, sets CWD, runs it. Runs on the Windows client. |
|
|
| `scripts/setup-playnite-pc-hack.ps1` | One-shot Playnite setup: registers the custom emulator + RomM `pc_windows` mapping (AutoExtract, download dir). Playnite must be closed. |
|
|
| `scripts/build-vault-mocs.py` | Regenerate the vault's static MOC tables + header counts (Index/Platforms/Bases) from the notes. Read-only on `Hacks/*.md`. Re-run after any note change. |
|
|
| `scripts/scrape_match.py` | Match the Discord-scrape `metadata.json` entries to vault notes → `.scrape/_match_report.json` (curated-overlap / discord-match / unmatched). |
|
|
| `scripts/enrich_vault.py` | Synthesize the scrape into notes: `backfill` (frontmatter for imports), `merge` (scrape into curated), `create` (new notes), `rebuild` (normalize import bodies). `--apply` writes; default dry-runs to `.scrape/_preview/`. |
|
|
| `scripts/enrich_web.py` | Apply hand/web-researched facts from `.scrape/web_facts*.json` onto notes (summary, features, dev, version, notability), idempotently. |
|
|
| `scripts/build-wiki-data.py` | Export all notes → `wiki/catalog.json`, the data source for the wiki site (see `wiki/SPEC.md`). |
|
|
| `scripts/build-romhack-vault.py` | **Archived.** Original 75-hack bootstrap generator — do **not** re-run against the live vault. Kept only for its structured `HACKS` dataset. |
|
|
| `wiki/` | `catalog.json` (exported 368-hack dataset) + `SPEC.md` (build spec for the future static wiki site). |
|
|
| `drop/` | **gitignored** staging area (~1.3 GB) of ROM/patch binaries pending import. |
|
|
| `.scrape/` | **gitignored** per-machine scratch: Discord-scrape `metadata.json` pulled from valhalla + match report + `web_facts*.json` + note backups. |
|
|
|
|
## Enrichment pipeline
|
|
|
|
The vault catalog (368 notes) was enriched from the Discord scrape on valhalla
|
|
(`/storage1/labdata/romhacks/metadata/*/metadata.json`) plus web research. To
|
|
re-run or extend:
|
|
|
|
```bash
|
|
# 1. pull the scrape metadata locally (one-time / refresh)
|
|
ssh valhalla "cd /storage1/labdata/romhacks/metadata && tar cf - */metadata.json" | tar xf - -C .scrape
|
|
|
|
# 2. match scrape -> notes
|
|
python scripts/scrape_match.py --report .scrape/_match_report.json
|
|
|
|
# 3. synthesize (drop --apply first to preview into .scrape/_preview/)
|
|
python scripts/enrich_vault.py backfill --apply
|
|
python scripts/enrich_vault.py rebuild --apply
|
|
python scripts/enrich_vault.py merge --apply
|
|
python scripts/enrich_vault.py create --apply
|
|
|
|
# 4. web-enrich more hacks: add a .scrape/web_factsN.json batch, then
|
|
python scripts/enrich_web.py --apply
|
|
|
|
# 5. refresh static surfaces + the site data
|
|
python scripts/build-vault-mocs.py
|
|
python scripts/build-wiki-data.py
|
|
```
|
|
|
|
Art for every scraped hack is web-served at
|
|
`https://romhacks-files.ginnoir.com/_meta/<scrape_dir>/<file>` (copied into the
|
|
Caddy-served `library/_meta/` tree on valhalla).
|
|
|
|
## PC / Windows hacks
|
|
|
|
The 40 `platform: PC` catalog entries are RPG-Maker XP / Pokémon Essentials
|
|
fan-games (`Game.exe` + `Data/*.rxdata`), not emulatable ROMs. 32 have files in
|
|
the scrape staging tree (`/storage1/labdata/romhacks/library/<dir>/`); the other 8
|
|
are gated (Reborn, Rejuvenation, Infinite Fusion, …) and live catalog-only on the
|
|
vault `Wanted` list.
|
|
|
|
They are served through the **same RomM stack** as the console hacks, under the
|
|
`windows` platform (RomM's "Microsoft Windows"; note `pc` is excluded in RomM's
|
|
`config.yml`, `windows` is not). Each hack is a single archive in the platform
|
|
**root** — `Pokemon - <Hack> [Hack].zip` — NOT in a subfolder (a subfolder would
|
|
make RomM treat the whole thing as one multi-file game).
|
|
|
|
```bash
|
|
# place the PC hacks into roms/windows/ (dry-run first)
|
|
python3 scripts/romhack-pc-migrate.py --catalog wiki/catalog.json
|
|
python3 scripts/romhack-pc-migrate.py --catalog wiki/catalog.json --apply
|
|
# then scan just that platform in RomM, or via API
|
|
```
|
|
|
|
- **Windows play:** RomM Playnite plugin downloads + extracts the zip, then
|
|
launches via `scripts/launch-pc-hack.ps1` registered as a Custom emulator.
|
|
- **Steam Deck:** no automated path — RetroDECK has no Windows runtime. mkxp-z
|
|
ports (ship `mkxp.json`) run natively on Linux; the rest need manual Proton.
|
|
- **Save sync:** RomM's save sync is emulator-only (won't cover these). Use
|
|
Ludusavi + Syncthing; Essentials saves land in `~/Saved Games/<Game.ini Title>/`.
|
|
|
|
## Acquisition policy
|
|
|
|
Pre-3DS handhelds (gb/gbc/gba/nds) + pre-Wii consoles. Direct, non-anti-bot
|
|
sources only for auto-fetch; gated hacks are tracked in the vault's
|
|
`Pokémon ROM Hacks/Wanted.md` for manual hand-off. No offensive/"shitpost"
|
|
content (e.g. Clover excluded).
|