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