<div align="center">
# π οΈ League Toolkit
**Rust library for parsing, editing, and writing League of Legends file formats**
[](https://github.com/LeagueToolkit/league-toolkit/actions/workflows/ci.yml)
[](https://crates.io/crates/league-toolkit)
[](https://docs.rs/league-toolkit)
[](https://github.com/LeagueToolkit/league-toolkit/blob/main/LICENSE)
[Documentation](https://docs.rs/league-toolkit) β’ [Crates.io](https://crates.io/crates/league-toolkit) β’ [Changelog](CHANGELOG.md)
</div>
---
## β¨ Features
- π¦ **WAD Archives** β Read and write `.wad.client` asset containers
- π¨ **Textures** β Decode/encode `.tex` and `.dds` formats
- π§ **Meshes** β Parse skinned (`.skn`) and static (`.scb`/`.sco`) meshes
- 𦴠**Animation** β Load skeletons (`.skl`) and animations (`.anm`)
- π **Property Bins** β Read/write `.bin` configuration files
- πΊοΈ **Map Geometry** β Parse `.mapgeo` environment assets
- π§ **Modular** β Use individual crates or the umbrella crate
---
## π¦ Installation
Add the umbrella crate to your project:
```toml
[dependencies]
league-toolkit = { version = "0.2", features = ["wad", "mesh", "texture"] }
```
Or use individual crates for a smaller dependency footprint:
```toml
[dependencies]
ltk_wad = "0.2"
ltk_texture = "0.4"
ltk_mesh = "0.3"
```
---
## π Quick Start
### Reading a WAD Archive
```rust
use std::fs::File;
use ltk_wad::Wad;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("assets.wad.client")?;
let mut wad = Wad::mount(file)?;
println!("Archive contains {} files", wad.chunks().len());
// Decode a specific chunk
let (mut decoder, chunks) = wad.decode();
for chunk in chunks.values().take(5) {
let data = decoder.load_chunk_decompressed(chunk)?;
println!("Chunk {:016x}: {} bytes", chunk.path_hash(), data.len());
}
Ok(())
}
```
### Decoding a Texture
```rust
use ltk_texture::Tex;
use std::io::Cursor;
let tex = Tex::from_reader(&mut cursor)?;
let surface = tex.decode_mipmap(0)?;
let image = surface.into_rgba_image()?;
image.save("output.png")?;
```
### Parsing a Skinned Mesh
```rust
use ltk_mesh::SkinnedMesh;
use std::fs::File;
let mesh = SkinnedMesh::from_reader(&mut File::open("champion.skn")?)?;
println!("Vertices: {}", mesh.vertex_buffer().vertex_count());
println!("Submeshes: {}", mesh.ranges().len());
```
### Working with Property Bins
```rust
use ltk_meta::{BinTree, BinTreeObject, value::*};
// Read
let tree = BinTree::from_reader(&mut file)?;
for (hash, object) in &tree.objects {
println!("Object 0x{:08x}", hash);
}
// Create
let tree = BinTree::builder()
.dependency("shared/data.bin")
.object(
BinTreeObject::builder(0x12345678, 0xABCDEF00)
.property(0x1111, I32Value(42))
.build()
)
.build();
```
---
## π Crates
| [`league-toolkit`](https://crates.io/crates/league-toolkit) | Umbrella crate (feature-gated re-exports) | β |
| [`ltk_wad`](https://crates.io/crates/ltk_wad) | WAD archive reading/writing | `.wad.client` |
| [`ltk_texture`](https://crates.io/crates/ltk_texture) | Texture decoding/encoding | `.tex`, `.dds` |
| [`ltk_mesh`](https://crates.io/crates/ltk_mesh) | Skinned & static mesh parsing | `.skn`, `.scb`, `.sco` |
| [`ltk_anim`](https://crates.io/crates/ltk_anim) | Skeleton & animation formats | `.skl`, `.anm` |
| [`ltk_meta`](https://crates.io/crates/ltk_meta) | Property bin files | `.bin` |
| [`ltk_ritobin`](https://crates.io/crates/ltk_ritobin) | Human-readable bin format | ritobin text |
| [`ltk_mapgeo`](https://crates.io/crates/ltk_mapgeo) | Map environment geometry | `.mapgeo` |
| [`ltk_file`](https://crates.io/crates/ltk_file) | File type detection | β |
| [`ltk_hash`](https://crates.io/crates/ltk_hash) | Hash functions (FNV-1a, ELF) | β |
| [`ltk_shader`](https://crates.io/crates/ltk_shader) | Shader path utilities | β |
| [`ltk_primitives`](https://crates.io/crates/ltk_primitives) | Geometric primitives | β |
| [`ltk_io_ext`](https://crates.io/crates/ltk_io_ext) | I/O extensions (internal) | β |
Each crate lives under `crates/<name>`.
---
## βοΈ Feature Flags
The `league-toolkit` umbrella crate uses feature flags to control which subsystems are included:
| `anim` | `ltk_anim` | β
|
| `file` | `ltk_file` | β
|
| `mesh` | `ltk_mesh` | β
|
| `meta` | `ltk_meta` | β
|
| `primitives` | `ltk_primitives` | β
|
| `texture` | `ltk_texture` | β
|
| `wad` | `ltk_wad` | β
|
| `hash` | `ltk_hash` | β
|
| `serde` | Serde support (where available) | β |
For a minimal build, disable defaults and opt-in selectively:
```toml
[dependencies]
league-toolkit = { version = "0.2", default-features = false, features = ["wad"] }
```
### Texture Encoding with `intel-tex`
BC1/BC3 texture encoding requires the optional `intel-tex` feature on `ltk_texture`:
```toml
[dependencies]
league-toolkit = { version = "0.2", features = ["texture"] }
ltk_texture = { version = "0.4", features = ["intel-tex"] }
```
---
## π Documentation
- **[API Documentation](https://docs.rs/league-toolkit)** β Full rustdoc reference
- **[LTK Guide](docs/LTK_GUIDE.md)** β Comprehensive usage guide with examples
---
## π οΈ Development
**Prerequisites:** Rust stable toolchain
```bash
# Build all crates
cargo build
# Run tests
cargo test
# Build documentation
cargo doc --open
```
### Project Structure
```
league-toolkit/
βββ crates/
β βββ league-toolkit/ # Umbrella crate
β βββ ltk_wad/ # WAD archives
β βββ ltk_texture/ # Textures
β βββ ltk_mesh/ # Meshes
β βββ ltk_anim/ # Animation
β βββ ltk_meta/ # Property bins
β βββ ltk_ritobin/ # Ritobin text format
β βββ ltk_mapgeo/ # Map geometry
β βββ ltk_file/ # File detection
β βββ ltk_hash/ # Hashing
β βββ ltk_shader/ # Shader utilities
β βββ ltk_primitives/ # Primitives
β βββ ltk_io_ext/ # I/O extensions
βββ docs/
βββ LTK_GUIDE.md # Usage guide
```
---
## π Releasing
This repository uses [Release-plz](https://release-plz.ieni.dev/) for automated versioning and publishing:
1. Pushes to `main` trigger Release-plz to open a release PR
2. Merging the release PR publishes updated crates to crates.io
---
## π License
Licensed under either of:
- **Apache License, Version 2.0** ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- **MIT License** ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
---
<div align="center">
Made with β€οΈ by the [LeagueToolkit](https://github.com/LeagueToolkit) community
</div>