Metadata-Version: 2.4
Name: pykotor
Version: 2.2.1
Summary: Read, modify and write files used by KotOR's game engine.
Author: Nick Hugi, th3w1zard1
Maintainer-email: th3w1zard1 <boden.crouch@gmail.com>
License: LGPL-3.0-or-later
Project-URL: Homepage, https://github.com/OldRepublicDevs/PyKotor
Project-URL: Changelog, https://github.com/OldRepublicDevs/PyKotor/releases
Project-URL: Documentation, https://github.com/OldRepublicDevs/PyKotor/wiki
Project-URL: Issues, https://github.com/OldRepublicDevs/PyKotor/issues
Project-URL: Repository, https://github.com/OldRepublicDevs/PyKotor.git
Keywords: 2da,bif,bioware,erf,game-files,game-modding,gff,holocron,knights-of-the-old-republic,kotor,kotor1,kotor2,lucasarts,mdl,modding,pykotor,rim,sith-lords,star-wars,tlk,tsl
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Games/Entertainment :: Role-Playing
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: File Formats
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: defusedxml>=0.7
Requires-Dist: ply<4,>=3.11
Provides-Extra: all
Requires-Dist: pykotor[encodings,exp,extra,font,gl,updater]; extra == "all"
Provides-Extra: dev
Requires-Dist: astroid<3.5.0,>=3.2.0; python_version < "3.9" and extra == "dev"
Requires-Dist: astroid>=3.2.0; python_version >= "3.9" and extra == "dev"
Requires-Dist: autoflake>=2.3.1; extra == "dev"
Requires-Dist: mypy-extensions>=1.1.0; python_version >= "3.8" and extra == "dev"
Requires-Dist: mypy<1.10.0,>=1.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: mypy>=1.19.1; python_version >= "3.9" and extra == "dev"
Requires-Dist: pyflakes<3.4.0,>=2.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: pylint<3.3.9,>=2.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-html<4.0.0,>=3.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: pytest-html>=4.2.0; python_version >= "3.9" and extra == "dev"
Requires-Dist: pytest-json-report>=1.5.0; extra == "dev"
Requires-Dist: pytest-metadata<3.0.0,>=2.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: pytest-metadata>=3.1.1; python_version >= "3.9" and extra == "dev"
Requires-Dist: pytest-xdist<3.8.0,>=2.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: pytest-xdist>=3.8.0; python_version >= "3.9" and extra == "dev"
Requires-Dist: pytest>=7.0.0; python_version >= "3.9" and extra == "dev"
Requires-Dist: pytest<8.0.0,>=7.0.0; python_version < "3.9" and extra == "dev"
Requires-Dist: python-dateutil>=2.9.0.post0; extra == "dev"
Requires-Dist: python-dotenv; python_version < "3.9" and extra == "dev"
Requires-Dist: python-dotenv>=1.2.1; python_version >= "3.9" and extra == "dev"
Requires-Dist: python-multipart; python_version < "3.10" and extra == "dev"
Requires-Dist: python-multipart>=0.0.22; python_version >= "3.10" and extra == "dev"
Requires-Dist: ruff>=0.5.3; extra == "dev"
Requires-Dist: ruff<0.6.0,>=0.5.3; python_version < "3.9" and extra == "dev"
Requires-Dist: snakeviz; python_version < "3.9" and extra == "dev"
Requires-Dist: snakeviz>=2.2.2; python_version >= "3.9" and extra == "dev"
Requires-Dist: tomli-w>=1.2.0; python_version > "3.11" and extra == "dev"
Requires-Dist: tomli>=2.4.0; python_version > "3.11" and extra == "dev"
Requires-Dist: tomli>=2.4.0; python_version < "3.11" and extra == "dev"
Requires-Dist: types-cffi>=1.17.0.20250915; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-colorama>=0.4.15.20250801; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-defusedxml>=0.7.0.20250822; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-pillow>=10.2.0.20240822; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-psutil>=7.2.2.20260130; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-pywin32>=38; (python_version >= "3.9" and sys_platform == "win32") and extra == "dev"
Requires-Dist: types-pyyaml>=6.0.12.20250915; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-requests>=2.32.4.20260107; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-send2trash>=2.1.0.20260117; python_version >= "3.9" and extra == "dev"
Requires-Dist: types-setuptools>=80.10.0.20260124; python_version >= "3.9" and extra == "dev"
Requires-Dist: typing-extensions<4.9.0,>=4.5.0; python_version < "3.9" and extra == "dev"
Requires-Dist: typing-extensions>=4.15.0; python_version >= "3.9" and extra == "dev"
Requires-Dist: typing-inspection>=0.4.2; python_version >= "3.9" and extra == "dev"
Provides-Extra: encodings
Requires-Dist: charset-normalizer<3.4,>=2.0; python_version < "3.9" and extra == "encodings"
Requires-Dist: charset-normalizer>=2.0; python_version >= "3.9" and extra == "encodings"
Provides-Extra: exp
Requires-Dist: fusepy>=3.0.1; extra == "exp"
Requires-Dist: pywin32>=38; sys_platform == "win32" and extra == "exp"
Provides-Extra: extra
Requires-Dist: PyYAML>=6.0; extra == "extra"
Requires-Dist: colorama>=0.4.6; extra == "extra"
Requires-Dist: comtypes>=1.4.0; sys_platform == "win32" and extra == "extra"
Requires-Dist: gputil>=1.4.0; extra == "extra"
Requires-Dist: psutil>=7.2.2; extra == "extra"
Provides-Extra: font
Requires-Dist: pillow<11.1.0,>10; platform_python_implementation == "PyPy" and extra == "font"
Requires-Dist: pillow>=9.5; platform_python_implementation == "CPython" and extra == "font"
Provides-Extra: gl
Requires-Dist: PyGLM<2.8,>=2.0; platform_python_implementation == "CPython" and extra == "gl"
Requires-Dist: PyOpenGL>=3.1; extra == "gl"
Requires-Dist: numpy>=1.22; extra == "gl"
Provides-Extra: gl-exp
Requires-Dist: moderngl; extra == "gl-exp"
Provides-Extra: updater
Requires-Dist: certifi>=2021.10.8; extra == "updater"
Requires-Dist: pycryptodome>=3.19.0; extra == "updater"
Requires-Dist: requests<2.32.0,>=2.25.0; python_version < "3.9" and extra == "updater"
Requires-Dist: requests>=2.25.0; python_version >= "3.9" and extra == "updater"
Dynamic: license-file
Dynamic: requires-python

# PyKotor

[![PyPI](https://img.shields.io/pypi/v/pykotor.svg)](https://pypi.org/project/pykotor/)
[![docs](https://img.shields.io/badge/docs-wiki-blue.svg)](https://github.com/OldRepublicDevs/PyKotor/wiki)
[![license: LGPL v3+](https://img.shields.io/badge/license-LGPL%20v3%2B-lightgrey.svg)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![CI](https://github.com/OldRepublicDevs/PyKotor/actions/workflows/ci.yml/badge.svg)](https://github.com/OldRepublicDevs/PyKotor/actions/workflows/ci.yml)
[![pre-commit](https://results.pre-commit.ci/badge/github/OldRepublicDevs/PyKotor/main.svg)](https://results.pre-commit.ci/latest/github/OldRepublicDevs/PyKotor/main)

**PyKotor** is a modern Python library and toolset for reading, writing, and modding resources from the Star Wars: Knights of the Old Republic (KOTOR, K1) and The Sith Lords (KOTOR II, TSL) game engines.

---

## Features

- Read and write almost all K1/TSL resource and file formats (BIF, ERF, GFF, KEY, TLK, DLG, UTC, UTP, UTI, UTS, etc.)
- Support for both K1 (*swkotor.exe*) and TSL (*swkotor2.exe*) with unified APIs
- High-fidelity, reverse-engineered format logic and type safety
- Command-line toolkit (`pykotorcli`) for file conversion, inspection, and batch operations
- Programmatic API for advanced automation and mod tooling
- Modern, type-checked, actively maintained, and well-tested codebase

## Documentation & Community

- 📚 **Docs / Usage:** [Wiki & Getting Started](https://github.com/OldRepublicDevs/PyKotor/wiki)
- 🐛 **Bugs:** [GitHub Issues](https://github.com/OldRepublicDevs/PyKotor/issues)
- 💬 **Community Discord:** [Invite Link](https://discord.gg/4bEyeF3)
- 🌟 **Changelog:** [Releases](https://github.com/OldRepublicDevs/PyKotor/releases)

## Quick Install

```bash
pip install pykotor
```

Or with extras for format encodings and update tool:
```bash
pip install "pykotor[encodings,updater]"
```

## CLI Example

```bash
# Convert a BIF file to readable resources
pykotorcli extract-bif --input KOTOR1/BIFs/data.bif --output ./output_dir

# Inspect a GFF (generic file format)
pykotorcli gff-dump --file some_file.uti

# See all CLI features
pykotorcli --help
```

## Python Usage Example

```python
from pykotor.tsl.gff import GFF

# Parse a .utc (creature) file
gff = GFF.parse("dan13_01.utc")
print(gff.root["FirstName"].string)  # Accessing the field value

# Modify and save
gff.root["FirstName"].string = "HK-47"
gff.write("hk_utc.gff")
```

## Supported Formats

Major types:
- Containers: BIF, ERF, KEY, MOD, RIM
- Resources: GFF/UT*, GIT, DLG, ARE, UTP, UTI, UTC, UTS, UTM, UTR, UTT, JRL, TLK, etc.
- 2DA, SSF, NCS/NSS, NDB, models, textures, etc.
See [Wiki Format Coverage](https://github.com/OldRepublicDevs/PyKotor/wiki/Format-Support-Matrix).

## Development & Contributing

1. Clone the repo and install [Poetry](https://python-poetry.org/) or use `uv`.
2. `poetry install` or `uv pip install -e .[dev]`
3. Run `pytest` and `ruff check .` and `mypy --strict` before submitting PRs.

For feature requests, new formats, or reverse-engineering findings, see [CONTRIBUTING.md](https://github.com/OldRepublicDevs/PyKotor/blob/master/CONTRIBUTING.md).

---

## License

LGPL-3.0-or-later (see [LICENSE](https://github.com/OldRepublicDevs/PyKotor/blob/master/LICENSE))

---

> This project follows unified K1/TSL reverse engineering practices. All resource logic is verified across both game engines using REVA MCP tools. See the [Wiki](https://github.com/OldRepublicDevs/PyKotor/wiki/Reverse-Engineering-Workflow) for details on our protocol.


