Class DeferredRebuildQueue

Single-threaded queue of physics work that is deferred to end-of-frame.

Per CLAUDE.md hard rule #3, Box2D body creation and destruction must never happen inside a physics step. The queue exists so that game logic running inside world.step() (e.g. carve operations triggered from a contact callback) can mark work without violating the rule; the actual body churn happens later in flush().

Two work categories:

  • Terrain rebuildenqueueChunk(chunk). Each dirty chunk has its solid pixels independently extracted and triangulated; only the chunk's own static body is rebuilt. Chunks not in the dirty set are untouched, so contacts between dynamic bodies and other chunks' static bodies survive across the carve. The chunks' collider dirty flags are cleared once the rebuild completes (the visual flag is left for the renderer).
  • Debris bodiesenqueueDebris(contour, material). On flush, every queued debris is converted into a dynamic body via Box2DAdapter.createDebrisBody. Debris is event-driven and is processed unconditionally — debris that misses its creation frame would visibly pop in.

Each chunk owns its own static body, made of triangulated polygons extracted from just that chunk's pixels. Chunk-boundary edges are handled correctly by two-sided polygon collision: adjacent chunks each carry a polygon whose edge sits on the boundary, and the combined mass acts as one solid for any body sitting on top. The cross-chunk stitching from Phase 2.5 is no longer required and the global flood-fill rebuild was retired with this model.

Why per-chunk over per-blob: a per-blob model rebuilt the entire blob's body on every carve, destroying every contact bound to it and waking every dynamic body resting on the blob — including bodies nowhere near the carve. With per-chunk colliders the blast radius of a carve is the dirty chunks only, so a settled body on a distant chunk doesn't see its underlying static body change at all.

Constructors

Methods

  • Marks a chunk for rebuild on the next flush. Re-enqueueing the same chunk before flush is a no-op (deduplicated by Set semantics).

    Parameters

    Returns void