Skip to main content

Decompile, unpack, recover, and repack tools for Murder Engine games

Project description

murder-unpack

Reverse-engineer exported Murder Engine games back into editor-openable projects. Extracts sprites, dialogues, world data, and more.

Features

  • Project recovery — Reconstruct a Murder Engine editor project from an exported game
  • Asset extraction — Unpack .gz data files into individual JSON assets
  • Sprite extraction — Extract individual sprites from texture atlas sheets as PNG
  • Dialogue export — Reconstruct .gum scripts and export to markdown
  • Localization export — Export localization CSV files matching Murder's editor format
  • Engine version detection — Auto-detect engine version from game_config fingerprinting
  • Binary analysis — Detect .NET deployment format (NativeAOT, single-file, self-contained)
  • C# stub generation — Auto-generate typed C# classes from packed JSON data
  • Repacking — Repack modified assets back into .gz format
  • Plugin system — Extend with drop-in .py files or pip-installable packages

Quick Start

Requirements

  • Python 3.11+
  • uv (recommended) or pip
  • Git (for engine cloning)
  • .NET 8 SDK (for building recovered projects)

Install

# With uv (recommended)
uv tool install murder-unpack

# Or from source
git clone https://github.com/yuna0x0/murder-unpack.git
cd murder-unpack
uv sync

Usage

# Show game info and detected engine version
murder-unpack info "path/to/game"

# Extract all data, sprites, dialogues, and localization
murder-unpack extract-all "path/to/game" output/

# Recover into a full editor project
murder-unpack recover "path/to/game" recovered/

# List assets with optional filters
murder-unpack list-assets "path/to/game" --type WorldAsset

Commands

Command Description
info Show game info, asset counts, detected engine version
extract-all Full extraction: data, sprites, dialogues, localization
extract-data Dump all .gz data files as plain JSON
extract-sprites Extract sprites from atlas sheets as PNG
extract-dialogue Export dialogues as .gum scripts, markdown, or both
list-assets List assets with --type and --name filters
decode-qoi Convert a single QOI image to PNG
recover Full editor project recovery
engine-versions List available Murder Engine branches and tags
repack Repack modified assets back into .gz format
analyze-binary Detect .NET format, extract types from NativeAOT binaries
plugins list List loaded plugins
plugins dir Show plugin directories

Recovery Options

murder-unpack recover "path/to/game" recovered/ \
    --engine-version rel/11.0 \    # Override auto-detected version
    --game-name MyGame \           # Project name (default: original assembly name)
    --skip-engine \                # Don't clone engine
    --engine-path /path/to/murder  # Use existing engine
    --no-stubs                     # Skip C# stub generation

Plugin System

Place .py files in ~/.murder-unpack/plugins/ or ./plugins/:

# plugins/my_handler.py
def register(registry):
    registry.asset_handlers["my_handler"] = MyHandler()

class MyHandler:
    name = "my_handler"
    asset_types = ["Custom.Assets.MyAsset"]

    def parse(self, asset_data):
        return asset_data

    def export(self, asset, output_path):
        output_path.write_text(str(asset))

Pip-installable plugins use entry points:

[project.entry-points."murder_unpack.asset_handlers"]
my_handler = "my_plugin:MyHandler"

[project.entry-points."murder_unpack.commands"]
my_cmd = "my_plugin.cli:my_command"

Limitations

Engine Version Detection

Murder Engine does not embed a version string in exported games. Version detection works by fingerprinting which fields are present in game_config — fields were added and removed across major releases. This means:

  • Detection covers rel/3.6 through rel/11.0. Unrecognized configs fall back to main (per Murder Engine convention).
  • Some version ranges are indistinguishable (e.g., rel/8.0, rel/9.0, and rel/10.0 share identical GameProfile fields — we default to rel/10.0).
  • Use --engine-version to override if auto-detection picks the wrong version.

NativeAOT Game Recovery

Games compiled with NativeAOT (like most shipped Murder Engine games) have their game logic baked into a native binary. Recovery can extract all data and assets but cannot recover:

  • Game-specific components — ECS component structs with behavior logic (e.g., Road.Components.*). Generated stubs are empty placeholders that allow the project to compile but have no behavior.
  • Game-specific systems — ECS systems that drive gameplay logic.
  • State machines, interactions, services — All compiled game code.

The recovery process patches the engine to warn instead of crash when referencing missing assets, so the editor remains usable. However, world entities that depend on missing game logic may not render or behave correctly.

Dialogue Reconstruction

.gum script reconstruction from compiled dialogue graphs is best-effort. Original formatting, comments, and some control flow nuances may differ from the source. The semantic content (text, choices, conditions, actions) is preserved.

Repacking

The repack command produces .gz files compatible with Murder's format, but replacing files in a NativeAOT game binary requires additional patching that is not currently automated.

Development

git clone https://github.com/yuna0x0/murder-unpack.git
cd murder-unpack
uv sync

# Run tests
uv run pytest

License

MIT - yuna0x0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

murder_unpack-0.1.6.tar.gz (68.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

murder_unpack-0.1.6-py3-none-any.whl (48.2 kB view details)

Uploaded Python 3

File details

Details for the file murder_unpack-0.1.6.tar.gz.

File metadata

  • Download URL: murder_unpack-0.1.6.tar.gz
  • Upload date:
  • Size: 68.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for murder_unpack-0.1.6.tar.gz
Algorithm Hash digest
SHA256 2df720ea453022a8efe9014874494560d618508cd5cbf0666594f272b2675b6b
MD5 00190201f8b980376135ea1a7b9731eb
BLAKE2b-256 82ddeb479e6161040b1613f61d380f304f917ed14f947965dc4a37020bcd5f04

See more details on using hashes here.

Provenance

The following attestation bundles were made for murder_unpack-0.1.6.tar.gz:

Publisher: pypi-publish.yml on yuna0x0/murder-unpack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file murder_unpack-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: murder_unpack-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 48.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for murder_unpack-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 e407b864c2e3df644a97b9a43ce5647a1899a551fe967c10a92479d464ebc36a
MD5 7e04a4243373f6d34cc8ca8a29b3958f
BLAKE2b-256 92b5c633ad7950567f0c08ef79533f8c28792db3476c680c480f13e872680578

See more details on using hashes here.

Provenance

The following attestation bundles were made for murder_unpack-0.1.6-py3-none-any.whl:

Publisher: pypi-publish.yml on yuna0x0/murder-unpack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page