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 (auto-detected if omitted)
    --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 editor will open and you can browse assets, but 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.5.tar.gz (65.7 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.5-py3-none-any.whl (45.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: murder_unpack-0.1.5.tar.gz
  • Upload date:
  • Size: 65.7 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.5.tar.gz
Algorithm Hash digest
SHA256 85c9e43eb05ac021f202ea82292fe628f3f481f1f66729187b26c00a259ed27b
MD5 5c4a26761052ca712d4380d5f290b75d
BLAKE2b-256 a11e99a767b0c07ceef8629aeb4b68b80a39a266f2384c1b6ae5d4a9229a4d39

See more details on using hashes here.

Provenance

The following attestation bundles were made for murder_unpack-0.1.5.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.5-py3-none-any.whl.

File metadata

  • Download URL: murder_unpack-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 45.7 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c1e3fcda9d521d7b7a6f0f130aace0fbe68f2eceaef08b5f5c98294c93a7d79d
MD5 8ffce27528a91516ea81692da5ffb29a
BLAKE2b-256 8d2e69f6f19f42e227cdb579115b96ccf100d17abe5190af98d5db2589d3e16d

See more details on using hashes here.

Provenance

The following attestation bundles were made for murder_unpack-0.1.5-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