Send three real heightmaps instead of one repeated three times

writeHeightmaps computed "highest non-air" once and wrote the same 37 longs
under all three ids, on the stated assumption that our terrain has no leaves or
transparency. That stopped being true the moment the generator grew trees and
flowers.

Vanilla's three client heightmaps stop at different blocks: WORLD_SURFACE at the
first thing that is not air, MOTION_BLOCKING at the first that blocks motion or
holds fluid, MOTION_BLOCKING_NO_LEAVES at the first such thing that is not a
LeavesBlock -- an instanceof, not the minecraft:leaves tag. The client places
rain and snow particles off MOTION_BLOCKING and lands a fishing bobber on it, so
a tree canopy reported as solid ground rains under itself.

Neither blocksMotion() nor the leaves test is derivable from blocks.json: the
first reads cached VoxelShape collision geometry and the forceSolidOn/Off
properties, the second is a Java class check. So the Java dumper grows three
flag bits and the whole thing is renamed for what it now is -- block state
properties, not just lighting. tools/VanillaBlockStateDump.java writes
internal/world/block_properties.bin at format 2; the light bytes are unchanged
byte for byte and only the previously unused high flag bits moved.

Verified the dumper round trip while doing it: recompiling the old
VanillaLightDump against the jar reproduces the committed binary exactly, so the
data really does come from the runtime registry and not from a stale checkout.
CLAUDE.md now carries the command to rebuild it.
This commit is contained in:
Master290 2026-07-27 03:27:09 +03:00
parent 57214fbd76
commit 7880531bdb
8 changed files with 280 additions and 48 deletions

View file

@ -60,11 +60,22 @@ threshold was pinned down: `Strategy$2` switches `{0..3}` and everything above f
global palette, which `.refjava/` alone could not show.
When a constant has to come from vanilla's *runtime* rather than its source or reports, dump it with
a throwaway Java program run against the jar. `tools/VanillaLightDump.java` is the precedent — it
walks the block-state registry and emits opacity, emission and voxel face shapes into
`internal/world/light_properties.bin`. Substring-matching block names is how the light table was
wrong before (`grass_block` matched "grass", `bedrock` matched "bed"); don't reintroduce that shape
of guess anywhere.
a Java program run against the jar. `tools/VanillaBlockStateDump.java` is the one that exists — it
walks the block-state registry and emits, per state, light opacity and emission, voxel face-occlusion
masks, and the `blocksMotion` / fluid / leaves flags the heightmaps need, into
`internal/world/block_properties.bin`. Rebuild it with:
```
CP="versions/26.1.2/server-26.1.2.jar;$(find libraries -name '*.jar' | tr '\n' ';')"
javac -nowarn -cp "$CP" -d <out> tools/VanillaBlockStateDump.java
java -cp "<out>;$CP" VanillaBlockStateDump > internal/world/block_properties.bin
```
The 39 jars under `libraries/` are required; the server jar alone will not boot the registry. Bump
the format version in both the Java and `internal/world/block_properties.go` whenever the layout or
a flag's meaning changes. Substring-matching block names is how the light table was wrong before
(`grass_block` matched "grass", `bedrock` matched "bed"); don't reintroduce that shape of guess
anywhere.
## Layout
@ -74,7 +85,7 @@ cmd/gendump/ client-free generator diagnostics — biome spread, surface bl
subsurface banding, deep-layer composition, bedrock band, fluid census,
cross-section
cmd/genblocks/ generates internal/worldgen/generated_blocks.go from the block report
cmd/genlight/ legacy light-table generator, superseded by tools/VanillaLightDump.java
cmd/genlight/ legacy light-table generator, superseded by tools/VanillaBlockStateDump.java
tools/ Java dumpers run against the jar, plus their Go-side fixtures
internal/protocol/ VarInt, framing, compression, packet IDs
internal/nbt/ NBT codec (modified UTF-8)