Skip to content

Repository files navigation

wadup

wadup is a command-line toolkit for reshaping Doom-engine WAD/PK3 archives: bundling a map with only the resources it actually uses, converting between WAD and PK3 layouts, and renaming textures/flats/patches so they can't collide with another WAD loaded alongside them.

It understands both classic binary formats (TEXTURE1/TEXTURE2, PNAMES, SIDEDEFS/SECTORS) and ZDoom's text-based ones (TEXTURES, TEXTMAP/UDMF, ANIMDEFS, SWITCHES, SNDINFO), and keeps their cross-references in sync whenever it renames or repacks something.

Installation

Requires Go 1.22+. No external runtime dependencies - it's a static binary.

git clone https://github.com/indrora/wadup.git
cd wadup
go build

This produces a wadup (or wadup.exe on Windows) binary in the current directory.

Commands

Command Purpose
mkstandalone Merge map WAD(s) with only the resources they reference from one or more resource archives, optionally renaming everything to avoid collisions
mkwad Pack a PK3-structured directory (or PK3 file) into a single WAD
wad2pk3 Unpack a WAD into a PK3 (or a loose directory), decoding graphics to PNG
uniqify Rename only the entries in a WAD that collide with a given set of other WADs/PK3s

Every command accepts -v (repeatable) to raise log verbosity: none is warnings-only, -v adds info, -vv adds more detail, -vvv is debug, -vvvv also turns on byte-level tracing inside the WAD/format decoders. Run wadup <command> --help for the full flag reference at any time.


mkstandalone

Takes one or more map WADs and one or more resource archives, and produces a single WAD containing every map plus exactly the textures, flats, and patches those maps reference - nothing more. The output no longer depends on the resource archives at runtime.

wadup mkstandalone --map mymap.wad --res OTEX.wad -o standalone.wad
  • --map (repeatable, at least one required) - a map WAD/PK3/directory. Every map it contains, and any resource lumps it already carries, is always included in the output.
  • --res (repeatable) - a resource WAD/PK3/directory to pull missing textures/flats from, searched in the order given; the first one that defines a name wins.
  • -o, --output (required) - the output WAD path.
  • --png - re-encode every flat/patch/sprite/simple-texture/graphic lump as PNG (grAb offsets preserved). Composite TEXTURE1/TEXTURE2 definitions stay binary metadata; the patches they're built from are converted individually.
  • -g, --game - stock palette to fall back on for --png when the output has no PLAYPAL of its own (doom, heretic, hexen, strife; default doom).

Textures, flats, and their composite-texture patches are resolved recursively: if a texture is built from patches, those patches get pulled in too, wherever they live among the --res archives. Anything that can't be resolved is logged as a warning rather than failing the build - it'll just show up as a missing-texture placeholder in-game. SWITCHES pairs and ANIMATED/ANIMDEFS animation chains that involve a used texture/flat are pulled in the same way (see How renaming actually works for how those two end up represented in the output).

Making the output collide-proof

By default, names keep whatever they were called in the map/resource archives. Two flags make every name unique instead, so this WAD can be loaded next to any other without stepping on its textures:

  • --uniq - replaces every texture/flat/patch name physically present in the output with a deterministic PREFIX + CRC-16 hash name (the prefix is derived from the output filename). Opaque, but guaranteed collision-free.
  • --res-prefix XXXX (1-4 characters) - overwrites the leading characters of every name with XXXX instead, keeping the rest intact (SW1BRN1 with --res-prefix MYPX becomes MYPXRN1). Much more readable than --uniq. If two names still collide after the overwrite, the loser keeps as much of its original suffix as possible and only has its last character or two replaced with a disambiguator; a full CRC-16 hash is the last resort, and in practice should never actually happen.

--uniq and --res-prefix are two answers to the same problem - use one or the other, not both. Every reference is rewritten to match: map sublumps (SIDEDEFS/SECTORS or TEXTMAP), TEXTURE1/TEXTURE2, TEXTURES, PNAMES, SWITCHES, ANIMDEFS, and MAPINFO/ZMAPINFO's Sky1/Sky2. A composite texture's patch reference that isn't backed by a lump anywhere in --map or --res (most often something expected from the base IWAD) is left alone rather than renamed, since it isn't this WAD's resource to rename.

  • --no-clobber - narrows either scheme to only the names actually pulled in from a --res archive. The map's own resources are left completely untouched, however they're named (a map-defined texture BINGO stays BINGO instead of becoming XXXINGO). Requires --uniq or --res-prefix.

mkwad

Packs a ZDoom PK3-structured directory (or an existing PK3 archive) into a single WAD file, routing files into WAD namespaces by their folder (flats/F_START/F_END, patches/P_START/P_END, and so on) and folding any maps/<NAME>.wad entries into real map lumps.

wadup mkwad myproject/ -o myproject.wad
  • -o, --output - output WAD path (defaults to <inputdir>.wad).
  • --map (repeatable) - additional map WAD(s) whose maps get appended to the output.
  • -c, --crushpng - recompress PNG lumps at maximum compression (grAb offsets preserved).
  • -z, --compression - PNG recompression level 1-9 (0 leaves PNGs as-is).

Graphic lumps that are already PNG are carried over as-is - ZDoom-family engines read them natively, so there's no need to convert back to raw Doom picture format.


wad2pk3

The reverse of mkwad: unpacks a WAD into a PK3 (or a loose directory tree), routing entries into the standard ZDoom folder layout and decoding flats/patches/sprites/textures/graphics to PNG (with grAb offsets preserved as a PNG chunk). Maps come out as maps/<NAME>.wad.

wadup wad2pk3 mymod.wad -o mymod.pk3
  • -o, --output - output PK3 file or directory (defaults to <input>.pk3, or <input>_pk3 with --dir).
  • -d, --dir - write an unpacked directory tree instead of a zipped PK3.
  • -t, --textures - convert binary TEXTURE1/TEXTURE2 + PNAMES into a ZDoom TEXTURES text lump before writing.
  • -g, --game - stock palette to use when the input has no PLAYPAL of its own (doom, heretic, hexen, strife, plus aliases doom1/doom2/ultimate/freedoom; default doom).
  • -c, --crushpng / -z, --compression - same PNG recompression controls as mkwad.
  • --keep-unknown - keep root lumps wadup can't otherwise classify as <name>.lmp instead of dropping them.

Colors come from the WAD's own PLAYPAL if it has one; a PWAD that relies on its IWAD's palette needs --game set to the right one.


uniqify

A narrower, older sibling of mkstandalone --uniq: renames only the entries in one WAD that collide with a given set of other WAD/PK3/directory "patches", instead of computing a fresh standalone build.

wadup uniqify input.wad output.wad other1.wad other2.pk3 ...

Takes exactly INPUT OUTPUT PATCH... (at least one patch is required). The rename prefix is derived automatically from OUTPUT's basename (mymaps.wadMYMA, short names are padded with X). Only names that actually collide get renamed - everything else in INPUT is left alone.

This does not understand scripts: if an ACS/SNDSEQ/etc. script references a lump by name and that lump gets renamed, the script keeps referring to the old (now different) resource. In that situation, either rename the resource by hand ahead of time or update the script afterward. mkstandalone avoids this class of problem for the lumps it knows how to parse (see the reference-rewriting list above), but neither tool touches compiled ACS bytecode.

How renaming actually works

Every rename scheme in wadup ultimately answers the same question - "what does resource X become?" - and then rewrites every place that name is used, not just the resource's own lump. A name can simultaneously be a texture, a flat, and a patch (a raw patch graphic doubling as its own simple texture is a common ZDoom pattern); when that happens, wadup assigns it exactly one new name and uses that everywhere, rather than letting each category drift to a different answer.

--uniq/--res-prefix (and uniqify's renaming) are tracked and rewritten across:

  • Classic binary maps (SIDEDEFS texture fields, SECTORS floor/ceiling flats)
  • UDMF text maps (TEXTMAP's texture* sidedef and sector fields)
  • TEXTURE1/TEXTURE2 (binary composite textures) and TEXTURES (ZDoom's text equivalent), plus PNAMES
  • SWITCHES, ANIMATED, and ANIMDEFS - whichever are present, each rewritten in its own native format
  • MAPINFO/ZMAPINFO's Sky1/Sky2

mkstandalone additionally normalizes animations as it assembles the output, before any of the above renaming happens: ANIMATED is always folded into ANIMDEFS (explicit frame-by-frame, never using ANIMDEFS' Range shorthand, since a range's in-between members are only implied by their position in the final texture directory - a position nothing guarantees survives merging and renaming). SWITCHES stays SWITCHES, just deduplicated. This mainly matters for mkstandalone; uniqify works on a single WAD as-is and never does this conversion.

Separately, whenever mkwad/mkstandalone folds a PK3 or directory into a WAD, SNDINFO's quoted PK3-style path references (e.g. "sounds/beepclunk.wav") get rewritten to whatever lump name that file actually ended up with - this is unrelated to --uniq/--res-prefix, and mainly matters when a filename is long enough that the 8-character lump name truncates it, which would otherwise silently break the reference.

Supported formats

Lump / namespace Read Write
TEXTURE1 / TEXTURE2 (binary composite textures) Yes Yes
TEXTURES (ZDoom text composite textures) Yes Yes
PNAMES Yes Yes
SWITCHES (binary) Yes Yes
ANIMATED (binary) Yes mkstandalone always converts it to ANIMDEFS; uniqify renames it in place
ANIMDEFS (text) Yes Yes
MAPINFO / ZMAPINFO (Sky1/Sky2 only) Yes Yes
SNDINFO (quoted PK3-path references only) Yes Rewritten when folding a PK3/directory into a WAD; not part of --uniq/--res-prefix
TX_START/TX_END, F_START/F_END (+ FF_ alias), P_START/P_END (+ PP_ alias), S_START/S_END (+ SS_ alias) Yes Yes
PK3 folders (textures/, flats/, patches/, sprites/, sounds/, music/, graphics/, maps/, ...) Yes Yes
Map format Support
Classic binary (SIDEDEFS/SECTORS) Yes
UDMF (TEXTMAP) Yes
Hexen-format THINGS/LINEDEFS, ACS BEHAVIOR/SCRIPTS Carried through as opaque data; not parsed or rewritten

Limitations

  • Names are limited to 8 characters, as Doom's format requires, and are matched case-insensitively.
  • --uniq's CRC-16 hash space is 65536 values; renaming everything (not just what collides) makes this a real, if small, risk at very large name counts. Collisions are detected and resolved with a salted retry, so uniqueness is always guaranteed - it just occasionally costs an extra hash.
  • Scripts (ACS bytecode, SNDSEQ, and similar) that reference a lump by name aren't rewritten when that lump is renamed, except where wadup explicitly parses the reference (see the list above). uniqify in particular makes no attempt at this.
  • PK3/directory inputs are expected to follow the standard ZDoom folder layout; nonstandard layouts may misclassify entries.

Development

go build ./...      # build everything
go test ./...        # run the test suite
go vet ./...          # static checks

Tests live alongside the code they cover (internal/doom/*_test.go, cmd/*_test.go) plus a set of root-level wadup_*_test.go files exercising the lower-level rewrite functions directly; _testdata/ holds real WAD/PK3 fixtures used for integration-level checks. See docs/TESTING.md for more background on the test layout (some of it predates the current subcommand structure and may lag behind).

Code layout

main.go                 - entry point, delegates to cmd.Execute()
cmd/                    - one file per subcommand (mkstandalone, mkwad, uniqify, wad2pk3) + root/shared flags
internal/doom/
├── archive.go          - Archive/Entry model, WAD <-> PK3 reading/writing, renaming
├── standalone.go       - mkstandalone's resource-resolution and pull-in logic
├── maps.go             - map sublump handling (SIDEDEFS/SECTORS/TEXTMAP)
├── textures.go         - TEXTURE1/2, TEXTURES, PNAMES
├── animations.go       - SWITCHES, ANIMATED, ANIMDEFS
├── sndinfo.go          - SNDINFO quoted-path rewriting
├── rename.go           - CRC-16 hashing and the --uniq/--res-prefix schemes
├── palette.go          - PLAYPAL / stock game palettes
├── flat.go, picture.go, png_grab.go - graphic <-> PNG conversion
├── pk3.go              - PK3/directory path <-> lump name derivation
├── classify.go         - root lump classification for wad2pk3
├── wad.go              - raw WAD file I/O
└── crc16.go, trace.go  - small supporting utilities

License

MIT - see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages