Skip to main content

py-starbound

Python utilities for Starbound files, plus shipworld rendering and mod generation.

File & data formats

See FORMATS.md for technical details on Starbound’s formats (BTreeDB5, SBAsset6, SBVJ01, SBON, worlds).

Installation

  • Recommended (editable):
    • Core only:
python -m pip install -e .
  • With image features (Pillow) for render/modgen and related tests:
python -m pip install -e '.[ship]'

CLI commands (pystarbound)

CLI examples

  • Extract a .pak/.modpak to a directory
pystarbound export /Starbound/assets/packed.pak -d assets
  • Print world region info (tiles or entities)
# Pretty-print tiles for the region containing the player spawn
pystarbound region "/Starbound/storage/universe/-382912739_-582615456_-73870035_3.world"

# Print a specific region and value (e.g., liquid_pressure)
pystarbound region --value-index=12 \
  "/Starbound/storage/universe/-382912739_-582615456_-73870035_3.world" 69 27

# Print entities in a region
pystarbound region --entities \
  "/Starbound/storage/universe/-382912739_-582615456_-73870035_3.world" 69 27
  • World selection workflow (preview → requires → extract)
# Preview a player-built area by seed/flood-fill, with padding
pystarbound world-preview /path/to/world.world -o preview.png \
  --assets "/path/to/vanilla:/path/to/mods" \
  --seed 123,456 --seed-mode any --pad 2

# See which mods are required for that selection
pystarbound world-requires /path/to/world.world --json \
  --assets "/path/to/vanilla:/path/to/mods" \
  --seed 123,456 --pad 2 --objects --objects-only-known

# Extract the same selection as an installable mod, with objects and BYOS
pystarbound world-extract /path/to/world.world -o out/mod/export \
  --assets "/path/to/vanilla:/path/to/mods" \
  --seed 123,456 --pad 2 \
  --objects --objects-only-known --byos
  • Publish a directory to .pak
pystarbound publish ./folder -o out.pak \
  --only 'assets/*' --exclude '*.skip' --strip-prefix 'assets' \
  --metadata meta.json --meta author=py-starbound
  • Export packaged assets:
# List only
pystarbound export --list /path/to/packed.pak
# Extract
pystarbound export /path/to/packed.pak -d out/dir
  • Publish directory to .pak:
pystarbound publish ./folder -o out.pak \
  --only 'assets/*' --exclude '*.skip' --strip-prefix 'assets' \
  --metadata meta.json --meta author=py-starbound
  • Verify package integrity:
pystarbound verify out.pak
  • Versioned JSON:
pystarbound vjson-dump input.sbvj01 -o out.json
pystarbound vjson-make in.json -o out.sbvj01
# Edit: deep-merge a JSON patch and set/append fields
pystarbound vjson-edit in.sbvj01 --patch patch.json --set 'identity.name="Beta"' \
  --append 'tags="t1"' --append 'tags="t2"' -o out_edited.sbvj01
  • Render shipworld to PNG (requires extras [ship]):
pystarbound render /path/to/file.shipworld --assets '/path/to/vanilla:/path/to/mods' -o ship.png
  • World preview: layers, dungeon overlays, legend (requires extras [ship]):
# Only foreground, draw dungeon bounding boxes and labels, and write a legend of material colors used
pystarbound world-preview /path/to/world.world -o preview.png \
  --assets '/path/to/vanilla:/path/to/mods' \
  --layers fg --overlay-dungeons --overlay-dungeon-labels \
  --legend legend.json
  • Export selection to a Tiled-like JSON (experimental):
# Export a cropped area as a Tiled-like JSON with material IDs stored in CSV tile layers
pystarbound world-export-tiled /path/to/world.world \
  --rect 100,200,200,260 --pad 2 -o out/map.json
  • Workshop: list and sync (no login required):
# List installed Workshop items (JSON)
pystarbound workshop list --json

# Dry-run sync of contents.pak into Starbound/mods
pystarbound workshop sync --dry-run

# Symlink (or copy if not supported)
pystarbound workshop sync --link
  • Workshop: prepare/pack/verify modsets:
# Prepare a filtered modset (by IDs)
pystarbound workshop prepare --out-dir ./modset --ids 12345,67890

# Prepare by title substrings (case-insensitive) listed in a file (one per line)
pystarbound workshop prepare --out-dir ./modset --titles-file titles.txt

# Prepare with glob patterns on id/title
pystarbound workshop prepare --out-dir ./modset --only 'X-*' --exclude '*old*'

# Pack a prepared directory into a .pak
pystarbound workshop pack --dir ./modset -o modset.pak

# Verify all .pak files in a directory
pystarbound workshop verify --dir ./modset --json
  • Generate a mod from a shipworld (requires extras [ship]):
pystarbound modgen /path/to/file.shipworld \
  --assets '/path/to/vanilla:/path/to/mods' \
  -o out/mod/export \
  [--background-overlay] [--objects [--objects-only-known] [--objects-log-unknown path.json]] \
  [--material-map material_map.json]
  • World selection preview (PNG):
pystarbound world-preview /path/to/world.world -o preview.png \
  --assets '/path/to/vanilla:/path/to/mods' \
  [--dungeon-id N | --rect x0,y0,x1,y1 | --seed x,y [--seed-mode any|fg|bg]] [--pad 2] [--textured] [--no-crop]
  • Extract a structure from a planet/world:
pystarbound world-extract /path/to/world.world \
  --assets '/path/to/vanilla:/path/to/mods' \
  -o out/mod/export \
  [--dungeon-id N | --rect x0,y0,x1,y1 | --seed x,y [--seed-mode any|fg|bg] [--seed-connectivity four|eight]] [--pad 2] \
  [--background-overlay] [--objects [--objects-only-known] [--objects-log-unknown path.json]] \
  [--object-map objects.json] [--materials-include 1,2,3] [--materials-exclude 12345] \
  [--objects-include name1,name2] [--objects-exclude 'glob*'] [--blocks-position x,y] \
  [--requires-into-metadata] [--report report.json] [--pack] [--pack-out out.pak]
  • Batch export dungeons by id or by size:
# Specific dungeon ids
pystarbound world-extract /path/to/world.world -o out/mod/export \
  --assets "/path/to/vanilla:/path/to/mods" \
  --dungeon-ids 12,17,33 --pack

# Top 3 dungeons by tile count (min 500 tiles)
pystarbound world-extract /path/to/world.world -o out/mod/export \
  --assets "/path/to/vanilla:/path/to/mods" \
  --top-dungeons 3 --min-tiles 500 --pack --combined-patch combined_universe_server.config.patch
  • List dungeons present in a world (optionally with bounding boxes):
pystarbound world-dungeons /path/to/world.world [--bbox] [--json] [--min-tiles 100]
  • Analyze required mods for a selection (no export):
pystarbound world-requires /path/to/world.world \
  --assets '/path/to/vanilla:/path/to/mods' \
  [--dungeon-id N | --rect x0,y0,x1,y1 | --seed x,y [--seed-mode any|fg|bg]] [--pad 2] \
  [--objects [--objects-only-known]] [--json]

Assets roots

  • Use your OS path separator when passing multiple roots to --assets:
    • macOS/Linux: :
    • Windows: ;

Examples:

# macOS/Linux
--assets "/path/to/vanilla:/path/to/mods"
# Windows (PowerShell/cmd)
--assets "C:\Starbound\assets;C:\Starbound\mods"
  • When you pass a directory root to --assets, any .pak files inside it are automatically scanned. Material names and mapColor are read from .pak as well, so previews and blockKey naming work for .pak-only mods. Provenance (world-requires and requires.json) also includes .pak mods discovered under those directories.

Notes

  • Mod id default: when --mod-id is omitted, it is derived from the world filename (sanitized to [a-z0-9_-]).
  • Previews: --textured now reads texture paths from each material’s .material (renderParameters.texture) and loads from both directories and .pak files when available. It falls back to mapColor when textures are missing.
  • --no-crop renders the full world extents (default behavior crops to nonzero tiles).
  • Textures are not bundled; Starbound renders installed materials at runtime.
  • Unknown materials:
    • Provide assets roots with --assets
    • Or map manually via --material-map with a JSON mapping, for example:
{"12345": "modid:materialName"}

Testing

# All tests
pytest -q

# Single file
pytest tests/test_cli_publish_export.py -q

# Single test
pytest tests/test_cli_publish_export.py::test_publish_export_roundtrip -q

Note: Image-related tests require Pillow via extras:

python -m pip install -e '.[ship]'

Build (PEP 517 via setuptools)

python -m pip install -U build
python -m build

Artifacts are written to dist/.

Running from source (without install)

  • Detect Starbound installation (Steam paths):
pystarbound detect-install --json

If you prefer not to install during development, invoke the CLI via the module entrypoint. Ensure you set PYTHONPATH to include src/:

PYTHONPATH=src python3 -m starbound.cli <command> [options]
# examples
PYTHONPATH=src python3 -m starbound.cli export --list /path/to/packed.pak
PYTHONPATH=src python3 -m starbound.cli region /path/to/world.world --entities

Using the Python package

Example: Reading a player file

import starbound

with open('player/11475cedd80ead373c19a91de2e2c4d3.player', 'rb') as fh:
    player = starbound.read_sbvj01(fh)
    print('Hello, {}!'.format(player.data['identity']['name']))

Example: World files (fast with mmap)

import mmap, starbound

with open('universe/43619853_198908799_-9440367_6_3.world', 'rb') as fh:
    mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
    world = starbound.World(mm)
    world.read_metadata()

    print('World size: {}×{}'.format(world.width, world.height))
    x, y = world.metadata['playerStart']
    print('Player spawns at ({}, {})'.format(x, y))

    # Regions consist of 32×32 tiles.
    rx, ry = int(x) // 32, int(y) // 32
    print('An entity:', world.get_entities(rx, ry)[0])

Example: Easy access to various world attributes

import starbound

# Assume 'world' from the example above
info = world.info
print('World Name:', info.name)
print('World Description:', info.description)
print('World Coordinates:', info.coords)

Example: Getting assets from packed.pak

import starbound

with open('assets/packed.pak', 'rb') as fh:
    package = starbound.SBAsset6(fh)
    print(package.get('/lighting.config'))

Example: Finding an entity by UUID/ID

Many entities (flags, mech beacons, quest markers, etc.) have UUIDs or IDs the game uses to locate them. You can use World.get_entity_uuid_coords to locate the tile coordinates quickly when the index is present:

import mmap, starbound

with open('universe/43619853_198908799_-9440367_6_3.world', 'rb') as fh:
    mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
    world = starbound.World(mm)
    world.read_metadata()

mechbeacon_coords = world.get_entity_uuid_coords('mechbeacon')
if mechbeacon_coords:
    print('Mech beacon at', mechbeacon_coords)
else:
    print('No mech beacon in level!')

Example: Modifying SBVJ01 files (players, client contexts)

import starbound

with open('player/420ed511f83b3760dead42a173339b3e.player', 'r+b') as fh:
    player = starbound.read_sbvj01(fh)

    old_name = player.data['identity']['name']
    new_name = old_name[::-1]  # example transform
    player.data['identity']['name'] = new_name
    print('Updating name: {} -> {}'.format(old_name, new_name))

    # Rewrite file with updated data
    fh.seek(0)
    starbound.write_sbvj01(fh, player)
    fh.truncate()

Credits

  • Core: Blixt
  • Contributions and enhancements: Xytronix

License

MIT License

Release files for pstarbound 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pstarbound 1.3.0
File Size Uploaded
pstarbound-1.3.0.tar.gz 51.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pstarbound 1.3.0
File Interpreter ABI Platform
pstarbound-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 104.6 kB

Release files / pstarbound-1.3.0.tar.gz

Download URL pstarbound-1.3.0.tar.gz
Size 51.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6a3263f2b0924a7355efb480f0c987a82b367765de2029aff12ef444c6faac66
BLAKE2b-256 checksum
How to use checksums
bd3fcd3bc71965ad448ffde52db4b64c5d6ed212a25fae560a9904ce6a9b2917
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2025.

Transparency log

Release files / pstarbound-1.3.0-py3-none-any.whl

Download URL pstarbound-1.3.0-py3-none-any.whl
Size 53.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cc942aba5e40c8ff4a2ef96738fe5042ba72df835bbc7b2de6dddea01b68a318
BLAKE2b-256 checksum
How to use checksums
9e80cfbddf67832e3f47b9f6f6f993a78e9c009ff180c339d671951454d5b57b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page