Skip to main content
Glama
README.md
# L2 Modding MCP

MCP Server for **Lineage 2 / Unreal Engine 2.5** asset modding — 25 tools. Extract, modify, repackage textures (.utx), generate procedural meshes (.usx), parse animations (.ukx), sounds (.uax), and maps (.unr).

## Features

### Textures
- Extract/inspect/import textures from `.utx` packages
- Codec: DXT1/DXT3/DXT5/P8/RGBA8/RGB8/G16 (decode + encode)
- Batch process: grayscale, invert, brightness, contrast, resize, blur, sharpen
- Batch import: folder of PNGs → `.utx` in one step
- Normal map, AO map, specular map generation
- Texture atlas builder (grid packing)
- PBR channel packer (metallic/roughness/AO/height → RGBA)

### 3D Meshes
- Procedural castle generator (towers, walls, battlements, gate, keep, floor)
- StaticMesh serializer for `.usx` packages
- Export to OBJ and FBX ASCII
- Import from OBJ back into the pipeline
- LOD generator (vertex decimation, LOD0–LOD3)
- Collision mesh generator (box, cylinder)
- Procedural heightmap terrain (hills, mountains, plains, island, noise)

### Animations (.ukx)
- Parse AnimationSequence data (frames, bones, tracks)
- Export to BVH format (Blender/Maya compatible)

### Sounds (.uax)
- List sound assets
- Extract sounds to WAV (PCM and embedded WAV)

### Maps (.unr)
- Parse level data: brushes, static meshes, lights, player starts

### Package Management
- Package browser: scan directories for mesh↔texture cross-references
- Package optimizer: remove dead exports, reduce size
- Package comparator: diff two packages

## Installation

```bash
pip install -e .
```

## Usage with opencode

Add to `opencode.json`:

```json
{
  "mcp": {
    "l2-modding": {
      "type": "local",
      "command": ["python", "-m", "l2_mcp.server"],
      "enabled": true
    }
  }
}
```

## MCP Tools (25)

### Textures
| Tool | Description |
|------|-------------|
| `l2_list_package` | List all assets in .utx/.usx/.ukx |
| `l2_list_names` | List name table entries |
| `l2_texture_info` | Detailed texture info (format, mips, palette) |
| `l2_extract_texture` | Extract single texture to PNG |
| `l2_extract_all_textures` | Extract all textures to directory |
| `l2_import_texture` | Replace texture with PNG (repacks .utx) |
| `l2_batch_process` | Batch transform (grayscale, invert, etc.) |
| `l2_batch_import_textures` | Folder of PNGs → .utx |
| `l2_gen_normal_map` | Generate normal/AO/specular map |
| `l2_build_atlas` | Pack textures into atlas grid |
| `l2_pack_pbr` | Pack metallic/roughness/AO/height → RGBA |

### Meshes & Level Design
| Tool | Description |
|------|-------------|
| `l2_create_castle` | Generate procedural 3D castle |
| `l2_generate_textures` | Generate stone/roof/floor/gate textures |
| `l2_create_usx_package` | Export meshes to .usx |
| `l2_export_obj` | Export meshes to OBJ or FBX |
| `l2_import_obj` | Import OBJ → mesh pipeline |
| `l2_generate_lods` | Generate LOD0–LOD3 by decimation |
| `l2_gen_collision` | Generate collision mesh (box/cylinder) |
| `l2_gen_terrain` | Procedural heightmap terrain |

### Animations
| Tool | Description |
|------|-------------|
| `l2_animation_info` | List animations in .ukx |
| `l2_export_animation` | Export animation to BVH |

### Sounds
| Tool | Description |
|------|-------------|
| `l2_list_sounds` | List sounds in .uax |
| `l2_extract_sound` | Extract sound to WAV |
| `l2_extract_all_sounds` | Extract all sounds to WAV |

### Package Management
| Tool | Description |
|------|-------------|
| `l2_compare_packages` | Diff two packages |
| `l2_scan_directory` | Scan L2 folder for mesh↔texture refs |
| `l2_optimize_package` | Strip dead exports, reduce size |
| `l2_parse_map` | Read .unr maps (brushes, actors, lights) |

## Supported Texture Formats

| ID | Format | Description |
|----|--------|-------------|
| 0 | P8 | 256-color paletted |
| 1 | RGBA8 | 32-bit RGBA |
| 3 | DXT1/BC1 | 4 bpp, optional 1-bit alpha |
| 4 | RGB8 | 24-bit RGB |
| 5 | DXT3/BC2 | 8 bpp, explicit alpha |
| 6 | DXT5/BC3 | 8 bpp, interpolated alpha |
| B | G16 | 16-bit grayscale |

## Project Structure

```
src/l2_mcp/
├── server.py          # MCP server (25 tools)
└── upk/
    ├── reader.py      # Binary reader (compact indices, GUIDs)
    ├── package.py     # UPK parser (.utx/.usx/.ukx) + serializer
    ├── texture.py     # DXT codec + texture decode/encode
    ├── writer.py      # Package rebuilder / repacker
    ├── mesh.py        # StaticMesh serializer + primitives
    ├── castle.py      # Procedural castle generator
    ├── obj_io.py      # OBJ/FBX export
    ├── obj_import.py  # OBJ import
    ├── animation.py   # .ukx parser + BVH export
    ├── normal_map.py  # Normal/AO/specular map generator
    ├── batch_builder.py # Batch import + heightmap terrain
    ├── lod.py         # LOD generator + collision mesh
    ├── browser.py     # Package scanner + optimizer
    ├── atlas.py       # Texture atlas + PBR packer
    ├── sound.py       # .uax sound extractor
    └── unr.py         # .unr map parser
```

## License

MIT

TDQS

A3.7/5.0

Scored across 18 tools

Disambiguation5/5

Each tool targets a distinct operation on L2 package assets (listing, extracting, importing, generating, comparing). No overlapping purposes; even similar tools like l2_extract_texture and l2_extract_all_textures are clearly differentiated by scope.

Naming Consistency5/5

All tools follow the 'l2_verb_noun' pattern consistently, using snake_case. Verbs like list, compare, extract, import, generate, create are predictably placed, making the set easy to navigate.

Tool Count5/5

With 18 tools covering textures, meshes, animations, packages, and procedural generation, the count fits the modding domain well. Each tool serves a clear purpose without redundancy.

Completeness4/5

The toolset covers most modding workflows: texture and package management, mesh import/export, animation export, procedural generation. Minor gaps exist (e.g., no animation import/creation, no generic package creation for non-castle assets), but core operations are well-supported.

Maintenance

ActivityInactive
ResponsivenessNo issues