Skip to content

Render negative-Y sections on 1.18+ worlds - #485

Closed
u9g wants to merge 1 commit into
PrismarineJS:26-1-supportfrom
u9g:fix/negative-y-sections
Closed

Render negative-Y sections on 1.18+ worlds#485
u9g wants to merge 1 commit into
PrismarineJS:26-1-supportfrom
u9g:fix/negative-y-sections

Conversation

@u9g

@u9g u9g commented Aug 16, 2026

Copy link
Copy Markdown
Member

Stacked on #484 — merge that first, after which this PR's diff collapses to just the last commit.

Problem

Any camera below y=0 renders nothing but the clear color — e.g. a mineflayer bot standing in a deepslate cave shows a uniform sky-blue frame, even with the surrounding chunks fully loaded.

Cause

  • worldrenderer.js hardcodes the pre-1.18 world range: the dirty-section loops in addColumn/removeColumn iterate y = 0..240, so sections below y=0 are never queued for meshing.
  • worker.js's section-presence guard indexes chunk.sections[Math.floor(y / 16)], but ChunkColumn (1.18+) indexes sections from minY (-64): sections[(pos.y - this.minY) >> 4]. For y < 16 sections this resolves to the wrong index, and for y < 0 to sections[-1] = undefined, so those sections are skipped. (Above ground it is accidentally harmless — sections are dense and geometry is read via absolute coordinates — but the guard checks the wrong slot.)
  • models.js culls faces against a hardcoded y < 0 instead of the world's minY.

Fix

  • Derive minY/worldHeight from the version's chunk implementation in setVersion (defaults 0/256, so pre-1.18 behavior is unchanged) and iterate the real range in addColumn/removeColumn.
  • Index worker sections by (y - (chunk.minY ?? 0)) / 16.
  • Expose minY on the worker's World wrapper and gate models.js face culling on world.minY ?? 0.

Verification

  • setVersion('26.1'){ minY: -64, worldHeight: 384 }; 1.16.5 / 1.12.2{ 0, 256 } (new Chunk() constructs fine on old versions)
  • A 26.1 column with a block set at y=-7 round-trips through World.addColumn(fromJson): the y=-16 section resolves and the block reads back through world.getBlock
  • addColumn on 26.1 now queues 20 negative-Y section jobs per column (previously 0)

Sections below y=0 were never meshed: worldrenderer's dirty-section loops
hardcoded the pre-1.18 0..256 range, and the worker's section-presence
guard indexed chunk.sections by y/16 even though ChunkColumn indexes
sections from minY (-64 since 1.18), so negative sections resolved to
undefined and were skipped. Any camera below y=0 saw only the clear color.

Derive minY/worldHeight from the version's chunk implementation, index
worker sections by (y - minY) / 16, and gate models.js face culling on
world.minY instead of 0.
@u9g
u9g changed the base branch from master to 26-1-support August 17, 2026 03:23
@u9g
u9g deleted the branch PrismarineJS:26-1-support August 17, 2026 03:25
@u9g u9g closed this Aug 17, 2026
u9g added a commit to u9g/prismarine-viewer that referenced this pull request Sep 6, 2026
A camera below y=0 renders nothing but the clear color: a bot standing on
the surface of any 1.18+ world (surface ~y=-60 in the overworld's lower
range, or anywhere in a deepslate cave) shows a uniform sky-blue frame with
the surrounding chunks fully loaded.

Three spots hardcode the pre-1.18 world range [0, 256):
- worldrenderer.js dirty-section loops in addColumn/removeColumn iterate
  y=0..240, so sections below y=0 are never queued for meshing
- worker.js indexes chunk.sections[floor(y/16)], but 1.18+ ChunkColumn
  indexes from minY (-64): sections[(y - minY) >> 4]; y<0 resolves to
  sections[-1] = undefined and the section is skipped
- models.js culls faces against a hardcoded y<0 instead of the world's minY

Derive minY/worldHeight from the version's chunk implementation (defaults
0/256, so pre-1.18 is unchanged), iterate the real range, index worker
sections by (y - minY)/16, and gate models.js culling on world.minY.

Revives PrismarineJS#485 (closed); no longer stacked on the 26.1 PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant