mojira.dev
MC-4533

Water graphical glitch when connecting diagonally

When water is placed diagonally from other water blocks like it does in the screenshots below, it causes a graphical glitch.

You must connect the second source at the farthest point of the first. Let the first stretch all the way out.
It doesn't matter what block is near the water.

Code analysis

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

Linked issues

Attachments

Comments 35

I think that this may ne intended, but I am not entirely sure.

Not really intended, but one more case of "it works well enough and doesn't completely break things, so leave it as is for now".

It has been around a long time, and iirc, has even been (ab)used for benefits, but that does not make it less of a bug.

In addition, removing a block diagonally makes the water dip in that corner.

The code calculates the corner water levels based on the existence and levels of water in 8 blocks around each corner/edge. However, it is quite naive and does not make any checks whether the neighbor blocks provide a path for the water to actually affect the block being rendered.

There are a number of cases (block patterns) to check, but it seems doable. This has been "bugging" me, too, so... Working on a fix, lets see what I can come up with.

Current code
I will only include the method signature for the method getFluidHeight() here as the method body gets changed quite a bit, no point in showing the original.

RenderBlocks

public boolean renderBlockFluids(Block block, int x, int y, int z) {
    ...
    double var24 = (double) this.getFluidHeight(x, y, z, var22);
    double var26 = (double) this.getFluidHeight(x, y, z + 1, var22);
    double var28 = (double) this.getFluidHeight(x + 1, y, z + 1, var22);
    double var30 = (double) this.getFluidHeight(x + 1, y, z, var22);
    ...
}

private float getFluidHeight(int x, int y, int z, Material fluidType)

Better code

RenderBlocks

public boolean renderBlockFluids(Block block, int x, int y, int z) {
    ...
    double var24 = (double) this.getFluidHeight(x, z, x, y, z, var22);
    double var26 = (double) this.getFluidHeight(x, z, x, y, z + 1, var22);
    double var28 = (double) this.getFluidHeight(x, z, x + 1, y, z + 1, var22);
    double var30 = (double) this.getFluidHeight(x, z, x + 1, y, z, var22);
    ...
}

private float getFluidHeight(int blockx, int bloxkz, int x, int y, int z, Material fluidType) {
    int var5 = 0;
    float var6 = 0.0F;
        
    for (int direction = 0; direction < 4; ++direction) {
        int checkX = x - (direction & 1);
        int checkZ = z - (direction >> 1 & 1);

        if (this.blockAccess.getBlockMaterial(checkX, y + 1, checkZ) == fluidType) {
            // These are checks that there is actually a suitable path for the fluid from that block to this block so that its level can affect.
            if (checkX == blockx && checkZ == blockz) // Directly above
                return 1.0F;
            if (checkX != blockx && checkZ != blockz) { // Diagonal in every way
                // Does not affect directly at all.
            } else { // Diagonal in one main direction
                // If there is same fluid above this block, then 1.0
                if (this.blockAccess.getBlockMaterial(blockx, y + 1, blockz) == fluidType)
                    return 1.0F;
                // If there is same fluid under that block, then 1.0
                if (this.blockAccess.getBlockMaterial(checkX, y, checkZ) == fluidType)
                    return 1.0F;
            }
        }

        Material checkedMaterial = this.blockAccess.getBlockMaterial(checkX, y, checkZ);

        if (checkedMaterial == fluidType) {
            // The diagonal neighbor block must have a path of same fluid to this block, or skip its effect:
            if (checkX != blockx && checkZ != blockz
                    && (this.blockAccess.getBlockMaterial(checkX, y, blockz) != fluidType
                    && this.blockAccess.getBlockMaterial(blockx, y, checkZ) != fluidType)) {
                continue;
            } else {
                int checkedMeta = this.blockAccess.getBlockMetadata(checkX, y, checkZ);

                if (checkedMeta >= 8 || checkedMeta == 0) {
                    var6 += BlockFluid.getFluidHeightPercent(checkedMeta) * 10.0F;
                    var5 += 10;
                }

                var6 += BlockFluid.getFluidHeightPercent(checkedMeta);
                ++var5;
            }
        } else if (!checkedMaterial.isSolid()) {
            // Non-solid makes the level lower
            // If it is in diagonal neighbor, then there must be non-solid path, or skip its effect:
            if (checkX != blockx && checkZ != blockz
                    && (this.blockAccess.getBlockMaterial(checkX, y, blockz).isSolid()
                    && this.blockAccess.getBlockMaterial(blockx, y, checkZ).isSolid()))
                continue;
            ++var6;
            ++var5;
        }
    }

    return 1.0F - var6 / (float) var5;
}

I will attach a screenshot showing the results (for the changed rendering; there are other cases of rendering, which I managed to mess up temporarily while working on the fix, but since they haven't changed with the version above, I won't include screenshots of those.)

25 more comments

Can confirm in 21w42a.

can confirm in 1.17.1 and added another example:

[media]

(the orange blocks are normal solid blocks and the fences on top are all waterlogged and blocked with sings.)

Oh and it doesn't look at all like never fixing these old issues didn't create any new problems later on.... (<- be aware of the sarcasm! And I'm not sure if the amount of negations is right in there)

-> MC-239475, MC-228434 and more...

Can confirm in 21w44a.

I got a similar issue to this bug MC-236748

with a quarter-waterlogged big dripleaf. 

Version: 1.18.1-pre1

The glitch persists after server restart and client restart.

[media]

FireHunterX

muzikbike

(Unassigned)

Confirmed

Low

Rendering

fluid-geometry

Minecraft 1.4.5, Snapshot 12w49a, Snapshot 12w50a, Minecraft 1.4.6, Minecraft 1.4.7, ..., 21w42a, 21w44a, 1.18 Pre-release 1, 1.18 Pre-release 5, 1.18.1

22w05a

Retrieved