POSTAL 2
Platform ID com.runningwithscissors.postal2
DigitalHeaven.Mods.Postal2 Prototype replaces the Dude with a DigitalHeaven avatar in POSTAL 2 (build 5100, an early hybrid Unreal Engine 2). It is an UnrealScript mod with a small native library behind it. Nothing of the game’s is replaced.
Requirements
Section titled “Requirements”| Game | POSTAL 2, build 5100 (System\Postal2.exe, InstalledVersion=5100) |
| Mod hook | Workshop P2GameMod (a mutator) |
Platform support
Section titled “Platform support”| Platform | Status |
|---|---|
| Windows | 🟡 Prototype |
| Linux (Proton only) | ❔ |
| macOS (Proton only) | ❔ |
| Share the Pain (build 1409) | ❌ |
Two integrations
Section titled “Two integrations”| Runtime mod | Exporter | |
|---|---|---|
| Role | Primary | Fallback |
| Avatars | Any workspace avatar, picked in the game | Avatars exported ahead of time |
| Package built | In the game process, on pick | By the DigitalHeaven.Platforms.Postal2 CLI, with UCC or --writer csharp |
| Read through | DHRuntime | DHManifest.txt |
| Needs UCC | No | Yes, unless --writer csharp |
The mod asks the runtime first, then the manifest. Everything after that (state, picking, limbs, the settings page, saves) is the same code for both. Without DHRuntime.u the mod is the exporter mod.
Runtime pipeline
Section titled “Runtime pipeline”Picking an avatar builds its package in the game process, off the game thread.
- The picker lists the workspace’s avatars. A pick sends
buildtoDHRuntime. - Reference skeletons are read from the player’s own
Characters.ukxand weapon.ukxfiles: the Dude and 19 limb skeletons. - Load workspace: the avatar’s pallet is read.
- Fit: the avatar is fitted onto the reference skeletons.
- Textures are converted.
- C# writer: a
DHRt<hash>package is written in memory (<hash>is 16 hex of its SHA-256). - A KERNEL32 file hook answers the engine’s open of
..\System\DHRt<hash>.ufrom memory. - The engine loads the package like any other, and the mod swaps the body.
picker -> reference skeletons -> load workspace -> fit -> textures -> C# writer (pick) 50 ms 700 ms 1.4-1.6 s 270 ms 210 ms | engine loads package <- KERNEL32 file hook serves bytes from memory <+ (DHRt<hash>.u, 14.3 MB, never written to disk)Measured for mltn Taidum (build 5100, suburbs-3):
| Stage | Time |
|---|---|
| Reference skeletons | 50 ms |
| Load workspace | 700 ms |
| Fit | 1.4 to 1.6 s |
| Textures | 270 ms |
| C# writer | 210 ms |
| Total | 2.6 to 2.9 s |
The package is 14.3 MB. Nothing is written to disk and nothing is cached. A changed avatar is a new content-hashed package under the same choice. Builds run one at a time on their own thread. A frame hitch was not measured.
Shipped files
Section titled “Shipped files”Four files go into the game’s System folder. Nothing of the game’s is replaced, and no RWS data ships: the reference skeletons are read from the player’s own install.
| File | Holds |
|---|---|
DigitalHeaven.u | The mod (script package) |
DHRuntime.u | DHRuntimeBridge, the one native function |
DHRuntime.dll | UE2 native package; forwards to DHRtCore.dll and installs the file hook |
DHRtCore.dll | NativeAOT win-x86 library: workspace, fit, textures, package writer |
native\install-runtime.bat and uninstall-runtime.bat copy exactly these and refuse while the game runs.
| Peak working set while building | about +360 MB (1692 MB with the build, 1332 MB without) |
| Resident after the build | 1537 MB |
The game is a 32-bit process, so the peak matters. Reduction work is in progress.
Enabling the mod
Section titled “Enabling the mod”- Start POSTAL 2.
- New Game > Workshop… > Mods > DigitalHeaven, then Start.
Plain New Game strips mutators and does not load the mod.
What the mod does
Section titled “What the mod does”| Feature | Status |
|---|---|
| Body swap (with mirrors) | 🟡 Prototype |
| First-person hands on 19 limb skeletons | 🟡 Prototype |
| First-person kick | 🟡 Prototype |
Settings page and DigitalHeaven.ini | 🟡 Prototype |
| Spring bones | ❌ |
| Overlay | ❌ |
Replaces the Dude’s mesh and skins, in third person and in mirrors. The fit keeps the Dude’s bone names, hierarchy and animations, and by default writes the avatar’s own proportions into the skeleton. A late swap restarts the Dude’s idle so the avatar does not stay in the bind pose.
First-person hands and kick
Section titled “First-person hands and kick”The avatar’s hands are drawn over the held weapon on 19 limb skeletons, one per weapon family. The kick draws the avatar’s foot. Each avatar’s package carries its own limb meshes.
Settings page
Section titled “Settings page”Reach it with Escape > Options > DigitalHeaven, or mutate dhmenu. The Options list on the main menu is not reachable (no mod runs there).
| Setting | Values | Status |
|---|---|---|
| Avatar | Every workspace avatar, or Dude (default) | ✅ via .ini, ❔ via the page |
| Replace Body | on, off | ✅ |
| Replace First Person Hands | on, off | ✅ |
| Replace First Person Kick | on, off | ✅ |
| Level of Detail | Full Detail, Automatic | 🟡 the runtime writer emits one LOD |
Choices are written to System\DigitalHeaven.ini on the first change:
[DigitalHeaven.DHSettings]Avatar=DHAvatar_MltnTaidumbReplaceBody=TruebReplaceHands=TruebReplaceKick=TruebFullDetail=TrueAn empty Avatar takes the manifest’s active avatar. Restore Defaults clears the choices. Taking the avatar off restores the Dude captured before the first swap in the level.
Console commands
Section titled “Console commands”Type each with mutate:
| Command | Does |
|---|---|
dhstatus | Logs which avatar is worn |
dhreload | Reloads the manifest and avatar |
dharms | Logs arm bone data |
dhhead | Logs head bone data |
dhbones | Logs the bone table and whether the game applies the avatar’s bone lengths |
dhhands | Logs one frame of hand placement against the held weapon |
dhglow | dhglow <0 to 255> sets the hands’ ambient light |
dhmenu | Opens the settings page |
dhnoclip | Toggles DigitalHeaven noclip (the key V when it was free, and a button on the Tools page) |
DigitalHeaven noclip
Section titled “DigitalHeaven noclip”Noclip flies the player through everything with the look direction: jump climbs, crouch descends, and the walk key (Shift by default) flies faster. The flight is Core’s NoclipFlight, the same step the engine and the other game mods run, with its default speed (12 m/s, 2.5 times that with the walk key). The runtime library runs one step per frame through the native bridge (about a microsecond a call), and the mod reads the held movement keys through the player’s own binds (the game’s input axes read zero outside the player’s own tick, so a key held when noclip starts counts at once), converts meters to Unreal units (88 per meter, the avatar scale), and moves the pawn by the answered velocity with physics and collision off. The numbers cross as whole millionths, since UnrealScript prints a float with two decimals and would round a frame’s time to zero. Noclip needs the runtime.
Switching it off puts the collision back at once, where the player is, inside geometry or not, as Source’s noclip does. Noclip never reaches a save: it ends for the save and comes back after.
The V key is bound the way the menu keys are: only when free, never over another binding, logged, and removed when the Menu Key setting is off or the runtime is uninstalled.
Settings layering
Section titled “Settings layering”lods, fit and proportions resolve in this order, each layer overriding the one before:
- Built-in default
dh-config.jsonc,platforms.postal2- The avatar’s override,
platforms/postal2/<avatar>.jsonc(or under the IDcom.runningwithscissors.postal2) - User force (CLI flag, or the settings page for Level of Detail)
| Key | Values | Default | Effect |
|---|---|---|---|
lods | on, off | off | off keeps the full mesh at every distance |
fit | height, hips | height | height scales to the Dude’s total height with the hip cap |
proportions | own, reference | own | own writes the avatar’s own bone lengths into the skeleton |
| Key | Runtime mod | Exporter |
|---|---|---|
lods | 🟡 single LOD from the C# writer | ✅ with UCC (LOD 1 to 3 are one bone per vertex) |
fit | ✅ | ✅ |
proportions | ✅ | ✅ |
Known limits
Section titled “Known limits”| Item | State |
|---|---|
| Finger fit | 🟡 approximate on some weapons (chainsaw and dusters worst) |
| Tail | 🟡 rigid: the Dude has no tail bones |
| Patterned fur | 🟡 flattened to a tint |
| LODs from the C# writer | 🟡 one LOD (collapse data is zero; pops would be the first suspect) |
| Share the Pain | ❌ needs the 1409 script and native builds |
| Workshop delivery of the DLLs | ❌ files are installed by hand |
| Linux and macOS | ❔ Proton only, untested |
| Settings page avatar picker in game | ❔ the same path was driven through the .ini |
| Saves with a runtime avatar | ❔ |
| Limbs with runtime avatars | ❔ |