wowlib 0.0.0
Read & write World of Warcraft client files — a C++26 core
Loading...
Searching...
No Matches
wdl.hpp
Go to the documentation of this file.
1#pragma once
2
18
19#include <algorithm>
20#include <cstdint>
21#include <cstring>
22#include <format>
23#include <optional>
24#include <span>
25#include <string>
26#include <vector>
27
30#include <wowlib/core/error.hpp>
32#include <wowlib/core/lang.hpp>
44
45namespace wowlib::formats::wdl {
46 using namespace wowlib::formats::wdl::chunks;
47
57 struct [[
58 =welder::weld,
59 =welder::weld_as("WDL"),
61 =welder::doc(R"(
62 A map's low-resolution heightmap file, abstract over the client
63 version — the background mountain silhouettes. Construct the concrete
64 version with WDL.for_version(expansion), then read()/write(); the
65 per-version WDL* classes are subclasses. See
66 https://wowdev.wiki/WDL.)")
67 ]] WDLBase : FileEntityBase {};
68
69 namespace detail {
70 // --- version-range trait bases (unwelded) ---------------------------------
71 // One struct per availability range; members keep their chunk/since/until/
72 // doc/marks (read off the declaring class, so flattening preserves them).
75 struct WdlPreLegion {
76 [[
81 =welder::doc(
82 R"(Per-tile occlusion mesh vertices (MAOC, pre-Legion; optional
83 and absent from every surveyed file), one record per
84 occurrence, kept opaque. Follows its tile's heightmap in the
85 stream.)")]]
86 std::vector<ChunkBlob> occlusionMeshes;
87 };
90 struct WdlTbc {
91 [[
92 =chunk("MAHO"),
96 =welder::mark::no_reassign,
97 =welder::doc(
98 R"(Per-tile hole masks (MAHO, TBC+): the i-th mask belongs to
99 the i-th heightmap. Blizzard writes one per tile even when
100 all zero; hole masks are all-or-nothing — leave the list
101 empty or give every heightmap its mask. (wowdev.wiki dates
102 MAHO to WotLK, but vanilla WDLs carry none and every 2.4.3
103 WDL pairs one MAHO per MARE — so it debuts in TBC.))")]]
104 std::vector<TileHoles> holes;
105 };
108 struct WdlLegion {
109 [[
110 =chunk("MLDD"),
113 =welder::mark::no_reassign,
114 =welder::doc(
115 R"(Low-resolution M2 placements (MLDD, Legion+), drawn instead
116 of the far-away real models; name_id is always a
117 FileDataID here.)")]]
118 std::vector<SMDoodadDef> lodDoodads;
119
120 [[
121 =chunk("MLDX"),
124 =welder::mark::no_reassign,
125 =welder::doc(
126 R"(Visibility extents for the M2 placements (MLDX, Legion+);
127 same count and order as lod_doodads.)")]]
128 std::vector<LodExtent> lodDoodadExtents;
129
130 [[
131 =chunk("MLMD"),
134 =welder::mark::no_reassign,
135 =welder::doc(R"(Low-resolution WMO placements (MLMD, Legion+); sorted by
136 their extent radius, largest first, in shipped files.)")
137 ]]
138 std::vector<LodMapObjDef> lodMapObjects;
139
140 [[
141 =chunk("MLMX"),
144 =welder::mark::no_reassign,
145 =welder::doc(
146 R"(Visibility extents for the WMO placements (MLMX, Legion+);
147 same count and order as lod_map_objects.)")]]
148 std::vector<LodExtent> lodMapObjectExtents;
149
150 [[
151 =chunk("MAOE"),
155 =welder::mark::no_reassign,
156 =welder::doc(
157 R"(Sparse per-tile ocean masks (MAOE, Legion+), emitted between
158 a tile's heightmap and its hole mask — only SOME tiles have
159 one, so use ocean_mask_tiles() for the mask -> heightmap
160 pairing.)")]]
161 std::vector<TileOcean> oceanMasks;
162 };
163
165 struct WdlBfA {
166 [[
167 =chunk("MLDF"),
170 =welder::mark::no_reassign,
171 =welder::doc(R"(Fade-distance ranges for the M2 placements (MLDF, BfA);
172 same count and order as lod_doodads. Undocumented on
173 wowdev; the layout and the BfA (not Shadowlands) debut
174 are survey findings across every 8.3.7 WDL carrying the
175 chunk.)")]]
176 std::vector<LodDoodadFade> lodDoodadFades;
177
178 [[
179 =chunk("MLMB"),
182 =welder::mark::no_reassign,
183 =welder::doc(R"(One byte per WMO placement (MLMB, BfA; same count and
184 order as lod_map_objects — the ADT twin pairs with
185 MODF in _obj0 and MLMD in _obj1). Semantics unknown;
186 the 8.3.7 fleet survey (1300+ instances) shows an
187 enum-like value set (0x19/0x20/0x26/0x33/0x40/0x46/
188 0x80) that clusters per map, varies per instance of
189 the same asset, and does not correlate with the
190 placement radius; 0x80 co-occurs with other values on
191 the same asset like an override state.)")]]
192 std::vector<std::uint8_t> mlmb;
193 };
194
196 struct WdlSL {
197 [[
198 =chunk("MLDL"),
201 =welder::mark::no_reassign,
202 =welder::doc(
203 R"(MLDL (9.x+): per-lod_doodads values, engaged by placement
204 flag 0x8 (as the ADT chunk of the same name).)")]]
205 std::vector<std::uint32_t> mldl;
206
207 [[
208 =chunk("MLDB"),
211 =welder::doc("MLDB (9.x+, undocumented); preserved opaque.")]]
213
214 [[
215 =chunk("MSSN"),
218 =welder::mark::no_reassign,
219 =welder::doc("Sky scenes (MSSN, Shadowlands+).")]]
220 std::vector<SkyScene> skyScenes;
221
222 [[
223 =chunk("MSSC"),
226 =welder::mark::no_reassign,
227 =welder::doc("Sky-scene conditions (MSSC, Shadowlands+), ranged by the "
228 "scenes' condition_index/count.")]]
229 std::vector<SkySceneCondition> skySceneConditions;
230
231 [[
232 =chunk("MSSO"),
235 =welder::mark::no_reassign,
236 =welder::doc(
237 "Sky-scene objects (MSSO, Shadowlands+), ranged by the scenes' "
238 "object_index/count.")]]
239 std::vector<SkySceneObject> skySceneObjects;
240
241 [[
242 =chunk("MSSF"),
245 =welder::mark::no_reassign,
246 =welder::doc(
247 R"(Sky-scene object params (MSSF; wowdev dates it Dragonflight+
248 but 9.2.7 files carry it), referenced by the objects'
249 params_index.)")]]
250 std::vector<SkySceneObjectParams> skySceneObjectParams;
251 };
252
254 struct WdlTww {
255 [[
256 =chunk("MSLD"),
259 =welder::mark::no_reassign,
260 =welder::doc("Scene-living definitions (MSLD, The War Within+).")]]
261 std::vector<SceneLivingDef> sceneLivingDefs;
262
263 [[
264 =chunk("MSLI"),
267 =welder::mark::no_reassign,
268 =welder::doc(
269 "Scene-living indices (MSLI, The War Within+): one MSLD index "
270 "per sky-scene object.")]]
271 std::vector<std::int32_t> sceneLivingIndices;
272 };
273 }
274
275 namespace detail {
286 @tparam V the client version this layout targets.
287 @see https://wowdev.wiki/WDL */
288 template <ClientVersion V>
289 struct [[
290 =welder::weld,
291 =welder::doc(R"(
292 A map's low-resolution heightmap file for one client version: the
293 64x64 tile offset table, one 17x17+16x16 int16 heightmap (and hole
294 mask) per present tile, the low-resolution object placements of the
295 era, and the Shadowlands+ sky scenes. Tile chunks pair by ordinal —
296 the i-th heightmap belongs to the i-th nonzero tileOffsets slot
297 (row-major); the offsets themselves are recomputed on every write,
298 so only the nonzero pattern is authored data. An instance read from
299 a client file rewrites byte-for-byte until modified. See
300 https://wowdev.wiki/WDL.)")
301 ]] WDL
303 WDLBase,
310 static constexpr ClientVersion Version = V;
311
312 [[
313 =chunk("MVER"),
314 =welder::doc("The WDL format version; 18 for every supported client.")]]
315 std::uint32_t mver = WdlVersion18;
316
317 [[
318 =chunk("MWMO"),
320 =welder::doc(
321 R"(WMO silhouette filenames (MWMO): zero-terminated strings,
322 referenced by offset. Every pre-Legion file carries the
323 chunk (often empty); Legion+ terrain maps replace the
324 object set with the MLDD/MLMD placements, but WMO-only
325 maps keep shipping it.)")]]
327
328 [[
329 =chunk("MWID"),
331 =welder::mark::no_reassign,
332 =welder::doc("MWMO filename start offsets (MWID), one per name.")]]
333 std::vector<std::uint32_t> wmoFilenameOffsets;
334
335 [[
336 =chunk("MODF"),
338 =welder::mark::no_reassign,
339 =welder::doc(
340 "WMO silhouette placements (MODF), one per MWMO name; the same "
341 "64-byte record the WDT and ADT use.")]]
342 std::vector<SMMapObjDef> wmoPlacements;
343
344 [[
345 =chunk("MAOF"),
346 =welder::mark::no_reassign,
347 =welder::doc(
348 R"(The tile offset table (MAOF): 64 x 64 absolute file offsets
349 in row-major order (y outer, x inner), 0 for absent tiles.
350 The offset VALUES are derived — every write restamps them
351 from the finished layout — so only the nonzero pattern is
352 authored: the i-th nonzero slot owns the i-th heightmap.)")
353 ]]
354 std::vector<std::uint32_t> tileOffsets;
355
356 [[
357 =chunk("MARE"),
360 =welder::mark::no_reassign,
361 =welder::doc(
362 R"(The per-tile heightmaps (MARE), one per nonzero tileOffsets
363 slot, in row-major slot order.)")]]
364 std::vector<TileHeights> heightmaps;
365
370 static constexpr std::array ChunkOrder = {
371 fourcc("MVER"),
372 fourcc("MWMO"),
373 fourcc("MWID"),
374 fourcc("MODF"),
375 fourcc("MLDD"),
376 fourcc("MLDX"),
377 fourcc("MLDF"),
378 fourcc("MLDL"),
379 fourcc("MLDB"),
380 fourcc("MLMD"),
381 fourcc("MLMX"),
382 fourcc("MLMB"),
383 fourcc("MSSN"),
384 fourcc("MSSC"),
385 fourcc("MSSO"),
386 fourcc("MSSF"),
387 fourcc("MSLD"),
388 fourcc("MSLI"),
389 fourcc("MAOF"),
390 fourcc("MARE"),
391 fourcc("MAOC"),
392 fourcc("MAOE"),
393 fourcc("MAHO"),
394 };
395
400 [[=welder::doc(
401 R"(The heightmap ordinal each ocean mask belongs to (parallel
402 to oceanMasks), derived from the read file's chunk
403 interleave. Empty when there are no ocean masks.)"),
404 =welder::returns("one heightmap ordinal per ocean mask")]]
405 std::vector<std::uint32_t> oceanMaskTiles() const;
406
414 [[=welder::mark::exclude]]
415 void validateExtra(ValidationReport& report) const;
416
425 [[=welder::mark::exclude]]
427 resequencedJournal() const;
428
434 [[=welder::mark::exclude]]
435 Result<void> patchFile(std::span<std::byte> image) const;
436
437 [[=welder::mark::only(welder::lang::lua, wowlib::lang::Cs),
438 =welder::doc("Load the WDL from a client filesystem, replacing this "
439 "entity's contents.")]]
440 Result<void> read(fs::FileSystem& fs [[=welder::doc("the filesystem gateway")]],
441 const FileKey& key [[=welder::doc("the file identity (path and/or FileDataID)")]]);
442
443 [[=welder::mark::only(welder::lang::lua, wowlib::lang::Cs),
444 =welder::doc(
445 "Serialize and store the WDL through the filesystem's project "
446 "overlay.")]]
447 Result<void> write(fs::FileSystem& fs [[=welder::doc("the filesystem gateway")]],
448 const FileKey& key [[=welder::doc("the file identity; must resolve to a path")]]) const;
449
450 // the inherited ChunkedFile read(span)/write() stay available for
451 // buffer-level access
454 };
455 }
456
461 template <ClientVersion V>
463}
464
465// --- method definitions -------------------------------------------------------
466// Inline in this header: the entity is a template, so the definitions must be
467// visible for implicit instantiation — the library ships NO explicit
468// instantiations; the bindings expand the full matrix in their own TUs.
469namespace wowlib::formats::wdl {
470 template <ClientVersion V>
471 std::vector<std::uint32_t> detail::WDL<V>::oceanMaskTiles() const {
472 std::vector<std::uint32_t> out;
473 if constexpr (requires { this->oceanMasks; }) {
474 constexpr auto mareIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MARE"));
475 constexpr auto maoeIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MAOE"));
476 const std::size_t n = this->oceanMasks.size();
477 if (n == 0) return out;
478 out.reserve(n);
479 std::size_t maresSeen = 0;
480 for (const JournalEntry& entry : this->journal) {
481 if (entry.member == mareIdx) ++maresSeen;
482 else if (entry.member == maoeIdx && out.size() < n)
483 out.push_back(maresSeen == 0 ? 0 : static_cast<std::uint32_t>(maresSeen - 1));
484 }
485 if (out.size() != n) {
486 // fresh entity (or masks added since the read): the identity pairing
487 out.clear();
488 const std::size_t last = heightmaps.empty() ? 0 : heightmaps.size() - 1;
489 for (std::size_t i = 0; i < n; ++i) out.push_back(static_cast<std::uint32_t>(std::min(i, last)));
490 }
491 }
492 return out;
493 }
494
495 template <ClientVersion V>
496 void detail::WDL<V>::validateExtra(ValidationReport& report) const {
497 const std::size_t nTiles = heightmaps.size();
498 std::size_t engagedSlots = 0;
499 for (const std::uint32_t offset : tileOffsets) engagedSlots += (offset != 0);
500
501 // MAOF is a fixed 64x64 slot table; a zero slot means "no tile here"
502 if ((nTiles != 0 || engagedSlots != 0) && tileOffsets.size() != WdlTileSlots)
503 report.addError("tileOffsets",
504 std::format(
505 "the MAOF table holds {} offsets, not 64*64 — resize " "tileOffsets to {} (0 = tile absent)",
506 tileOffsets.size(), WdlTileSlots));
507 if (engagedSlots != nTiles)
508 report.addError("heightmaps",
509 std::format(
510 "{} nonzero tileOffsets slots but {} heightmaps — the "
511 "i-th nonzero slot owns the i-th heightmap, so the " "counts must match", engagedSlots,
512 nTiles));
513
514 if constexpr (requires { this->holes; })
515 if (!this->holes.empty() && this->holes.size() != nTiles)
516 report.addError("holes", std::format(
517 "{} hole masks but {} heightmaps — hole masks are "
518 "all-or-nothing (empty, or one per heightmap)", this->holes.size(), nTiles));
519 if constexpr (requires { this->oceanMasks; })
520 if (this->oceanMasks.size() > nTiles)
521 report.addError("oceanMasks", std::format(
522 "{} ocean masks but only {} heightmaps", this->oceanMasks.size(), nTiles));
523 if constexpr (requires { this->occlusionMeshes; })
524 if (this->occlusionMeshes.size() > nTiles)
525 report.addError("occlusionMeshes",
526 std::format("{} occlusion meshes but only {} heightmaps", this->occlusionMeshes.size(),
527 nTiles));
528 }
529
530 template <ClientVersion V>
532 constexpr auto mareIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MARE"));
533 constexpr auto mahoIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MAHO"));
534 constexpr auto maoeIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MAOE"));
535 constexpr auto maocIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MAOC"));
536 constexpr auto maofIdx = formats::detail::chunkMemberIndex<WDL>(fourcc("MAOF"));
537
538 const auto journalCount = [&](std::int32_t index) -> std::size_t {
539 if (index < 0) return 0;
540 std::size_t n = 0;
541 for (const JournalEntry& entry : this->journal) n += (entry.member == index);
542 return n;
543 };
544
545 const std::size_t nTiles = heightmaps.size();
546 std::size_t nHoles = 0;
547 std::size_t nOcean = 0;
548 std::size_t nOcclusion = 0;
549 if constexpr (requires { this->holes; }) nHoles = this->holes.size();
550 if constexpr (requires { this->oceanMasks; }) nOcean = this->oceanMasks.size();
551 if constexpr (requires { this->occlusionMeshes; }) nOcclusion = this->occlusionMeshes.size();
552
553 // the stored journal still matches the tile data: replay it as-is
554 if (!this->journal.empty() && journalCount(mareIdx) == nTiles && journalCount(mahoIdx) == nHoles &&
555 journalCount(maoeIdx) == nOcean && journalCount(maocIdx) == nOcclusion) return std::optional<std::vector<
556 JournalEntry>>{};
557
558 // rebuild path: the layout below only makes sense once the tile-table
559 // pairing holds, so require it through the same hook validate() uses
560 {
561 ValidationReport report;
562 validateExtra(report);
563 if (auto r = report.toResult(); !r) return std::unexpected{r.error()};
564 }
565
566 // Per-tile attachment of the sparse chunks (MAOE/MAOC): pair through the
567 // stored journal's interleave when it still covers them, else the
568 // identity pairing (i-th mask -> i-th tile).
569 const auto attach = [&](std::int32_t index, std::size_t count) {
570 std::vector<std::vector<std::uint32_t>> per(nTiles);
571 if (nTiles == 0 || count == 0) return per;
572 if (journalCount(index) == count) {
573 std::size_t maresSeen = 0;
574 bool paired = true;
575 for (const JournalEntry& entry : this->journal) {
576 if (entry.member == mareIdx) ++maresSeen;
577 else if (entry.member == index) {
578 if (maresSeen == 0 || entry.occurrence >= count) {
579 paired = false;
580 break;
581 }
582 per[std::min(maresSeen - 1, nTiles - 1)].push_back(entry.occurrence);
583 }
584 }
585 if (paired) return per;
586 per.assign(nTiles, {});
587 }
588 for (std::size_t i = 0; i < count; ++i) per[std::min(i, nTiles - 1)].push_back(static_cast<std::uint32_t>(i));
589 return per;
590 };
591 const auto occlusionPerTile = attach(maocIdx, nOcclusion);
592 const auto oceanPerTile = attach(maoeIdx, nOcean);
593
594 // every non-tile chunk in canonical order, ...
595 auto out = formats::detail::freshJournal(*this);
596 std::erase_if(out, [&](const JournalEntry& entry) {
597 return entry.member == mareIdx || (mahoIdx >= 0 && entry.member == mahoIdx) || (maoeIdx >= 0 && entry.member
598 == maoeIdx) || (maocIdx >= 0 && entry.member == maocIdx);
599 });
600
601 // ... then the interleaved tile block right after MAOF, ...
602 std::size_t insertAt = out.size();
603 for (std::size_t i = 0; i < out.size(); ++i)
604 if (out[i].member == maofIdx) {
605 insertAt = i + 1;
606 break;
607 }
608 std::vector<JournalEntry> block;
609 for (std::size_t tile = 0; tile < nTiles; ++tile) {
610 block.push_back({fourcc("MARE"), mareIdx, static_cast<std::uint32_t>(tile)});
611 for (const std::uint32_t occurrence : occlusionPerTile[tile]) block.push_back({
612 fourcc("MAOC"),
613 maocIdx,
614 occurrence
615 });
616 for (const std::uint32_t occurrence : oceanPerTile[tile]) block.push_back({
617 fourcc("MAOE"),
618 maoeIdx,
619 occurrence
620 });
621 if (tile < nHoles)
622 block.push_back({fourcc("MAHO"), mahoIdx, static_cast<std::uint32_t>(tile)});
623 }
624 out.insert(out.begin() + static_cast<std::ptrdiff_t>(insertAt), block.begin(), block.end());
625
626 // ... and the preserved unknown chunks last, in their stored order
627 for (const JournalEntry& entry : this->journal)
628 if (entry.member < 0) out.push_back(entry);
629 return std::optional{std::move(out)};
630 }
631
632 template <ClientVersion V>
633 Result<void> detail::WDL<V>::patchFile(std::span<std::byte> image) const {
634 constexpr std::uint32_t maofCc = fourcc("MAOF");
635 constexpr std::uint32_t mareCc = fourcc("MARE");
636
637 std::size_t maofPayload = image.size();
638 std::uint32_t maofSize = 0;
639 std::vector<std::uint32_t> mareOffsets;
640 std::size_t pos = 0;
641 while (image.size() - pos >= 2 * sizeof(std::uint32_t)) {
642 std::uint32_t fourcc = 0;
643 std::uint32_t size = 0;
644 std::memcpy(&fourcc, image.data() + pos, sizeof fourcc);
645 std::memcpy(&size, image.data() + pos + sizeof fourcc, sizeof size);
646 if (size > image.size() - pos - 2 * sizeof(std::uint32_t)) break; // the preserved trailing-bytes region
647 if (fourcc == maofCc && maofPayload == image.size()) {
648 maofPayload = pos + 2 * sizeof(std::uint32_t);
649 maofSize = size;
650 }
651 else if (fourcc == mareCc) mareOffsets.push_back(static_cast<std::uint32_t>(pos));
652 pos += 2 * sizeof(std::uint32_t) + size;
653 }
654
655 if (mareOffsets.empty() && maofSize == 0) return {}; // no tiles and no table: nothing to stamp
656 if (maofPayload == image.size())
657 return makeError(ErrorCode::InvalidEntityState, "heightmap chunks without a MAOF table to point at them");
658 if (maofSize != WdlTileSlots * sizeof(std::uint32_t))
660 std::format(
661 "the written MAOF table holds {} bytes, not 64*64 " "offsets — resize tileOffsets to {}",
662 maofSize, WdlTileSlots));
663
664 std::size_t next = 0;
665 for (std::size_t slot = 0; slot < WdlTileSlots; ++slot) {
666 std::uint32_t value = 0;
667 std::byte* at = image.data() + maofPayload + slot * sizeof value;
668 std::memcpy(&value, at, sizeof value);
669 if (value == 0) continue;
670 if (next >= mareOffsets.size())
672 std::format("more nonzero tileOffsets slots than the {} written " "heightmaps",
673 mareOffsets.size()));
674 std::memcpy(at, &mareOffsets[next++], sizeof value);
675 }
676 if (next != mareOffsets.size())
678 std::format("{} written heightmaps but only {} nonzero tileOffsets " "slots",
679 mareOffsets.size(), next));
680 return {};
681 }
682
683 template <ClientVersion V>
684 Result<void> detail::WDL<V>::read(fs::FileSystem& fs, const FileKey& key) {
685 const auto data = fs.readFile(key);
686 if (!data) return std::unexpected{data.error()};
687 *this = WDL{};
688 if (auto r = ChunkedFile<WDL>::read(*data); !r) return std::unexpected{r.error()};
689 if (mver != WdlVersion18)
691 std::format("WDL MVER is {}, expected {}", mver, WdlVersion18));
692 return {};
693 }
694
695 template <ClientVersion V>
696 Result<void> detail::WDL<V>::write(fs::FileSystem& fs, const FileKey& key) const {
697 const FileKey resolved = fs.resolve(key);
698 if (!resolved.path)
699 return makeError(ErrorCode::PathNotResolvable, "saving a WDL needs a path for the file key");
700 const auto data = ChunkedFile<WDL>::write();
701 if (!data) return std::unexpected{data.error()};
702 if (auto r = fs.addFile(*resolved.path, *data); !r) return std::unexpected{r.error()};
703 return {};
704 }
705}
The chunk framework, vocabulary and engine in one header.
void addError(std::string path, std::string message)
Record an error finding (see add()).
FileKey resolve(const FileKey &key) const
Result< FileBuffer > readFile(const FileKey &key)
Result< FileDataID > addFile(std::string_view path, std::span< const std::byte > content)
Named ClientVersion constants for the exact client builds format features appeared (or vanished) at —...
Client version identity, the flavor axis that separates a client's CONTENT version from the engine ge...
The error-handling vocabulary: ErrorCode, Error and the Result<T> alias every fallible wowlib operati...
File identity types: the strong FileDataID and the FileKey a read request travels as.
The runtime facade over the static compositions — the primary welder binding surface of the fs layer.
FourCC chunk identifiers: compile-time conversion of the four-letter codes to the host integers chunk...
Binding-language identities welder's core does not name.
#define WOWLIB_CS_FAMILY_SURFACE
The C# rod's family-surface opt-in, spellable in every build.
Definition lang.hpp:44
The map-placement binary records SHARED across the world file formats (namespace wowlib::formats::com...
constexpr ClientVersion SL
shadowlands (any 9.x client).
constexpr ClientVersion Legion
legion (any 7.x client).
constexpr ClientVersion TWW
The War Within (any 11.x client).
constexpr ClientVersion BfA
Battle for Azeroth (any 8.x client).
constexpr ClientVersion TBC
The Burning Crusade (any 2.x client).
std::vector< JournalEntry > freshJournal(const E &entity)
The journal a FRESH write of entity would produce: one entry per engaged (or required) chunk member i...
consteval std::int32_t chunkMemberIndex(std::uint32_t magic)
The flattened member index (a JournalEntry::member value) of the chunk member carrying magic,...
detail::WDL< canonicalVersion(V, WdlPivots, WdlVersions)> WDL
A WDL low-resolution heightmap — the canonicalizing face of detail::WDL: every client version maps to...
Definition wdl.hpp:276
constexpr std::array WdlPivots
WDL: every chunk-set change point (see the file comment).
constexpr std::array WdlVersions
The versions WDL is instantiated (and welded) for: every targeted last-minor-of-major release,...
constexpr std::size_t WdlTileSlots
The MAOF tile table's slot count: one per map tile of the 64x64 grid, row-major, a zero offset meanin...
constexpr std::uint32_t WdlVersion18
The WDL format version every supported client uses (MVER payload).
constexpr std::uint32_t fourcc(const char(&cc)[5], FourCCEndian endian=FourCCEndian::Reversed)
The host integer a scanned chunk id compares equal to for code cc.
Definition fourcc.hpp:33
constexpr ClientVersion canonicalVersion(ClientVersion v, std::span< const ClientVersion > pivots, std::span< const ClientVersion > grid)
The canonical version v collapses to: the FIRST grid version in v's range.
constexpr detail::RepeatingSpec Repeating
Mark a chunk that appears once PER ELEMENT of a std::vector<Element> member, any number of times: eac...
constexpr detail::OptionalSpec Optional
Mark a chunk member the format does not require: absence on read is fine.
consteval detail::UntilSpec until(ClientVersion v)
Restrict a member to entity versions < v (exclusive).
consteval detail::ChunkSpec chunk(const char(&cc)[5], FourCCEndian endian=FourCCEndian::Reversed)
Declare the chunk a member maps to.
consteval detail::SinceSpec since(ClientVersion v)
Restrict a member to entity versions >= v (inclusive).
std::conditional_t<(V.formatLineage() >=Since &&V.formatLineage()< Until), Trait, Absent< Trait > > Slot
A version-gated base: the entity inherits Trait (flattening its chunk members in) iff Since <= V < Un...
constexpr welder::lang Cs
C#/.NET — the welder-csharp rod's identity (user-range slot 0), respelled for wowlib's annotation sit...
Definition lang.hpp:23
std::expected< T, Error > Result
Every fallible wowlib operation returns Result<T>; bindings translate the error branch into a target-...
Definition error.hpp:100
std::unexpected< Error > makeError(ErrorCode code, std::string message, std::uint32_t nativeError=0)
Shorthand for constructing the error branch of a Result.
Definition error.hpp:107
@ InvalidEntityState
An entity's members disagree (e.g.
Definition error.hpp:40
@ PathNotResolvable
No FileDataID is known for the given path (listfile miss).
Definition error.hpp:23
@ FormatVersionMismatch
The file's version chunk disagrees with the requested version.
Definition error.hpp:41
WDL object-placement chunk binary structs (namespace wowlib::formats::wdl::chunks).
WDL sky-scene chunk binary structs (namespace wowlib::formats::wdl::chunks), Shadowlands+: distant sc...
StringBlock — the decoded representation of a chunk of zero-terminated strings (MOTX,...
std::optional< std::string > path
The canonical client-internal path, if known.
Definition file_key.hpp:31
An unparsed chunk payload, preserved verbatim for round-trip.
std::vector< JournalEntry > journal
The serialization face of a chunked entity, mixed in CRTP-style: an entity struct E : ChunkedFile<E> ...
Result< FileBuffer > write() const
Result< void > read(std::span< const std::byte > data)
Deserialize file bytes into this entity, replacing its contents.
The version-agnostic root of every file-level entity (welded as "FileEntity").
One chunk encounter in file order — the write path replays the journal to reproduce the original byte...
std::int32_t member
Declaration index of the member the chunk was read into, or -1 for an unknown chunk.
The version-agnostic base of every WDL<V> (welded as "WDL").
Definition wdl.hpp:63
A WDL low-resolution heightmap file for one client version.
Definition wdl.hpp:168
void validateExtra(ValidationReport &report) const
Validation hook (see formats::detail::validateValue): the tile-table pairing invariants — the MAOF ta...
Definition wdl.hpp:310
Result< void > read(fs::FileSystem &fs, const FileKey &key)
Load the WDL from a client filesystem, replacing this entity's contents.
Definition wdl.hpp:498
Result< std::optional< std::vector< JournalEntry > > > resequencedJournal() const
Serializer hook (see writeEntity): once the stored journal no longer matches the tile data (tiles add...
Definition wdl.hpp:345
std::vector< std::uint32_t > oceanMaskTiles() const
The heightmap ordinal each ocean mask belongs to (parallel to oceanMasks): derived from the stored jo...
Definition wdl.hpp:285
Result< void > patchFile(std::span< std::byte > image) const
Serializer hook (see writeEntity): stamp the MAOF table in the finished image — the i-th nonzero slot...
Definition wdl.hpp:447
Result< void > write(fs::FileSystem &fs, const FileKey &key) const
Serialize and store the WDL through the filesystem's project overlay.
Definition wdl.hpp:510
The BfA fade distances and WMO-map byte.
Definition wdl.hpp:101
std::vector< LodDoodadFade > lodDoodadFades
Definition wdl.hpp:103
std::vector< std::uint8_t > mlmb
Definition wdl.hpp:106
The Legion object swap (low-resolution placements) and ocean masks.
Definition wdl.hpp:83
std::vector< LodMapObjDef > lodMapObjects
Definition wdl.hpp:91
std::vector< LodExtent > lodDoodadExtents
Definition wdl.hpp:88
std::vector< LodExtent > lodMapObjectExtents
Definition wdl.hpp:94
std::vector< SMDoodadDef > lodDoodads
Definition wdl.hpp:85
std::vector< TileOcean > oceanMasks
Definition wdl.hpp:97
The pre-Legion per-tile occlusion mesh.
Definition wdl.hpp:71
std::vector< ChunkBlob > occlusionMeshes
Definition wdl.hpp:73
The Shadowlands sky scenes and undocumented blobs.
Definition wdl.hpp:110
std::vector< SkySceneObject > skySceneObjects
Sky-scene objects (MSSO, Shadowlands+), ranged by the scenes' object_index/count.
Definition wdl.hpp:128
std::vector< SkySceneCondition > skySceneConditions
Sky-scene conditions (MSSC, Shadowlands+), ranged by the scenes' condition_index/count.
Definition wdl.hpp:124
std::vector< SkyScene > skyScenes
Sky scenes (MSSN, Shadowlands+).
Definition wdl.hpp:120
std::vector< SkySceneObjectParams > skySceneObjectParams
Definition wdl.hpp:131
std::vector< std::uint32_t > mldl
Definition wdl.hpp:112
ChunkBlob mldb
MLDB (9.x+, undocumented); preserved opaque.
Definition wdl.hpp:116
The TBC+ per-tile hole masks.
Definition wdl.hpp:77
std::vector< TileHoles > holes
Definition wdl.hpp:79
The War Within scene-living schedule.
Definition wdl.hpp:135
std::vector< SceneLivingDef > sceneLivingDefs
Scene-living definitions (MSLD, The War Within+).
Definition wdl.hpp:138
std::vector< std::int32_t > sceneLivingIndices
Scene-living indices (MSLI, The War Within+): one MSLD index per sky-scene object.
Definition wdl.hpp:142
WDL per-tile chunk binary structs (namespace wowlib::formats::wdl::chunks): the MARE low-resolution h...
The conditional-base mechanism that gives a versioned chunked entity exactly the fields its client ve...
WDL version grid and canonicalization pivots.