mojira.dev
MC-250048

Lava calculates spreading fire state incorrectly

The bug

When lava spread fire, it can sometimes calculate the blockstate for the fire from the block beneath the fire. This bug can be replicated as so:

[media]

Doing so can sometimes create results like such: (Increasing the random tick speed will make it happen faster)

[media]

Code analysis

Specifically, this bug occurs in the random tick method of the lava fluid, it will calculate the fire state for the block below where the fire will be placed, causing the above result.

Code analysis by @unknown can be found in this comment.

Attachments

Comments 7

Just to be clear, the bug you are referring to is the placement of the fire?

Can Confirm

Man a lot of good ones today. So this has been in the game since 1.16 xD specifically 20w06a

Code Analysis (MojMap - 22w14a)

net.minecraft.world.level.material.LavaFluid.java

public void randomTick(Level level, BlockPos pos, FluidState fluid, RandomSource rand) {
    // not relevant
    int i = rand.nextInt(3);
    if (i > 0) {
        BlockPos blockPos = pos;
        for(int c = 0; c < i; ++c) {
            blockPos = blockPos.offset(rand.nextInt(3) - 1, 1, rand.nextInt(3) - 1);
            if (!level.isLoaded(blockPos)) return;
            BlockState state = level.getBlockState(blockPos);
            if (state.isAir()) {
                if (this.hasFlammableNeighbours(level, blockPos)) {
                    level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(level, blockPos));
                    return;
                }
            } else if (state.getMaterial().blocksMotion()) {
                return;
            }
        }
    } else {
        for(int c = 0; c < 3; ++c) {
            BlockPos newPos = pos.offset(rand.nextInt(3) - 1, 0, rand.nextInt(3) - 1);
            if (!level.isLoaded(newPos)) return;
            if (level.isEmptyBlock(newPos.above()) && this.isFlammable(level, newPos)) {
                level.setBlockAndUpdate(newPos.above(), BaseFireBlock.getState(level, newPos));
            }
        }
    }
}

 So this is the lavaFluid randomTick code. Let's focus on these two parts:

net.minecraft.world.level.material.LavaFluid.java

// Top part (not broken)
BlockState state = level.getBlockState(blockPos);
if (state.isAir()) { // Is position we are placing the fire at air?
    if (this.hasFlammableNeighbours(level, blockPos)) { // Is next to a flammable block?
        // Set the block at pos to FireBlock with states that it should have at that pos
        level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(level, blockPos));
        return;
    }
}
// Bottom part (broken)
// Is the block above the position selected empty?
// Is the block at the current position flammable?
if (level.isEmptyBlock(newPos.above()) && this.isFlammable(level, newPos)) {
    // If so then set the block above the position selected to the state it should have if we placed it below that position...
    level.setBlockAndUpdate(newPos.above(), BaseFireBlock.getState(level, newPos));
}

The code does the BaseFireBlock.getState(level, newPos) to generate the fire state at the wrong position, it should have been done one higher

The Fix:
Change the second BaseFireBlock.getState(level, newPos) to BaseFireBlock.getState(level, newPos.above())

Working Fix

Technically the fire would have spread there anyways, and a fire in that state does nothing different. So it just looks cursed, and disappears when given a block update

This issue is also present in 1.18.2 and isn't exclusive to 22w14a.

[media]

Can confirm in 1.19.

Can confirm in 1.19.2.

Can confirm in 1.19.3 and 23w05a

Can confirm in 1.19.4

Derek Thomson

(Unassigned)

Confirmed

Platform

Low

Block states

fire-spread, lava

1.18.2, 22w14a, 1.19, 1.19.2, 1.19.3, 23w05a, 1.19.4, 1.20.4

Retrieved