From 71378c20ffb7dca59baf4e3ab3918e49f6ccaad7 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 06:32:24 -0700 Subject: [PATCH] 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. --- tools/editor/wowee_terrain.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tools/editor/wowee_terrain.cpp b/tools/editor/wowee_terrain.cpp index df38efc4..96f10d20 100644 --- a/tools/editor/wowee_terrain.cpp +++ b/tools/editor/wowee_terrain.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace wowee { namespace editor { @@ -30,10 +31,23 @@ bool WoweeTerrain::exportOpen(const pipeline::ADTTerrain& terrain, // Per-chunk: baseHeight(4) + heights[145](580) + alphaSize(4) + alphaData(N) for (int ci = 0; ci < 256; ci++) { const auto& chunk = terrain.chunks[ci]; + // Sanitize base + heights on save so a corrupt in-memory terrain + // (e.g. mid-edit NaN spike) doesn't get persisted into the WHM + // and require the load-time guard to clean up forever after. float base = chunk.position[2]; + if (!std::isfinite(base)) base = 0.0f; f.write(reinterpret_cast(&base), 4); - f.write(reinterpret_cast(chunk.heightMap.heights.data()), 145 * 4); - uint32_t alphaSize = static_cast(chunk.alphaMap.size()); + float clean[145]; + for (int i = 0; i < 145; i++) { + clean[i] = chunk.heightMap.heights[i]; + if (!std::isfinite(clean[i])) clean[i] = 0.0f; + } + f.write(reinterpret_cast(clean), 145 * 4); + // Cap alpha size at 64KB (matches loader cap) — alphaMap is + // bounded in practice but defensive truncation prevents a + // stale memory state from producing an unloadable WHM. + uint32_t alphaSize = std::min( + static_cast(chunk.alphaMap.size()), 65536); f.write(reinterpret_cast(&alphaSize), 4); if (alphaSize > 0) { f.write(reinterpret_cast(chunk.alphaMap.data()), alphaSize);