d41d34ecd3
Public/VoxelDensityOp.h: IVoxelDensityOp (PrepareChunk / Eval / EffectOverBox / ClassifyBox / IsXYPure), EVoxelOpEffect, EVoxelOpRole (the four roles), EVoxelOpCombine, FVoxelOpContext, and the box-verdict fold. Nothing is wired in: GetDensityAt is untouched, the archetype switch is intact, no operator exists yet. This is the contract plus the reasoning behind it. Two things worth flagging beyond OPSTACK-PLAN §3: - ClassifyBox is NOT source-only. ApplyBoundarySeal does Max(D, SealFactor*Base) inside its band, i.e. it FORCES solid regardless of input. Pure direction (FillOnly) cannot express that: over a box that sits entirely in the top seal band above the terrain the source says AllAir, FillOnly then kills AllAir, both hypotheses die and the tile becomes Mixed — whereas ClassifyTile returns AllSolid there today. Not a hole, but a silent loss of exactly the trivial tiles T1.d exists to skip. So forcing ops override the fold, and ops after them still apply (a passage crossing that box takes the verdict back, as today). - The fold reproduces the current hand-written ClassifyTile line for line; the mapping is written out in the header. That correspondence is the evidence the abstraction fits this codebase rather than being imposed on it. Also moves EVoxelTileClass from VoxelGenerator.h to VoxelTypes.h (CODEMAP 3.2: foundational, no UClass, everyone includes it) so the op header needs no UCLASS dependency. All existing users reach it through VoxelTypes.h transitively. Types are plain C++ on purpose — no UHT, no .generated.h. They become UENUM/USTRUCT in Phase 3 when ops turn into data assets. UNVERIFIED: not compiled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>