Write the section fluid count instead of a hardcoded zero

LevelChunkSection puts two shorts in front of every section: nonEmptyBlockCount
and fluidCount. We wrote the first and then a literal 0 for the second, under a
comment claiming it was a reserved field that vanilla always leaves at zero.
It is not reserved and vanilla does not.

So every client was told every section is fluid-free, in a world where the
aquifer now fills oceans, lakes and flooded caves. The golden test did not catch
it because its fixture is a superflat chunk whose real fluid count is zero.

The count is per block state, not per block: a waterlogged stair holds a fluid
while a dry one does not, and the flag for that comes from the block-state dump
added with the heightmaps.
This commit is contained in:
Master290 2026-07-27 03:28:49 +03:00
parent 7880531bdb
commit 9e91425c5d
3 changed files with 69 additions and 14 deletions

View file

@ -104,3 +104,45 @@ func TestBlockStatePredicates(t *testing.T) {
t.Error("dandelion blocks motion; it should not")
}
}
// TestSectionFluidCount checks the second short of a chunk section. It was
// written as a constant zero under a comment calling it reserved, so every
// client was told every section is fluid-free.
func TestSectionFluidCount(t *testing.T) {
c := NewChunk(0, 0, BiomePlains)
const y = 20
// One section: stone floor, water above it, and one waterlogged block —
// which counts as fluid even though it is not a fluid block.
stairs := nameToStateID("minecraft:oak_stairs", map[string]string{
"facing": "north", "half": "bottom", "shape": "straight", "waterlogged": "true",
})
if stairs == StateAir {
t.Fatal("waterlogged oak stairs are missing from the block table")
}
if stateFlags(stairs)&flagFluid == 0 {
t.Fatal("waterlogged stairs do not carry the fluid flag; the dump is wrong")
}
for lx := 0; lx < 16; lx++ {
for lz := 0; lz < 16; lz++ {
c.SetBlock(lx, y, lz, StateStone)
c.SetBlock(lx, y+1, lz, StateWater)
}
}
c.SetBlock(0, y+2, 0, stairs)
si := (y - MinY) >> 4
nonEmpty, fluid := sectionCounts(c.sections[si])
if want := uint16(16*16*2 + 1); nonEmpty != want {
t.Errorf("nonEmptyBlockCount = %d, want %d", nonEmpty, want)
}
if want := uint16(16*16 + 1); fluid != want {
t.Errorf("fluidCount = %d, want %d (256 water + 1 waterlogged)", fluid, want)
}
// A section of dry stone still reports zero, and an absent section too.
dry := NewChunk(0, 0, BiomePlains)
dry.SetBlock(0, y, 0, StateStone)
if _, fluid := sectionCounts(dry.sections[si]); fluid != 0 {
t.Errorf("dry section fluidCount = %d, want 0", fluid)
}
}