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
  • C# decompilation — Full source recovery from managed single-file bundles via bundled per-type decompiler (ilspycmd fallback)
  • C# stub generation — Fallback: auto-generate typed C# classes from packed JSON data (NativeAOT games)
  • Per-game fixes — Auto-detected decompiler artifact fixes with extensible registry
  • 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)
  • 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 and the bundled decompiler)

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, decompile
plugins List loaded plugins and 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)
    --engine-path /path/to/murder  # Use existing engine clone
    --skip-engine \                # Don't clone engine
    --no-stubs \                   # Skip C# stub/decompilation
    --decompile-timeout 1200       # Decompilation timeout (default: 600)
    --game-fix neverway            # Per-game fix (auto-detected, 'none' to skip)

Per-Game Fixes

Decompiled code sometimes has game-specific issues that can't be fixed generically (lost tuple element names, readonly field assignments, duplicate local functions). The fix registry auto-detects the game and applies known fixes.

Detection uses: assembly name, game namespace, Steam App ID, or game_config $type.

Adding a fix for a new game

Create murder_unpack/fixes/my_game.py:

from murder_unpack.fixes import GameFix, Replacement

FIX = GameFix(
    id="my-game",
    name="My Game",
    assembly_names=["MyGame"],
    steam_app_ids=["123456"],
    replacements=[
        Replacement(
            file_glob="**/SomeFile.cs",
            old="broken code",
            new="fixed code",
            description="CS1234: description of the issue",
        ),
    ],
)

Register in murder_unpack/fixes/__init__.py:

def _load_builtin_fixes() -> None:
    from murder_unpack.fixes import my_game
    _registry.register(my_game.FIX)

Or register via plugin:

def register(registry):
    from murder_unpack.fixes import get_registry
    get_registry().register(my_fix)

Plugin System

Plugins extend murder-unpack with custom asset handlers, extractors, commands, and hooks.

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

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

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

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

Pip-installable plugins — Use entry points in pyproject.toml:

[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"

Available extension points: asset_handlers, extractors, commands, hooks (pre_extract, post_extract, pre_recover, post_recover)

Limitations

C# Source Recovery

  • Managed single-file bundles — Full source recovery via bundled decompile-helper (per-type decompilation with timeouts). Falls back to ilspycmd, then to stub generation.
  • NativeAOT binaries — Cannot be decompiled. Recovery generates C# stubs for compilation but without behavior.

With full decompilation, the recovery uses the decompiled game class directly and applies targeted compatibility fixes: initset on engine types that cause CS8852 errors (detected via trial build), readonly removal on class fields for JSON deserialization, and JsonStringEnumConverter for string-based enum keys.

Engine Version Detection

Covers rel/3.6 through rel/11.0. Some version ranges are indistinguishable (rel/8.0–10.0 default to rel/10.0). Use --engine-version to override.

Dialogue Reconstruction

.gum script reconstruction from compiled dialogue graphs is best-effort. Semantic content is preserved; original formatting may differ.

Development

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

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.9.tar.gz (83.8 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.9-py3-none-any.whl (66.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: murder_unpack-0.1.9.tar.gz
  • Upload date:
  • Size: 83.8 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.9.tar.gz
Algorithm Hash digest
SHA256 0222be7066b94ce7d65bfab6359c664af05ce2fdfced46de03e2797f472f8047
MD5 12022ae89936a12ab49956c0807ae875
BLAKE2b-256 8e3522ac4de45a8a457b3f5169a834a3b9ffc04262c08ea3c09f58a6e33b3d11

See more details on using hashes here.

Provenance

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

Publisher: release.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.9-py3-none-any.whl.

File metadata

  • Download URL: murder_unpack-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 66.3 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.9-py3-none-any.whl
Algorithm Hash digest
SHA256 ce03d04e94b1fd80d8714b8c023476fe9818f53afe731b81303d91c119e5f579
MD5 f001d8bcb1700e5b2a1808cbe05ad940
BLAKE2b-256 041a10b4fb5689b95ae55c9bd31e51140e322c9a4072beb46232ede95d6021e0

See more details on using hashes here.

Provenance

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

Publisher: release.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