Commit graph

3713 commits

Author SHA1 Message Date
Kelsi
c00bfab1a5 fix(wom): scrub NaN bone pivots and clamp parent indices at save time
Symmetric with the existing load-side guards. A bone with a NaN
pivot poisons its child bones' world matrices; an out-of-range
parent index would walk past the bones array during evaluation.
2026-05-06 07:26:26 -07:00
Kelsi
3b1fad7be9 fix(wob): scrub NaN/inf group vertices at save time
Symmetric scrub on the WoB save path matching the existing load
guard. A manually-constructed WoweeBuilding with NaN vertices
would otherwise persist them and force the load-time scrub to
re-clean the same data on every reload.
2026-05-06 07:24:51 -07:00
Kelsi
6347e78d72 fix(wom): scrub NaN/inf bone keyframes at save time
The load side already scrubs keyframe translation/rotation/scale
floats, but fromM2 → save → load is the typical path: a corrupt
M2 source would write NaN keyframes that the load-time guard would
have to clean up on every subsequent load. Symmetric scrub here
ensures the file is clean from the start.

movingSpeed also defaults to 0 if non-finite (matches load).
2026-05-06 07:23:35 -07:00
Kelsi
7a03011625 fix(sql): expand string escape to handle NUL, CR/LF/tab, Ctrl-Z
The previous escape only doubled quotes and backslashes. A quest
description containing a literal newline would emit a multi-line
INSERT that breaks per-line execution scripts; a NUL byte could
prematurely terminate the string in non-length-prefixed clients;
Ctrl-Z is the historical MySQL string terminator on Windows.

Now full MySQL/MariaDB string-literal escape: NUL drops, CR/LF/tab
become \r/\n/\t, Ctrl-Z becomes \Z.
2026-05-06 07:22:04 -07:00
Kelsi
19e479a8ff test(open-formats): add WOB doodad NaN scrub test
Verifies the recent WOB doodad-transform sanitize. A WOB with NaN
position/rotation/scale on a doodad should load with the doodad
zeroed out (position/rotation 0, scale 1). Prevents regressing
the GPU crash that NaN model matrices would cause.
2026-05-06 07:21:20 -07:00
Kelsi
a16689f7fa test(open-formats): add hardening tests + fix existing liquidType assertion
The existing WOT round-trip test asserted liquidType==5; the recent
commit clamped >3 to 0, so the test would have failed once rebuilt.
Updated the test data to use type=3 (slime, in valid range).

Adds 5 new hardening test cases:
- WOT clamps OOR tileX/tileY to 32
- WOT clamps OOR water liquidType to 0
- WOC load skips degenerate triangles
- WOC rejects > 2M triangle headers
- WOC clamps OOR tileX/tileY to 32

Catches regressions in the defensive bounds added across recent
commits.
2026-05-06 07:19:40 -07:00
Kelsi
a2a554dff7 feat(editor): add --info-quests CLI for quests.json summary
Completes the --info-* family. Reports total/chained quest counts,
reward/item counts, total XP awarded, objective-type breakdown
(kill/collect/talk), and any quest-chain validation errors. Lets
zone authors spot broken chains, missing rewards, and lopsided XP
balance from the command line.
2026-05-06 07:16:27 -07:00
Kelsi
df2027463a feat(editor): add --info-objects CLI for objects.json summary
Mirrors --info-creatures and the other format inspectors. Reports
total placement count, M2/WMO breakdown, unique source paths, and
scale range. Useful for spotting empty zones, accidental scale
extremes, or duplicated placements before packing.
2026-05-06 07:15:40 -07:00
Kelsi
93e67ae31b feat(editor): add --info-creatures CLI for creature.json summary
Mirrors the existing --info-wom/wob/woc/wot/wcp inspectors. Reports
total spawn count, hostile/questgiver/vendor/trainer flag counts,
behavior breakdown (stationary/wander/patrol), and unique displayId
count. Useful for triaging zone NPC content from the command line.
2026-05-06 07:14:42 -07:00
Kelsi
d1f347a9c1 fix(wob): sanitize doodad transform during fromWMO conversion
A WMO with a NaN doodad quaternion would produce NaN euler angles
through glm::eulerAngles() and persist them into the WoB. Identity
quaternion fallback for a non-finite source, plus NaN scrub on
position/rotation/scale separately so the converted WOB is always
load-safe.
2026-05-06 07:13:49 -07:00
Kelsi
5af4bba556 feat(validate): report file counts and per-format invalid totals
The previous --validate output told you whether *some* file of each
type existed, which was hard to act on for partially-valid zones.
Now reports the per-format file count and how many failed magic
validation, e.g. 'WOM (12 invalid: 2)' so a zone author can spot
missing or corrupted models without grepping through file listings.
2026-05-06 07:12:04 -07:00
Kelsi
7e2dc4ec1d fix(wcp): apply unpack-side header bounds to readInfo + categorize .woc
readInfo previously trusted fileCount/infoSize blindly, so a malicious
or corrupted WCP could allocate a 4GB string just to print metadata
via --info-wcp. Same 1M file / 16MB info caps now applied. Also
categorizes .woc collision files (was bucketed under 'other').
2026-05-06 07:10:53 -07:00
Kelsi
ed749b9afa fix(wot): clamp liquid type to known range on load
WoW liquid types are 0=water/1=ocean/2=magma/3=slime. A user-edited
WOT could carry an out-of-range value that the editor renderer
silently maps to plain water but the server treats as undefined.
2026-05-06 07:09:48 -07:00
Kelsi
1c1250a37c fix(wot): scrub NaN water height on load
A WOT water entry with non-finite height would push NaN through
the water mesh builder and produce a degenerate Vulkan draw
(invisible water at best, GPU hang at worst).
2026-05-06 07:08:50 -07:00
Kelsi
b8e2d08b17 fix(wob): scrub NaN/inf doodad transforms at save time
Same scrub now applied symmetrically on the save side so a
corrupted in-memory doodad transform can't be persisted into a
WOB and then have to be cleaned up on every subsequent load.
2026-05-06 07:07:21 -07:00
Kelsi
5d78cbb81d fix(wob): scrub NaN/inf doodad position+rotation on load
Already had a guard for scale; extending to position/rotation too.
A WoB with non-finite doodad transforms produces NaN model matrices
that propagate into the M2 instance SSBO and crash the GPU.
2026-05-06 07:06:25 -07:00
Kelsi
1135e499d7 fix(zone): scrub NaN/inf manifest floats at save time
Mirrors the load-side sanitize. nlohmann throws on NaN/inf, so
a corrupted in-memory baseHeight or volume would abort the manifest
save and lose all zone-level settings (flags, audio config, etc.).
2026-05-06 07:05:13 -07:00
Kelsi
49feb8b9f6 fix(objects): scrub NaN/inf floats at save time
Same json-serialization-safety fix as for NPC and WOT saves.
Object position/rotation NaN would abort the entire objects.json
save and lose all placement work in the session.
2026-05-06 07:04:27 -07:00
Kelsi
999388b805 fix(npc): scrub NaN/inf floats at save time
nlohmann::json throws on non-finite serialization, which would
abort the entire creatures.json save and lose every spawn change
in the session. Scrub position/orientation/scale/radii/patrol
floats on the way out so a single corrupt NPC can't kill the
batch save.
2026-05-06 07:03:51 -07:00
Kelsi
9ef04414d1 fix(wot): scrub NaN/inf in doodad/WMO placements at save time
nlohmann::json serialization throws on NaN/inf floats, which would
abort the entire WOT save and leave the user with an unsaved zone
state. Scrub on the way out so a single corrupted placement can't
take down the whole save.
2026-05-06 07:03:02 -07:00
Kelsi
826d218226 fix(zone): cap manifest strings at AzerothCore SQL limits
map_dbc.MapName / area_table_dbc.AreaName are varchar(100). Edited
zone.json could carry longer strings that would either fail the
INSERT or silently truncate. Cap mapName/displayName at 100,
biome at 64, description at 4096.
2026-05-06 07:02:09 -07:00
Kelsi
2119546a7a fix(npc): truncate over-long NPC name/modelPath at SQL limits
creature_template.name is varchar(100) in AzerothCore. Edited
creature JSON could carry longer names that would either fail
the INSERT or silently truncate. Cap name at 100 and modelPath
at 1024 on load.
2026-05-06 07:01:25 -07:00
Kelsi
280fe1e6e8 fix(quest): truncate over-long title/desc/completion to SQL limits
quest_template.LogTitle is varchar(200) in AzerothCore. Edited
quest JSON could carry longer strings that would either fail the
INSERT or silently truncate at the server. Cap title at 200 chars
and the longer text fields at 8KB on load.
2026-05-06 07:01:00 -07:00
Kelsi
3614a7dcd5 fix(zones): clamp discovery mapId and tile coords on scan
Mirrors the editor-side ZoneManifest sanitize on the discovery
scanner used by the launcher and asset manager. A custom_zones/
zone with bad mapId or out-of-range tile coords would otherwise
appear in the picker and silently fail when the user selects it.
2026-05-06 07:00:04 -07:00
Kelsi
6651eccf3b feat(editor): add --info-wot CLI for inspecting terrain metadata
Mirrors the existing --info-wom/--info-wob/--info-woc/--info-wcp
inspectors. Reports the tile coord, populated chunks, layer count,
water count, texture/doodad/WMO counts, and computed height range
across all chunks. Useful for triaging zones from the command line
without opening the GUI.
2026-05-06 06:58:34 -07:00
Kelsi
d127053e21 fix(objects): bound populateBiome density and asset scale ranges
Same defensive guards as scatter: cap per-asset count at 50k to
prevent editor freeze under a high-density biome, and ensure scale
range preconditions (a<b, both positive) so distScale construction
doesn't undermine validity.
2026-05-06 06:56:32 -07:00
Kelsi
c1af157587 fix(objects): guard ObjectPlacer::scatter against bad inputs
Same defensive guards now applied to NPC scatter: reject NaN/inf
center/radius, cap count at 100k (prevents editor freeze on huge
inputs), and ensure minScale < maxScale so uniform_real_distribution
preconditions hold.
2026-05-06 06:55:43 -07:00
Kelsi
10e77f1c2e fix(npc): guard NpcSpawner::scatter against zero radius and bad inputs
A radius of 0 would either throw from the uniform distribution
constructor (uniform_real_distribution requires a < b) or divide
by zero in the sqrt-based area-uniform sampler. Also reject NaN
center, non-positive radius, and absurdly large counts (>10k)
which would freeze the editor on placement.
2026-05-06 06:54:48 -07:00
Kelsi
d96d040831 fix(sql): substitute generic displayId for NPCs with displayId=0
A creature_template row with modelid1=0 spawns an invisible NPC
in-game. Fall back to 11707 (a generic humanoid) on export so
"Creature"-named placeholder spawns are at least usable; the user
can edit the displayId after.
2026-05-06 06:53:47 -07:00
Kelsi
1e378fb4ce fix(wot): clamp tile coords and scrub NaN doodad/WMO placements
A WOT JSON could carry tile coords outside 0..63 (would compute
chunk world positions tens of thousands of units off-grid) or NaN
position/rotation values on doodad/WMO placements (would propagate
into rendering matrices and produce invisible geometry).
2026-05-06 06:51:51 -07:00
Kelsi
aa9ef6f2ca fix(adt): scrub NaN/inf floats at write time
ADTWriter::writeFloat now coerces non-finite values to 0 before
emitting bits, so a stray NaN in a chunk position, MDDF rotation,
or MODF extent can't leak into the saved ADT and produce invisible
terrain or off-map placements after reload.
2026-05-06 06:49:51 -07:00
Kelsi
bc1839d9ab fix(zone): drop out-of-range tile coords on manifest load
WoW's tile grid is 64x64. A tile (200,200) entry would generate an
ADT filename the loader rejects and silently leave the zone with no
terrain. Drop bad entries instead.
2026-05-06 06:48:28 -07:00
Kelsi
4a98dd7a2c fix(editor): slugify mapName for module dir + conf keys
A zone named with spaces or punctuation (e.g. "My Zone!") used to
produce a module directory path "mod_wowee_My Zone!/" and conf
keys like "Wowee.My Zone!.Enabled" which AzerothCore's config
parser rejects. The slug is now stripped to [A-Za-z0-9_-], with
spaces/slashes mapped to underscores. SQL VALUES still use the
raw display text via SQLExporter::escape.
2026-05-06 06:47:43 -07:00
Kelsi
a8464fc367 fix(editor): escape user strings in server module map/zone/tele SQL
The map_dbc, area_table_dbc, and game_tele INSERTs previously
embedded mapName/displayName/manifest.mapName as raw strings — a
zone called "King's Land" or anything containing a single quote
would emit malformed SQL that AzerothCore would reject. Promotes
the existing escapeSql helper to a public SQLExporter::escape and
uses it in all three INSERTs.
2026-05-06 06:46:58 -07:00
Kelsi
cc1e1cb7fa fix(editor): cap stamp vertex count and skip NaN samples on load
A malformed stamp JSON could carry millions of entries (would OOM)
or NaN dx/dy/height (would propagate through brush blends and leave
permanent holes in the heightmap).
2026-05-06 06:45:41 -07:00
Kelsi
0a5583310c fix(editor): clamp project mapId and zone tile coords on load
A hand-edited project.json could carry a 0 or massively-OOR mapId
(would break DBC indexing) or tile coords outside 0..63 (would
produce garbage ADT filenames). Defaults restore safe values.
2026-05-06 06:45:09 -07:00
Kelsi
721efb2ecb fix(zone): clamp manifest audio volumes and reject NaN baseHeight on load
A user-edited zone.json could carry NaN/inf or out-of-range volumes
which would silently corrupt terrain elevation or produce silent /
clipping audio. Now baseHeight defaults back to 100 if non-finite,
and music/ambience volumes clamp to [0,1] with NaN fallbacks.
2026-05-06 06:44:30 -07:00
Kelsi
185b7b522d fix(wob): sanitize boundRadius + per-group boundMin/Max at save time
Same float-NaN scrub for WoB save matching the WHM/WOC/WOM saves.
Building boundRadius defaults to 1.0 if non-finite; per-group bounds
zero out non-finite components (would otherwise corrupt the cull
frustum).
2026-05-06 06:39:49 -07:00
Kelsi
d25654d11a fix(wom): sanitize boundRadius/min/max floats at save time
Mirrors the WHM and WOC save sanitize. boundRadius defaults to 1.0 if
non-finite (matches load-time default); boundMin/boundMax components
zero out non-finite values. Prevents an in-memory model with a NaN
spike (e.g. mid-edit) from being persisted into the WOM and requiring
load-time cleanup forever after.
2026-05-06 06:36:46 -07:00
Kelsi
663d34af0d fix(woc): sanitize triangle vertices + bounds at save time
In-memory collision can be polluted by addMesh on bad input (e.g. a
WMO with NaN vertex positions). Without this, the save would persist
that NaN into the WOC and the load-time guards would have to clean
it up forever. Now scrubs vertices and bounds at write time, matching
the WHM save sanitize.
2026-05-06 06:35:05 -07:00
Kelsi
71378c20ff fix(whm): exportOpen sanitizes heights + caps alphaSize at 64KB on save
Sanitize at write time too, not just on load. A mid-edit NaN spike
(e.g. brush operation that produced NaN before being committed) would
otherwise be persisted into the WHM and require the load-time guard
to clean it up forever after. AlphaSize is also capped at 64KB to
match the loader cap.
2026-05-06 06:32:24 -07:00
Kelsi
2df49c725f fix(editor): texture exporter validates BLP image before passing to stbi
Three new sanity checks before stbi_write_png:
  - dimensions <=0 or >8K rejected (matches PNG override loader cap)
  - data buffer must be >= width * height * 4 bytes (corrupt BLP could
    have mismatched dimensions vs data length, and stbi reads off the
    end of the buffer otherwise)
Skips with warning rather than crashing the exporter mid-zone.
2026-05-06 06:29:26 -07:00
Kelsi
d3a85776f8 fix(content-pack): packZone truncates path length + skips files >4GB
Two write-side guards mirroring the unpack-side ones:
  - Path length truncated to 1KB (matches unpack cap; long paths would
    silently wrap u16 and corrupt the pack)
  - Files >4GB on disk skipped with a zero-length entry rather than
    silently producing a truncated dataSize that overflows uint32
2026-05-06 06:27:04 -07:00
Kelsi
5019e21787 fix(wom): writeStr helper truncates length-prefixed strings to fit u16 length
Same fix as WoB save just got. Without truncation a model name or
texture path over 65535 chars would silently get a wrap-around length
and corrupt the file.
2026-05-06 06:25:33 -07:00
Kelsi
361ff712d7 fix(wob): writeStr helper truncates length-prefixed strings to fit u16 length
Without truncation, names over 65535 chars would silently get a wrap-
around length value and produce a corrupt file (the actual string would
be longer than the saved length, shifting everything after it). Single
shared writeStr lambda replaces five copy-pasted (uint16 length + bytes)
write blocks.
2026-05-06 06:23:35 -07:00
Kelsi
be64298218 fix(dbc): cap JSON DBC string sizes (4KB/string, 64MB total) + NaN floats
JSON DBC values are mostly small integers, but a malicious file could
stuff 100MB strings into every cell to OOM the stringBlock (which has
no per-string or total cap). Added 4KB per-string + 64MB total caps —
fields exceeding either are zeroed. Float fields also get NaN scrub
(same pattern as the earlier vertex/keyframe guards).
2026-05-06 06:19:01 -07:00
Kelsi
719951976d fix(wom+wob): reject path traversal in WOM texture paths + WOB material/group texPaths
Same defensive check as the WoB doodad path guard. Texture paths from
hostile WOM/WoB are passed to the asset manager; '..' or absolute paths
could probe outside the assets/ tree. Now cleared on detection — slot
survives but loads no texture (renderer falls back to white).

Single shared rejectTraversal lambda in WoB to avoid copy-paste.
2026-05-06 06:16:54 -07:00
Kelsi
c4463ba96e fix(wob): reject doodad paths with traversal/absolute components
Doodad model paths from a WoB are passed to the asset manager via
outModel.doodadNames. The asset manager only reads files, but '..' or
absolute paths from a hostile WoB could probe for files outside the
expected assets/ tree. Now clears the modelPath on traversal — the
doodad slot survives but loads no model.
2026-05-06 06:14:22 -07:00
Kelsi
bbfc364119 fix(editor): texture exporter rejects path-traversal in source M2/WMO texture paths
Texture paths come from M2/WMO files which a malicious zone author
could craft to include '..' or absolute paths. Without this check,
exporting such a zone would write PNGs outside outputDir/textures/
and clobber sibling export files.
2026-05-06 06:12:11 -07:00
Kelsi
b5a9ce7816 fix(assets): cap PNG override texture dimensions at 8K to prevent OOM
stbi_load happily decodes any PNG up to 32K x 32K — at 4 bytes/pixel
that's 4GB which OOMs the editor before the override even returns.
WoW textures top out at 4K; 8K cap leaves headroom for HD upgrades
without enabling abuse. Also widens the wxh multiplication to size_t
to defeat int overflow on 8K x 8K images.
2026-05-06 06:09:13 -07:00