Go library and CLI tools for working with EQOA's ESF/CSF game asset files. Parse, inspect, export, and modify zones, models, textures, animations, and spell effects from EverQuest Online Adventures (PS2).
Browse the ESF object tree, list zones, export meshes to OBJ, decompress CSF files.
# List all zones in TUNARIA
esfextract -list TUNARIA.ESF
# Export Freeport (zone 84) to OBJ
esfextract -zone 84 -o freeport.obj TUNARIA.ESF
# Export collision mesh
esfextract -zone 84 -coll -o freeport_coll.obj TUNARIA.ESF
# Export character models
esfextract -chars -o models.obj CHAR.ESF
# Dump the object tree
esfextract -tree -depth 3 TUNARIA.ESF
# List actors (NPCs, objects) in a zone
esfextract -actors -zone 84 TUNARIA.ESF
# List sprite dictionary
esfextract -sprites CHAR.ESF
# Decompress a CSF to ESF
esfextract -decompress UI.CSFCreate zone overlay patches for the eqoa-pipeline serve system. Patches modify zone data without touching the ISO.
# Color all geometry in zone 84 red
esfpatch -zone 84 -red -o patches/ TUNARIA.ESF
# Scale terrain height by 1.5x
esfpatch -zone 84 -yscale 1.5 -o patches/ game.iso
# Swap the nearest actor's model
esfpatch -zone 84 -swap -x 25245 -z 15699 -newid 0x3950ce16 -o patches/ game.iso
# Raise terrain within 200 units of a point
esfpatch -zone 84 -raise 50 -x 25247 -z 15695 -radius 200 -o patches/ game.iso
# List zone byte ranges
esfpatch -list TUNARIA.ESFOutput: zone_N.json + zone_N.bin overlay pairs. The pipeline serve tool reads these at runtime.
Replace zone geometry with OBJ meshes. Works by replacing existing PrimBuffer data in place (PS2 parser requires fixed node counts).
# List replaceable sprites in a zone
esfimport -list -zone 84 TUNARIA.ESF
# Replace a specific sprite's mesh
esfimport -obj cube.obj -replace 0 -zone 84 -o zone_84.esf TUNARIA.ESF
# Replace all terrain tiles
esfimport -obj terrain.obj -terrain -zone 84 -o zone_84.esf TUNARIA.ESFRebuild a complete ESF file with zone replacements. Adjusts all size headers automatically.
esfrebuild -o TUNARIA-modified.ESF -zones patches/ TUNARIA.ESFDump CPlayList animation data from CSprite models. Useful for debugging animation mapping in custom clients.
# Dump a specific model's playlist by DictID
playlist-dump CHAR.ESF 0x82A69570Shows playlist slot-to-animation mapping, speeds, play-once flags, and upper/lower body pairs.
Reverse-engineer HSpriteAnim (0x2600) binary format. Dumps keyframe data, bone mappings, and playback parameters.
dumpanim CHAR.ESFShows per-animation header (format, numNodes, numFrames, fps, playSpeed, playbackType), per-node quantized quaternion keyframes, and RefMap bone-to-node mappings.
Dump the full bone tree from CSprite character models.
dumpskeleton CHAR.ESFShows parent chains, local/accumulated positions, quaternion rotations, and scale for every bone. Useful for debugging skeletal animation and attachment points.
Parse ParticleDefinition (0xC000) and ParticleDefData (0xC020) from spell effect files.
dumpparticle SPELLFX.ESFDumps per-motif scalar parameters (13 floats), color variables, gradient color tables (32 RGBA entries), and Vec3 fields.
Analyze CSpriteVariant structures for armor/equipment mesh swapping.
dumpvariants CHAR.ESF
variantdump CHAR.ESFdumpvariants shows variant placement tags and texture DictIDs per armor set. variantdump dives deeper into variant header/footer binary structure and mesh counts.
Extract and crop UI atlas textures from UI.ESF.
dumpatlas UI.ESFSaves full atlas PNGs and crops specific UI regions (faces, window corners, bars).
Map TSlotList entries to material indices and equipment slots on character models.
dumptslot CHAR.ESF 0xC698D870Shows which materials correspond to which equipment slots (helm, chest, robe, etc.) with vertex/triangle counts per material.
Search for helmet textures across multiple ESF/CSF files and export slot 7 materials.
helmcheck CHAR.ESF ITEM.CSF CHARCUST.CSF
helmdiag CHAR.ESFhelmcheck cross-references helm DictIDs across files. helmdiag exports slot 7 base textures as PNG for visual inspection.
Extract armor set textures from CHARCUST.CSF and export as PNG.
extract-armor-tex CHARCUST.CSFDecode PS2 SPU2-ADPCM background music files to WAV.
bgmextract music.bgm -o output/Extract EQOA text data and PAK archives. Converts PS2 UTF-16LE strings to UTF-8.
dataextract DATA.PAK -o output/Convert PS2 raw framebuffer images (.16 ABGR1555, .RGB) to PNG.
imgextract image.16 -o output.pngScan ESF/CSF files for MaterialPalette and Material object versions.
survey_mp TUNARIA.ESF CHAR.ESFThe pkg/esf package can be imported by other Go programs:
import "github.com/DabDavis/eqoa-esf-tools/pkg/esf"
// Open any ESF, CSF, or ISO file
file, err := esf.Open("TUNARIA.ESF") // standalone ESF
file, err := esf.Open("game.iso") // auto-detects ISO, reads TUNARIA
file, err := esf.Open("UI.CSF") // auto-decompresses CSF
// Look up objects by DictID
obj, err := file.FindObject(0x82A69570)
cs := obj.(*esf.CSprite)
fmt.Println(cs.PlayList) // animation mappings
fmt.Println(cs.Animations) // skeletal animations
// Walk zones
for _, zone := range file.Zones {
base, _ := zone.GetZoneBase(file) // terrain, collision
actors, _ := zone.GetZoneActors(file) // NPCs, objects
flora, _ := zone.GetRadialFlora(file) // vegetation
}
// Export to OBJ
exporter := esf.NewObjExporter()
placements, _ := zone.GetSpritePlacements(file)
exporter.AddAll(placements, file)
exporter.Write("zone.obj")| Type | Code | Description |
|---|---|---|
| SimpleSprite | 0x1100 | Basic mesh with material |
| GroupSprite | 0x2100 | Multi-part mesh |
| HSprite | 0x2200 | Hierarchical (skeletal) sprite |
| CSprite | 0x2700 | Character sprite with animations, equipment slots |
| LODSprite | 0x2500 | Level-of-detail wrapper |
| PointSprite | 0x2D00 | Point-based particle/effect sprite |
| Zone | 0x6100 | World zone container |
| ZoneTree | 0x3300 | Per-zone spatial quadtree |
| ZoneRooms | 0x3350 | Portal-based room cells |
| WorldTree | 0x3370 | World-level spatial quadtree for zone lookup |
| WorldRegions | 0x3380 | Region metadata |
| ResourceTable | 0x3390 | Named resource hash lookup |
| RadialFlora | 0x32D0 | Procedural vegetation placement |
| PrimBuffer | 0x4000 | GPU vertex/index buffer |
| CollBuffer | 0x4100 | Collision mesh |
| ColorBuffer | 0x4200 | Per-vertex color data |
| Surface | 0x3000 | Texture data |
| Material | 0x3200 | Material properties |
| PointLight | 0x2B10 | Point light source |
| HSpriteAnim | 0x2600 | Skeletal animation |
| Font | 0x7000 | PS2 bitmap font (CLUT + per-char pixel data) |
| SpellEffect | 0x7100 | Spell visual effect |
| EffectVolume | 0xC300 | Fog, dust, leaf effects |
go install github.com/DabDavis/eqoa-esf-tools/cmd/esfextract@latest
go install github.com/DabDavis/eqoa-esf-tools/cmd/esfpatch@latest
go install github.com/DabDavis/eqoa-esf-tools/cmd/esfimport@latest
go install github.com/DabDavis/eqoa-esf-tools/cmd/esfrebuild@latestOr build from source:
git clone https://github.com/DabDavis/eqoa-esf-tools.git
cd eqoa-esf-tools
go build ./cmd/...ESF (EverQuest Sprite File): Binary object tree with typed nodes. Each node has a type code (uint16), version, size, and optional DictID. Nodes contain geometry, textures, materials, animations, and zone layout.
CSF (Compressed Sprite File): zlib-compressed ESF. Tools auto-detect and decompress.
ISO: Game disc image. Tools auto-detect ISOs and read TUNARIA.ESF from the known sector offset (520000).
None — Go stdlib only.