{"id":24861948,"url":"https://github.com/jwheare/mythextract","last_synced_at":"2025-04-12T23:14:10.559Z","repository":{"id":274822497,"uuid":"924172425","full_name":"jwheare/mythextract","owner":"jwheare","description":"Tools to extract assets from Myth: The Fallen Lords and Soulblighter tag files","archived":false,"fork":false,"pushed_at":"2025-04-01T11:14:39.000Z","size":1721,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T23:14:05.535Z","etag":null,"topics":["bungie","myth","soulblighter","soundblighter","thefallenlords","untag"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jwheare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-29T14:46:09.000Z","updated_at":"2025-04-01T11:14:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"df0dc271-99e3-4ffe-92aa-145196ecd036","html_url":"https://github.com/jwheare/mythextract","commit_stats":null,"previous_names":["jwheare/mythextract"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwheare%2Fmythextract","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwheare%2Fmythextract/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwheare%2Fmythextract/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwheare%2Fmythextract/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwheare","download_url":"https://codeload.github.com/jwheare/mythextract/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248643006,"owners_count":21138355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bungie","myth","soulblighter","soundblighter","thefallenlords","untag"],"created_at":"2025-01-31T22:20:33.279Z","updated_at":"2025-04-12T23:14:10.553Z","avatar_url":"https://github.com/jwheare.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mythextract\n\nTools to extract assets from *Myth: The Fallen Lords* (*TFL*) and *Myth II: Soulblighter* (*SB*) tag files.\n\nThese are the currently included scripts, please file an issue if you have ideas for any more.\n\n## [scripts/mono2tag.py](scripts/mono2tag.py)\n\nThis is a replacement for [UnTag](https://tain.totalcodex.net/items/show/untag-51-win) among others.\n\nList and export tag files from *TFL* or *SB* monolithic tag containers (e.g. `artsound.gor` or `international large install`).\n\n    Usage: python3 mono2tag.py \u003cmono_file\u003e [\u003ctype\u003e \u003cid\u003e [\u003coutput_file\u003e]]\n\n* `mono_file`: path to monolithic tag container\n* `type` AND `id`: **optional** — must be provided together to export a specific tag. If omitted, just list all tags without export\n* `output_file`: **optional** — defaults to `./tags/[game_ver]-[tagid]`\n\n## [scripts/tag2aifc.py](scripts/tag2aifc.py)\n\nThis is a replacement for [Soundblighter](https://tain.totalcodex.net/items/show/soundblighter-pc) among others.\n\nExports AIFC (AIFF-C, compressed sound file format) from *TFL* or *SB* `soun` tag files. Note that sound tags can contain multiple permutations. Each permutation is exported as a separate file.\n\n    Usage: python3 tag2aifc.py \u003cinput_file\u003e [\u003coutput_file\u003e]\n\n* `input_file`: path to individual tag file extracted from monolithic tag container (with `mono2tag.py`)\n* `output_file`: **optional** — defaults to `./output/aifc/[game_ver]-[tagid][-n].aifc` where `-n` is a permutation number prefix if there are more than 1\n\nSee [docs/SoundTagNarrationFormat.txt](docs/SoundTagNarrationFormat.txt) and the source code for detailed notes on the binary format.\n\nAIFF file format described here: https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/AIFF.html\n\n## [scripts/tag2png.py](scripts/tag2png.py)\n\nExports 32-bit alpha PNG from *TFL* or *SB* `.256` or `d256` (aka collection) tag files. Note that collections can contain multiple image. Each image is exported as a separate file.\n\n    Usage: python3 tag2png.py \u003cinput_file\u003e [\u003coutput_file\u003e]\n\n* `input_file`: path to individual tag file extracted from monolithic tag container (with `mono2tag.py`)\n* `output_file`: **optional** — defaults to `./output/png/[game_ver]-[tagid][-n].png` where `-n` is a bitmap number prefix if there are more than 1\n\nScript environment variables:\n* `DEBUG_COLL=1` prints lots of extra debug image parsing output\n\nSee [docs/256TagCollectionFormat.txt](docs/256TagCollectionFormat.txt) and the source code for detailed notes on the binary format.\n\n## [scripts/tag2font.py](scripts/tag2font.py)\n\nExtracts and lists glyph information from `font` tag files.\n\n    Usage: python3 tag2font.py \u003cinput_file\u003e\n\n* `input_file`: path to individual tag file extracted from monolithic tag container (with `mono2tag.py`)\n\nSee [docs/FontTagFormat.txt](docs/FontTagFormat.txt) and the source code for detailed notes on the binary format.\n\n## [scripts/loadtags.py](scripts/loadtags.py)\n\nLoads all the core tag archives and optionally a plugin from a *SB* game directory and lists all levels and tags\n\n    Usage: python3 loadtags.py \u003cgame_directory\u003e [\u003cplugin_names\u003e ...]\n\n* `game_directory`: path to a Myth game directory\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n## [scripts/mesh2info.py](scripts/mesh2info.py)\n\nPrints the headers of a mesh tag, or tags\n\n    Usage: python3 mesh2info.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided can load meshes from named plugins\n\n## [scripts/mesh2markers.py](scripts/mesh2markers.py)\n\nPrints all markers from a mesh tag\n\n    Usage: python3 mesh2markers.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided can load meshes from named plugins\n\nScript environment variables:\n* `DEBUG_MARKERS=1` prints extra debug marker parsing output\n\n## [scripts/mesh2actions.py](scripts/mesh2actions.py)\n\nPrints map scripting actions from a mesh tag\n\n    Usage: python3 mesh2actions.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided can load meshes from named plugins\n\nScript environment variables:\n* `DEBUG_ACTIONS=1` prints extra debug action parsing output\n\n## [scripts/action_browser.py](scripts/action_browser.py)\n\nRuns a map scripting actions terminal browser for a mesh tag. **requires `windows-curses` on Windows**\n\n    Usage: python3 action_browser.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_name\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided can load meshes from named plugins\n\nScript environment variables:\n* `DEBUG_ACTIONS=1` prints extra debug action parsing output\n* `DEBUG_MARKERS=1` prints extra debug marker parsing output\n\n## [scripts/mesh2text.py](scripts/mesh2text.py)\n\nOutputs pregame text data from a mesh tag\n\n    Usage: python3 mesh2text.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_name\u003e [\u003cplugin_output\u003e]]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_name`: **optional** — if provided can load meshes from the named plugin\n* `plugin_output`: **optional** - if provided specifies the output directory name to use instead of the plugin name\n\nScript environment variables:\n* `TIME=1` prints extra debug timing output\n\n## [scripts/fixmeshactions.py](scripts/fixmeshactions.py)\n\nFixes mesh actions by removing any unused data stored at the end of the action buffer and fixing header offsets and sizes. Outputs to `./output/fixed_mesh_actions/meshes/[mesh_name]`\n\n    Usage: python3 fixmeshactions.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided can load meshes from named plugins\n\nScript environment variables:\n* `DEBUG_ACTIONS=1` prints extra debug action parsing output\n\n## [scripts/fixentrypoints.py](scripts/fixentrypoints.py)\n\nFixes plugin entrypoints by looking up the description tag from the level mesh\n\n    Usage: python3 fixentrypoints.py \u003cmono_file\u003e [\u003coutput_path\u003e]\n\n* `mono_file`: path to monolithic tag container (plugin file)\n* `output_file`: **optional** — defaults to `./output/fixed_entrypoints/\u003cmono_file_name\u003e`\n\n## [scripts/tflmeshtext2sb.py](scripts/tflmeshtext2sb.py)\n\nLoad Myth TFL game tags and convert text and stli tags for a given mesh to Myth II format.\nAlso maps to the tag ids used by the ports of TFL to Myth II. Outputs to `./output/fixed_tfl_mesh_text/local`\n\n    Usage: python3 tflmeshtext2sb.py \u003cgame_directory\u003e [\u003clevel\u003e]\n\n* `game_directory`: path to a Myth TFL game directory\n* `level`: can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n\nScript environment variables:\n* `TIME=1` prints extra debug timing output\n\n\n## [scripts/d256info.py](scripts/d256info.py)\n\nPrints the headers of a detail collection (d256) tag\n\n    Usage: python3 d256info.py \u003cgame_directory\u003e [\u003ctag_id\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `tag_id`: **optional** — if omitted lists the names and ids of d256 tags. can be `all` to iterate\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n## [scripts/collmismatch.py](scripts/collmismatch.py)\n\nLists collection mismatches for a given level/mesh\n\n    Usage: python3 collmismatch.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n## [scripts/mons2info.py](scripts/mons2info.py)\n\nPrints the headers of a mons tag, or tags\n\n    Usage: python3 mons2info.py \u003cgame_directory\u003e [\u003cmons_id\u003e [\u003cplugin_names\u003e ...]]\n\n* `game_directory`: path to a Myth game directory\n* `mons_id`: **optional** — if omitted lists the names and ids of all mons tags\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n## [scripts/mesh2tags.py](scripts/mesh2tags.py)\n\nThis replaces some functionality of [Chaos](https://tain.totalcodex.net/items/show/chaos-source).\n\nRecursively extracts all referenced tags from a mesh to a local tree. Outputs to `./output/mesh2tags/[mesh_name]`\n\n    Usage: python3 mesh2tags.py \u003cgame_directory\u003e [\u003clevel\u003e [\u003cplugin_names...\u003e]]\n\n* `game_directory`: path to a Myth game directory\n* `level`: **optional** — if omitted just lists all levels. can be `all` to iterate endpoints or `meshid=\u003cmesh_id\u003e` if the level you want isn't numbered or ambiguous\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n## [scripts/tag2local.py](scripts/tag2local.py)\n\nThis replaces some functionality of [Chaos](https://tain.totalcodex.net/items/show/chaos-source).\n\nRecursively extracts all referenced tags from a tag into a local tree structure Outputs to `./output/tag2local/[tag_type]/[tag_id]`\n\n    Usage: python3 mesh2tags.py \u003cgame_directory\u003e \u003ctag_type\u003e \u003ctag_id\u003e [\u003cplugin_names...\u003e]\n\n* `game_directory`: path to a Myth game directory\n* `tag_type`: 4 character tag type, e.g. `unit`, `arti`, etc\n* `tag_id`: 4 character tag id, e.g. `spid`, `24am`, etc\n* `plugin_names`: **optional** — if provided loads tags from named plugins\n\n# Global environment variables\n\n* `DEBUG=1` prints extra debug output\n\n# Philosophy\n\nThe goal for this project is to provide tools that are designed to be self contained and run on all architectures for many years to come without dependencies or the need for a build step.\n\nWritten in python (a readable and widely used programming language) and open sourced under an MIT license to make it easy to learn from and adapt without restrictions.\n\nThere have been tools like this before but they historically become incompatible with modern hardware, and with no source code available, are effectively lost to time.\n\n# Compatibility\n\nInitially developed with python 3.13.1 on macOS Sequoia 15.2. Please file an issue if it doesn't work on your platform.\n\n# Thanks\n\nThese tools were developed without access to the Myth source code. Some useful information was found in the source code for [Chaos](https://tain.totalcodex.net/items/show/chaos-source) by TarousZars. Further information thanks to [Project Magma](https://projectmagma.net/) and [Oak](https://www.projectmagma.net/~melekor/oak/) developers.\n\nMostly just figuring things out with [HexFiend](https://github.com/HexFiend/HexFiend).\n\n# Extras\n\n* [hexfiend_templates/](hexfiend_templates/) — Basic *[Binary Templates](https://github.com/HexFiend/HexFiend/blob/master/templates/Tutorial.md)* for HexFiend (macOS) that parse the top level *TFL* and *SB* tag header (doesn't show tag specific headers yet). Copy these to `~/Library/Application Support/com.ridiculousfish.HexFiend/Templates`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwheare%2Fmythextract","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwheare%2Fmythextract","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwheare%2Fmythextract/lists"}