wow_adt/
lib.rs

1//! Two-pass parser for World of Warcraft ADT terrain files using binrw.
2//!
3//! This library implements a clean, type-safe parser for ADT (A Dungeon Terrain) files
4//! from World of Warcraft using the binrw serialization framework. It supports all
5//! ADT format versions from Vanilla (1.12.1) through Mists of Pandaria (5.4.8).
6//!
7//! ## Architecture
8//!
9//! The parser follows a two-pass architecture:
10//!
11//! **Pass 1 (Discovery)**: Fast chunk enumeration without parsing chunk data. Identifies
12//! version, file type, and chunk locations for selective parsing.
13//!
14//! **Pass 2 (Parse)**: Type-safe extraction of chunk data into binrw-derived structures
15//! with automatic offset resolution.
16//!
17//! ## Supported Versions
18//!
19//! - **Vanilla (1.x)** - Basic terrain chunks (MVER, MHDR, MCNK)
20//! - **The Burning Crusade (2.x)** - Flight boundaries (MFBO chunk)
21//! - **Wrath of the Lich King (3.x)** - Enhanced water/lava system (MH2O chunk)
22//! - **Cataclysm (4.x)** - Split file architecture, texture amplifiers (MAMP chunk)
23//! - **Mists of Pandaria (5.x)** - Texture parameters (MTXP chunk)
24//!
25//! Version detection is automatic based on chunk presence and structure analysis.
26//!
27//! ## Quick Start
28//!
29//! ```no_run
30//! use std::fs::File;
31//! use std::io::BufReader;
32//! use wow_adt::{parse_adt, ParsedAdt};
33//!
34//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
35//! // Parse any ADT file with automatic version detection
36//! let file = File::open("world/maps/azeroth/azeroth_32_32.adt")?;
37//! let mut reader = BufReader::new(file);
38//! let adt = parse_adt(&mut reader)?;
39//!
40//! // Access terrain data based on file type
41//! match adt {
42//!     ParsedAdt::Root(root) => {
43//!         println!("Version: {:?}", root.version);
44//!         println!("Terrain chunks: {}", root.mcnk_chunks.len());
45//!         println!("Textures: {}", root.textures.len());
46//!
47//!         // Access water data (WotLK+)
48//!         if let Some(water) = &root.water_data {
49//!             for (idx, entry) in water.entries.iter().enumerate() {
50//!                 if entry.header.has_liquid() {
51//!                     println!("Chunk {} has {} water layer(s)",
52//!                         idx, entry.instances.len());
53//!                 }
54//!             }
55//!         }
56//!     }
57//!     ParsedAdt::Tex0(tex) => {
58//!         println!("Texture file with {} entries", tex.textures.len());
59//!     }
60//!     ParsedAdt::Obj0(obj) => {
61//!         println!("Object file with {} models", obj.models.len());
62//!     }
63//!     _ => {}
64//! }
65//! # Ok(())
66//! # }
67//! ```
68//!
69//! ## Example: Fast Chunk Discovery
70//!
71//! ```no_run
72//! use std::fs::File;
73//! use wow_adt::{discover_chunks, ChunkId};
74//!
75//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
76//! let mut file = File::open("terrain.adt")?;
77//! let discovery = discover_chunks(&mut file)?;
78//!
79//! println!("Total chunks: {}", discovery.total_chunks);
80//!
81//! // Check for specific chunks without full parsing
82//! if discovery.has_chunk(ChunkId::MH2O) {
83//!     println!("File contains advanced water (WotLK+)");
84//! }
85//!
86//! // Selective parsing: only parse specific chunks
87//! for chunk_id in discovery.chunk_types() {
88//!     println!("Found chunk: {}", chunk_id.as_str());
89//! }
90//! # Ok(())
91//! # }
92//! ```
93//!
94//! ## Example: Building ADT Files
95//!
96//! ```no_run
97//! use wow_adt::builder::AdtBuilder;
98//! use wow_adt::{AdtVersion, DoodadPlacement};
99//!
100//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
101//! let adt = AdtBuilder::new()
102//!     .with_version(AdtVersion::WotLK)
103//!     .add_texture("terrain/grass_01.blp")
104//!     .add_texture("terrain/dirt_01.blp")
105//!     .add_model("doodad/tree_01.m2")
106//!     .add_doodad_placement(DoodadPlacement {
107//!         name_id: 0,
108//!         unique_id: 1,
109//!         position: [1000.0, 1000.0, 100.0],
110//!         rotation: [0.0, 0.0, 0.0],
111//!         scale: 1024,
112//!         flags: 0,
113//!     })
114//!     .build()?;
115//!
116//! adt.write_to_file("world/maps/custom/custom_32_32.adt")?;
117//! # Ok(())
118//! # }
119//! ```
120//!
121//! ## Example: Loading Split Files (Cataclysm+)
122//!
123//! ```no_run
124//! use wow_adt::AdtSet;
125//!
126//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
127//! // Load complete split file set (automatically discovers _tex0, _obj0, _lod files)
128//! let adt_set = AdtSet::load_from_path("World/Maps/Azeroth/Azeroth_30_30.adt")?;
129//!
130//! // Check if complete set
131//! if adt_set.is_complete() {
132//!     println!("Complete Cataclysm+ split file set");
133//!     println!("Version: {:?}", adt_set.version());
134//! }
135//!
136//! // Merge split files into unified structure
137//! let merged = adt_set.merge()?;
138//! println!("Merged {} MCNK chunks", merged.mcnk_chunks.len());
139//! println!("Textures: {}", merged.textures.len());
140//! println!("Models: {}", merged.models.len());
141//! # Ok(())
142//! # }
143//! ```
144//!
145//! ## Features
146//!
147//! - **Automatic version detection** - Identifies WoW client version from chunk analysis
148//! - **Split file support** - Cataclysm+ `_tex0`, `_obj0`, `_obj1`, `_lod` file handling
149//! - **Type-safe parsing** - binrw derives for zero-overhead serialization
150//! - **Fast discovery** - <10ms chunk inventory for selective parsing
151//! - **Builder API** - Fluent builder for programmatically constructing ADT files
152//!
153//! ## Modules
154//!
155//! - [`adt_set`] - High-level API for loading complete split file sets (Cataclysm+)
156//! - [`api`] - Core parser API (parse_adt, ParsedAdt enum)
157//! - [`builder`] - Fluent builder API for constructing ADT files
158//! - [`merger`] - Utilities for merging split files into unified structures
159//! - [`split_set`] - Split file discovery and path management
160//! - [`chunk_discovery`] - Discovery phase for fast chunk enumeration
161//! - [`chunk_header`] - ChunkHeader binrw structure (8-byte magic + size)
162//! - [`chunk_id`] - ChunkId type with reversed magic constants
163//! - [`version`] - AdtVersion enum and detection logic
164//! - [`file_type`] - AdtFileType enum (Root, Tex0, Obj0, etc.)
165//! - [`error`] - AdtError types with detailed context
166//! - [`chunks`] - Chunk structure definitions (MVER, MHDR, MCNK, etc.)
167//!
168//! ## References
169//!
170//! Based on information from:
171//! - [WoW.dev ADT Format](https://wowdev.wiki/ADT) - Format specification
172//! - [TrinityCore](https://github.com/TrinityCore/TrinityCore) - Server reference
173//! - [noggit-red](https://github.com/Marlamin/noggit-red) - Map editor reference
174
175// Public API modules
176pub mod adt_set;
177pub mod api;
178pub mod builder;
179pub mod chunk_discovery;
180pub mod chunk_header;
181pub mod chunk_id;
182pub mod chunks;
183pub mod combined_alpha_map;
184pub mod error;
185pub mod file_type;
186pub mod merger;
187pub mod split_set;
188pub mod version;
189
190// Internal parser modules
191pub(crate) mod root_parser;
192pub(crate) mod split_parser;
193
194// Public re-exports for convenience
195pub use adt_set::AdtSet;
196pub use api::{
197    AdtMetadata, LodAdt, McnkChunkObject, McnkChunkTexture, Obj0Adt, ObjectAdt, ParsedAdt, RootAdt,
198    Tex0Adt, TextureAdt, parse_adt, parse_adt_with_metadata,
199};
200pub use builder::{AdtBuilder, BuiltAdt};
201pub use chunk_discovery::{ChunkDiscovery, ChunkLocation, discover_chunks};
202pub use chunk_header::ChunkHeader;
203pub use chunk_id::ChunkId;
204pub use combined_alpha_map::CombinedAlphaMap;
205pub use error::{AdtError, Result};
206pub use file_type::AdtFileType;
207pub use version::AdtVersion;
208
209// Chunk structure re-exports
210pub use chunks::{
211    // MCNK terrain chunks
212    AlphaFormat,
213    AlphaMap,
214    // MH2O water chunks
215    DepthOnlyVertex,
216    // Placement chunks
217    DoodadPlacement,
218    HeightDepthVertex,
219    HeightUvDepthVertex,
220    HeightUvVertex,
221    LiquidType,
222    LiquidVertexFormat,
223    // Simple chunks
224    MampChunk,
225    McalChunk,
226    MccvChunk,
227    McinChunk,
228    McinEntry,
229    MclqChunk,
230    MclyChunk,
231    MclyFlags,
232    MclyLayer,
233    McnkChunk,
234    McnkFlags,
235    McnkHeader,
236    McnrChunk,
237    McrfChunk,
238    McseChunk,
239    McshChunk,
240    McvtChunk,
241    MddfChunk,
242    MfboChunk,
243    Mh2oAttributes,
244    Mh2oChunk,
245    Mh2oEntry,
246    Mh2oHeader,
247    Mh2oInstance,
248    MhdrChunk,
249    // String chunks
250    MmdxChunk,
251    MmidChunk,
252    ModfChunk,
253    MtexChunk,
254    MtxpChunk,
255    MverChunk,
256    MwidChunk,
257    MwmoChunk,
258    SoundEmitter,
259    TextureHeightParams,
260    UvMapEntry,
261    VertexColor,
262    VertexNormal,
263    WmoPlacement,
264};