Skip to content

[Audit][High] Off-by-one type mismatch in OverworldV2Generator tree/vegetation placement bounds check #707

Description

@MichaelFisher1997

🔍 Module Scanned

modules/worldgen-overworld-v2/src/ (automated audit scan)

📝 Summary

In OverworldV2Generator, the tree placement and vegetation placement bounds checks compare terrain_height (i32) directly against CHUNK_SIZE_Y - 8 (u32 constant 248), causing a Zig signed-to-unsigned comparison that produces incorrect results when terrain_height > 248. This causes trees and vegetation to be incorrectly skipped at high altitudes (mountain peaks, jagged peaks).

📍 Location

  • File: modules/worldgen-overworld-v2/src/root.zig:231
  • Function/Scope: placeTrees() and placeVegetation()

🔴 Severity: High

  • High: Incorrect rendering (missing trees/vegetation at high altitudes), broken features in mountainous terrain

💥 Impact

When terrain_height >= 248 (which easily occurs at mountainous peaks with sea_level=64):

  • The comparison terrain_height >= CHUNK_SIZE_Y - 8 evaluates as terrain_height >= 248
  • For terrain_height = 300, Zig performs 300 >= 248 = true, incorrectly skipping tree placement
  • This affects trees (line 231) and vegetation (line 280), which both use the same boundary check pattern
  • In mountainous worlds with peak heights of 140+ sea_level (204+ blocks), all trees are incorrectly suppressed

🔎 Evidence

Line 231 in placeTrees():

if (surface_y <= self.params.sea_level or surface_y >= CHUNK_SIZE_Y - 8) continue;

Line 280 in placeVegetation():

if (surface_y <= 0 or surface_y >= CHUNK_SIZE_Y - 2) continue;

The issue is the type mismatch in the comparison:

  • surface_y is i32 (from chunk.getSurfaceHeight() which returns i16 promoted to i32)
  • CHUNK_SIZE_Y is u32 = 256 (from world_core.CHUNK_SIZE_Y)
  • CHUNK_SIZE_Y - 8 evaluates to u2 248 (truncated from u32)
  • Zig performs signed-to-unsigned comparison, causing terrain heights > 248 to wrap

🛠️ Proposed Fix

Change the boundary checks to use explicit integer type casting:

// Line 231 - change from:
if (surface_y <= self.params.sea_level or surface_y >= CHUNK_SIZE_Y - 8) continue;
// To:
if (surface_y <= self.params.sea_level or surface_y >= @as(i32, CHUNK_SIZE_Y) - 8) continue;

// Line 280 - change from:
if (surface_y <= 0 or surface_y >= CHUNK_SIZE_Y - 2) continue;
// To:
if (surface_y <= 0 or surface_y >= @as(i32, CHUNK_SIZE_Y) - 2) continue;

Or equivalently, cast the upper bound to i32:

if (surface_y <= self.params.sea_level or surface_y >= @as(i32, CHUNK_SIZE_Y - 8)) continue;

✅ Acceptance Criteria

  • Trees spawn correctly at terrain heights >= 248
  • Vegetation spawns correctly at terrain heights >= 254
  • Unit test verifies tree placement at mountain peaks (height ~140 with sea_level=64)
  • Build succeeds with nix develop --command zig build

📚 References

Metadata

Metadata

Assignees

No one assigned

    Labels

    automated-auditIssues found by automated opencode audit scansbugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions