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};