Commit graph

21 commits

Author SHA1 Message Date
Kelsi
397034a750 feat(extract): incremental --upgrade-extract skips up-to-date sidecars
Compares the source file's mtime against the sidecar's; if the
sidecar is newer, the conversion is skipped and counted into
stats.skipped. Re-running --upgrade-extract on a fully-converted
tree is now nearly free (just an mtime check per file).

  asset_extract --upgrade-extract Data/expansions/wotlk
  Walking ... (first run)
    JSON (DBC→JSON)   : 240 ok
  asset_extract --upgrade-extract Data/expansions/wotlk
  Walking ... (second run, all sidecars up to date)
    up-to-date (skip) : 240
    JSON (DBC→JSON)   : 0 ok

emitOpenFormats() takes a new optional 'incremental' flag (default
false to preserve the asset_extract main-loop's overwrite behavior
since fresh extraction always wants new sidecars).

Verified end-to-end with a hand-built DBC: first run converts,
second run reports 'up-to-date (skip): 1'.
2026-05-06 11:00:20 -07:00
Kelsi
463a8cd751 feat(extract): expose --threads to upgrade-extract + report elapsed time
emitOpenFormats now takes an optional threadCount parameter (0 =
auto). The asset_extract --upgrade-extract path forwards opts.threads
so users can override the auto-detect when running on a CI machine
with limited cores or wanting deterministic timing.

Also wraps the upgrade pass with a chrono timer and prints elapsed
seconds so the parallelization payoff is visible at a glance:

  asset_extract --upgrade-extract Data/expansions/wotlk --threads 8
  Walking Data/expansions/wotlk for open-format upgrades...
    elapsed           : 47.2 s
    PNG (BLP→PNG)     : 12340 ok
    ...

Verified end-to-end: --threads 2 on 5 hand-built DBCs converts all
5 in well under a second.
2026-05-06 10:57:18 -07:00
Kelsi
cab1912441 perf(extract): parallelize open-format emit pass
Conversions are CPU-bound (BLP decode, M2/WMO parse, WOM/WOB
serialize) so the serial walk leaves cores idle. Now collects
every job into a vector during the directory walk, then dispatches
across hardware_concurrency() workers via an atomic next-index
queue. Stats use atomics to avoid the per-job mutex.

Expected ~5-8x speedup for full-tree --upgrade-extract on a
modern desktop. Existing test_open_format_emitter still passes
(it exercises both single-file emit*From* helpers and the parallel
emitOpenFormats walker).
2026-05-06 10:55:05 -07:00
Kelsi
30b15554a9 feat(extract): add --upgrade-extract for in-place sidecar generation
Standalone post-extract pass: walks an existing extracted asset
tree and writes open-format sidecars in place, without re-running
MPQ extraction.

  asset_extract --upgrade-extract Data/expansions/wotlk

Lets users with old extractions opt into the open-format pipeline
without losing the extracted state. Implies --emit-open if no
individual --emit-* flag is set.

Verified end-to-end: created a hand-built DBC in a temp dir, ran
--upgrade-extract, observed test.json appear with correct
metadata. Servers continue to read .dbc from manifest; the
runtime client picks up the new .json sidecar via the existing
pickup path.
2026-05-06 10:52:55 -07:00
Kelsi
d4c69a2b46 feat(extract): emit WHM+WOT+WOC for ADT terrain tiles
Final piece of the open-format emit pipeline:
  --emit-terrain  foo.adt → foo.whm + foo.wot + foo.woc

With this, --emit-open now produces a fully open-format zone
alongside every Blizzard MPQ extraction:
  BLP  → PNG       (textures)
  DBC  → JSON      (data tables)
  M2   → WOM       (models, with skin merge)
  WMO  → WOB       (buildings, with group merge)
  ADT  → WHM/WOT   (terrain heights + metadata)
       → WOC       (collision mesh derived from heights)

Originals stay on disk and indexed by manifest.json so private
servers continue to load proprietary formats; wowee runtime/editor
read the open formats directly. One extraction now feeds both
audiences with no separate conversion pass.

Implementation:
- Inline WHM+WOT writer in open_format_emitter.cpp (mirrors the
  editor's WoweeTerrain::exportOpen but without the PNG-preview /
  normal-map deps so the extractor stays editor-independent).
- Tile coords (x,y) parsed from <map>_<x>_<y>.adt filename.
- Collision mesh derived via WoweeCollisionBuilder::fromTerrain
  (terrain triangles only — WMO collision overlays would need
  asset manager and aren't worth the extractor complexity).
2026-05-06 10:36:14 -07:00
Kelsi
e6ace7cce5 feat(extract): emit WOM and WOB side-files (M2/WMO → open formats)
Extends asset_extract with two more open-format emitters:
  --emit-wom  foo.m2 (+ foo00.skin) → foo.wom
  --emit-wob  foo.wmo (+ foo_NNN.wmo groups) → foo.wob
  --emit-open now also turns these on

Originals are preserved so private servers still load .m2/.wmo
through the manifest path; the wowee runtime/editor pick up the
.wom/.wob next to them via the existing open-format search rules.

Implementation:
- New WoweeModelLoader::fromM2Bytes(m2Data, skinData) shares the
  conversion body with fromM2(path, am) via a static helper
  (convertM2ToWom). Lets the extractor convert without standing
  up an AssetManager.
- fromM2(path, am) moved to a separate translation unit
  (wowee_model_fromm2.cpp) so asset_extract doesn't have to
  link the AssetManager dependency.
- WoweeBuildingLoader::fromWMO already takes a WMOModel directly,
  so emitWobFromWmo just needs to read root + group files and
  call save().
- Group sub-files (<base>_NNN.wmo) are skipped during the walk
  since they're merged into the root WMO.
2026-05-06 10:32:17 -07:00
Kelsi
5ed2008621 feat(extract): emit open-format side-files (BLP→PNG, DBC→JSON)
The asset_extract tool now optionally writes wowee open-format
copies next to each extracted proprietary file:
  --emit-png      foo.blp → foo.png
  --emit-json-dbc foo.dbc → foo.json
  --emit-open     shortcut for both

Originals are left untouched, so private servers (AzerothCore,
TrinityCore) that load from the manifest's .blp/.dbc paths
continue to work unchanged. The wowee runtime / editor can now
consume the open formats directly without an extra conversion pass.

Implementation:
- New tools/asset_extract/open_format_emitter.{hpp,cpp} encapsulates
  the post-extract walk + per-file conversion.
- BLP→PNG uses BLPLoader::load + stbi_write_png with the same
  dimension/buffer-size sanity guards the editor's texture exporter
  applies.
- DBC→JSON mirrors the editor's DBCExporter::exportAsJson schema
  (string/float/uint heuristic) so the runtime DBC overlay loader
  can consume the output drop-in.
2026-05-06 10:23:32 -07:00
Kelsi Davis
bcf1015149 fix(rendering): check sampler validity in VkTexture::isValid(), fix Windows build
- VkTexture::isValid() now checks both image AND sampler handles. Previously
  it only checked the image, so a texture with a valid image but NULL sampler
  would pass validation and get bound to a descriptor set. On MoltenVK (macOS)
  this renders as pink/magenta boxes; the fallback white texture is now
  correctly used instead.

- Fix fs::path to std::string implicit conversion in asset extractor that
  broke the Windows (MSYS2/clang) CI build.
2026-04-05 01:34:49 -07:00
sschepens
1e464dd513
refactor path mapper 2026-04-04 14:34:23 -03:00
sschepens
5542cbaa02
refactor asset extractor
- mpq and locale finding is now case insensitive
- improve extraction order and support more patches
- unified much of the mpq logic for all expansions
- return a list of ordered paths for loading
2026-04-04 14:00:55 -03:00
Kelsi Davis
2343b768ce fix: warden mmap on macOS, add external listfile support to asset extractor
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Drop PROT_EXEC from warden module mmap when using Unicorn emulation
(not needed — module image is copied into emulator address space). Use
MAP_JIT on macOS for the native fallback path.

Add --listfile option to asset_extract and SFileAddListFileEntries
support for resolving unnamed MPQ hash table entries from external
listfiles.
2026-04-04 01:16:28 -07:00
Kelsi
7264ba1706 fix(extractor): lowercase all output paths to prevent duplicate folders
WoW archives contain mixed-case variants of the same path (e.g.,
ARMLOWERTEXTURE vs ArmLowerTexture) which created duplicate directories
on case-sensitive Linux filesystems. Now mapPath() lowercases the entire
output. Also keeps TextureComponents and ObjectComponents directory
names instead of abbreviating them (item/texturecomponents/ instead of
item/texture/) so filesystem paths match the WoW virtual paths used in
manifest lookups.
2026-04-03 21:26:20 -07:00
Kelsi
b31a2a66b6 tools: fix DBC string-column detection false positives in both dbc_to_csv and asset_extract
The string-column auto-detector in both tools had two gaps that caused small
integer fields (RaceID=1, SexID=0/1, BaseSection, ColorIndex) to be falsely
classified as string columns, corrupting the generated CSVs:

1. No boundary check: a value of N was accepted as a valid string offset even
   when N landed inside a longer string (e.g. offset 3 inside "Character\...").
   Fix: precompute valid string-start boundaries (offset 0 plus every position
   immediately after a null byte); reject offsets that are not boundaries.

2. No diversity check: a column whose only non-zero value is 1 would pass the
   boundary test because offset 1 is always a valid boundary (it follows the
   mandatory null at offset 0). Fix: require at least 2 distinct non-empty
   string values before marking a column as a string column. Columns like
   SexID (all values are 0 or 1, resolving to "" and the same path fragment)
   are integer fields, not string fields.

Both dbc_to_csv and asset_extract now produce correct column metadata,
e.g. CharSections.dbc yields "strings=6,7,8" instead of "strings=0,1,...,9".
2026-03-10 03:49:06 -07:00
Kelsidavis
1fab17e639 Add Windows build scripts, fix multi-threaded MPQ extraction, and cross-platform temp paths
- Add build.ps1/bat, rebuild.ps1/bat, debug_texture.ps1/bat (Windows equivalents
  of existing bash scripts, using directory junctions for Data link)
- Fix asset extractor: StormLib is not thread-safe even with separate handles per
  thread. Serialize all MPQ reads behind a mutex while keeping CRC computation and
  disk writes parallel. Previously caused 99.8% extraction failures with >1 thread.
- Add SFileHasFile() check during enumeration to skip listfile-only entries
- Add diagnostic logging for extraction failures (first 5 per thread + summary)
- Use std::filesystem::temp_directory_path() instead of hardcoded /tmp/ in
  character_renderer.cpp debug dumps
- Update debug_texture.sh to use $TMPDIR fallback and glob for actual dump filenames
2026-02-25 08:22:45 -08:00
Kelsi
d7e2b26af7 Unify asset system: one asset set, always high-res
Remove HDPackManager, expansion overlay manifests, and BLP size-comparison
logic. Assets now resolve through a single manifest with a simple override
directory (Data/override/) for future HD upgrades.
2026-02-15 04:18:34 -08:00
Kelsi
a67dca5787 Add overlay extraction for multi-expansion asset deduplication
Extracts each expansion's assets as a CRC-compared overlay against a
base manifest, storing only files that differ. Auto-detects overlay mode
when a base manifest already exists. Adds --as-overlay, --full-base
flags and manifest merge for partial extractions.
2026-02-14 03:09:17 -08:00
Kelsi
03013e751a Cache WoW.exe during asset extraction for Warden MEM_CHECK 2026-02-14 02:17:50 -08:00
Kelsi
886f4daf2e Add per-expansion asset overlay system and fix CharSections DBC layout
Expansion overlays allow each expansion to supplement the base asset data
via an assetManifest field in expansion.json, loaded at priority 50 (below
HD packs). The asset extractor gains --reference-manifest for delta-only
extraction. Also fixes CharSections field indices (VariationIndex=4,
ColorIndex=5, Texture1=6) across all DBC layout references.
2026-02-14 00:00:26 -08:00
Kelsi
f247d53309 Add expansion DBC CSVs, Turtle support, and server-specific login 2026-02-13 00:10:01 -08:00
Kelsi
7092844b5e Add multi-expansion support with data-driven protocol layer
Replace hardcoded WotLK protocol constants with a data-driven architecture
supporting Classic 1.12.1, TBC 2.4.3, and WotLK 3.3.5a. Each expansion
has JSON profiles for opcodes, update fields, and DBC layouts, plus C++
polymorphic packet parsers for binary format differences (movement flags,
speed fields, transport data, spline format, char enum layout).

Key components:
- ExpansionRegistry: scans Data/expansions/*/expansion.json at startup
- OpcodeTable: logical enum <-> wire values loaded from JSON
- UpdateFieldTable: field indices loaded from JSON per expansion
- DBCLayout: schema-driven DBC field lookups replacing magic numbers
- PacketParsers: WotLK/TBC/Classic parsers with correct flag positions
- Multi-manifest AssetManager: layered manifests with priority ordering
- HDPackManager: overlay texture packs with expansion compatibility
- Auth screen expansion picker replacing hardcoded version dropdown
2026-02-12 22:56:36 -08:00
Kelsi
aa16a687c2 Replace MPQ runtime with loose file asset system
Extract assets from MPQ archives into organized loose files indexed by
manifest.json, enabling fully parallel reads without StormLib serialization.
Add asset_extract and blp_convert tools, PNG texture override support.
2026-02-12 20:32:14 -08:00