diff --git a/src/pipeline/wowee_collision.cpp b/src/pipeline/wowee_collision.cpp index c28aed34..010841ec 100644 --- a/src/pipeline/wowee_collision.cpp +++ b/src/pipeline/wowee_collision.cpp @@ -170,16 +170,25 @@ bool WoweeCollisionBuilder::save(const WoweeCollision& collision, const std::str if (!std::isfinite(v.z)) v.z = 0.0f; return v; }; - uint32_t triCount = static_cast(collision.triangles.size()); + // Cap triangle count at the load-side limit (2M). Save previously + // wrote raw size() so a >2M-tri collision (theoretical, addMesh on + // huge geometry) would be silently rejected on round-trip. + uint32_t triCount = static_cast( + std::min(collision.triangles.size(), 2'000'000)); f.write(reinterpret_cast(&triCount), 4); - f.write(reinterpret_cast(&collision.tileX), 4); - f.write(reinterpret_cast(&collision.tileY), 4); + // Sanitize tile coords too — out-of-range would be clamped on load + // anyway but writing a clean file means no warning on every reload. + uint32_t tileX = collision.tileX > 63 ? 32 : collision.tileX; + uint32_t tileY = collision.tileY > 63 ? 32 : collision.tileY; + f.write(reinterpret_cast(&tileX), 4); + f.write(reinterpret_cast(&tileY), 4); glm::vec3 bmin = sanVec(collision.bounds.min); glm::vec3 bmax = sanVec(collision.bounds.max); f.write(reinterpret_cast(&bmin), 12); f.write(reinterpret_cast(&bmax), 12); - for (const auto& tri : collision.triangles) { + for (uint32_t ti = 0; ti < triCount; ti++) { + const auto& tri = collision.triangles[ti]; glm::vec3 v0 = sanVec(tri.v0), v1 = sanVec(tri.v1), v2 = sanVec(tri.v2); f.write(reinterpret_cast(&v0), 12); f.write(reinterpret_cast(&v1), 12);