Skip to content

Repository files navigation

TaleSpire Encoding

This is a Python package for encoding and decoding TaleSpire data.

It currently supports the following encoding types:

  • Slabs (v1, v2)
  • Creature Blueprints (v1, v2, v3)
  • Stats Links (v1)

It also contains tools for reading in TaleSpire Assets. This requires a path to the installation location of TaleSpire on your machine.

The package published on PyPI is talespire-encoding. The Python import package is ts_encoding.

Installation

Install the latest release from PyPI:

pip install talespire-encoding

To upgrade to the latest version:

pip install --upgrade talespire-encoding

To install a specific version

pip install talespire-encoding==1.2.5

Usage

The Python import package is ts_encoding.

# Core API
from ts_encoding import TSSlab, TSCreature, TSStatsLink, TSAssetLib

Most classes expose a mutable dictionary named data. A common workflow is:

  1. Decode a TaleSpire string or URL into data.
  2. Inspect or edit values in data.
  3. Encode the object back into a string or URL that can be pasted into TaleSpire.

Slabs Example Usage

Slabs are the building data copied from TaleSpire. A slab code is not a normal URL; it is the compressed text string that TaleSpire places on the clipboard.

from ts_encoding import TSSlab

# This is an example slab string copied from TaleSpire.
example_slab_code = ("H4sIAAAAAAAACjv369xFJgZGBgYGgUWHGX9Pme/S4z7T7pZ"
                     "doRonUGwCSIKhgRFMS0L4DTwMDCcYwOIsDBDADOZLQsRB8g"
                     "xQPgOcDwD7jJ0vaAAAAA==")

# Create a slab object, then decode the copied slab string into slab.data.
slab = TSSlab()
slab.decode_slab(example_slab_code)

# The slab contents are now in a dictionary named `slab.data`.
# pprint is a Python helper that prints dictionaries in a more readable format.
from pprint import pprint
pprint(slab.data)

"""
{'layout_count': 1,
 'layouts': [{'instance_count': 9,
              'instances': [{'degrees': 90.0,
                             'pos_x': 0.0,
                             'pos_y': 0.0,
                             'pos_z': 4.0},
                            {'degrees': 0.0,
                             'pos_x': 4.0,
                             'pos_y': 0.0,
                             'pos_z': 4.0},
                            {'degrees': 0.0,
                             'pos_x': 2.0,
                             'pos_y': 0.0,
                             'pos_z': 4.0},
                            {'degrees': 270.0,
                             'pos_x': 0.0,
                             'pos_y': 0.0,
                             'pos_z': 2.0},
                            {'degrees': 180.0,
                             'pos_x': 0.0,
                             'pos_y': 0.0,
                             'pos_z': 0.0},
                            {'degrees': 0.0,
                             'pos_x': 4.0,
                             'pos_y': 0.0,
                             'pos_z': 2.0},
                            {'degrees': 0.0,
                             'pos_x': 2.0,
                             'pos_y': 0.0,
                             'pos_z': 2.0},
                            {'degrees': 0.0,
                             'pos_x': 4.0,
                             'pos_y': 0.0,
                             'pos_z': 0.0},
                            {'degrees': 0.0,
                             'pos_x': 2.0,
                             'pos_y': 0.0,
                             'pos_z': 0.0}],
              'reserved': 0,
              'uuid': '01c3a210-94fb-449f-8c47-993eda3e7126'}],
 'magic_num': 3520002766,
 'num_creatures': 0,
 'version': 2}
"""

# To encode the data again, call encode_slab().
new_slab_code = slab.encode_slab()

# The new_slab_code can be pasted into TaleSpire.

Creating a Slab From Scratch

To create slab data manually, start a new TSSlab and edit the data dictionary. Each UUID is a new layout in the dictionary. It is currently up to you to format the dictionary properly so that it encodes correctly. In future versions there may be tools to help build the layouts.

Here is an example of creating a single grass tile:

from ts_encoding import TSSlab

new_slab = TSSlab()

# This slab contains one layout, meaning one type of asset.
new_slab.data["layout_count"] = 1

grass_layout = {
    "instance_count": 1,  # The number of grass tiles in this layout.
    "instances": [{
        "degrees": 0.0,  # Yaw rotation in degrees, 0-360.
        "pos_x": 0.0,    # X position within the slab.
        "pos_y": 0.0,    # Y position within the slab.
        "pos_z": 0.0     # Z position within the slab.
    }],
    "reserved": 0,  # Always set to 0.
    "uuid": "01c3a210-94fb-449f-8c47-993eda3e7126"  # Asset UUID for Grass - Lush.
}

new_slab.data["layouts"].append(grass_layout)
new_slab_code = new_slab.encode_slab()

# You can paste new_slab_code into TaleSpire to see your grass tile.

encode_slab() checks TaleSpire's 30 kB slab-size limit by default. Pass ignore_limit=True to bypass that check.

Creature Blueprint Example Usage

Creature blueprints are copied as talespire://creature-blueprint/... URLs.

from ts_encoding import TSCreature
from pprint import pprint

url_from_TS = ("talespire://creature-blueprint/"
              "AgAMV2hpdGUgTWVlcGxlAQAAACMAYnI6MDAwMDAwMDAwMDAwMDAwMD"
              "AwMDAwMDAwMDQ3MDQxMDABAAAAAI49u_vNJQRDrZctETEJKR8ABAAA"
              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQQAAIEEAACBBAAAgQQ"
              "AAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEAACBBAAAgQQAAIEEA"
              "ACBBAAAgQQAAIEEAACBBAAAA")

# Decode the TaleSpire URL into bp.data.
bp = TSCreature()
bp.decode_url(url_from_TS)
pprint(bp.data)

# You can change any of the data in `bp.data`.
bp.data["name"] = "New Name"

# The first stat is HP, so this changes the creature's HP to 100/100.
bp.data["stats"][0] = {"max": 100.0, "value": 100.0}

# To re-encode the data, call encode_url().
new_url = bp.encode_url()

print(new_url)  # You can copy/paste this new URL into TaleSpire.

By default, encode_url() preserves the decoded version. You can pass force_encode_version=1 or force_encode_version=2 when you need a specific schema.

Stats Link Example Usage

Stat links are copied as talespire://stat-names/... URLs. They define the custom stat names used by a TaleSpire board.

from ts_encoding import TSStatsLink
from pprint import pprint

# Example from the TaleSpire 5e Creature Blueprint Database.
stats_link_url = "talespire://stat-names/AQAIAkFDBVNwZWVkB1NUUiBNb2QHREVYIE1vZAdDT04gTW9kB0lOVCBNb2QHV0lTIE1vZAdDSEEgTW9k"

# Decode the copied URL into stats.data.
stats = TSStatsLink()
stats.decode_url(stats_link_url)
pprint(stats.data)

# To create a stats link from scratch, start with a new TSStatsLink.
new_stats = TSStatsLink()

# Tell TaleSpire how many stat names are in this link.
new_stats.data["num_stats"] = 8

# These are the names that will appear in TaleSpire.
new_stats.data["names"] = [
    "AC", "CMD", "STR", "DEX", "CON", "INT", "WIS", "CHA"
]

new_url = new_stats.encode_url()

print(new_url)  # You can copy/paste this URL into TaleSpire to import your stats.

Use None in names for a null stat name.

Asset Library Example Usage

TSAssetLib reads TaleSpire asset metadata from a local TaleSpire installation. The supplied path should be the base TaleSpire install directory that contains the Taleweaver folder.

from ts_encoding import TSAssetLib

# Change this path to match where TaleSpire is installed on your computer.
talespire_path = r"C:\Program Files (x86)\Steam\steamapps\common\TaleSpire"

# Load all supported asset types: Tiles, Props, Creatures, and Music.
library = TSAssetLib(talespire_path)

# Look up an asset by UUID.
grass = library.asset("01c3a210-94fb-449f-8c47-993eda3e7126")
print(grass.name)
print(grass.asset_type)

# Get a list of every asset that was loaded.
all_assets = library.assets()

You can limit the loaded asset types:

library = TSAssetLib(talespire_path, asset_filter=["Tiles", "Props"])

Valid asset types are Tiles, Props, Creatures, and Music.

Exceptions

The public exception classes are available from ts_encoding:

from ts_encoding import (
    BadSlabCode,
    InvalidAssetType,
    InvalidTaleSpireDirectory,
    SlabExceedsSizeLimit,
    UnsupportedSlabVersion,
)

All package-specific exceptions inherit from TSEncodingException.

Development

Install the project locally with test dependencies:

python -m pip install -e .[dev]

Run the test suite:

python -m pytest

Asset-library tests need a local TaleSpire installation. They look for common Steam install paths and also respect the TALESPIRE_PATH environment variable. When TaleSpire is not found, those tests are skipped.

More development notes are in CONTRIBUTING.md.

About

Encoding/Decoding tools for TaleSpire

Topics

Resources

Contributing

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages