Skip to content

Commit

Permalink
Add a hook for blocks to suppress a neighboring fluid overlay (#1690)
Browse files Browse the repository at this point in the history
  • Loading branch information
embeddedt authored Nov 24, 2024
1 parent b91dba8 commit bc0cdb7
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
--- a/net/minecraft/client/renderer/block/LiquidBlockRenderer.java
+++ b/net/minecraft/client/renderer/block/LiquidBlockRenderer.java
@@ -37,6 +_,7 @@
@@ -37,12 +_,17 @@
this.waterIcons[0] = Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(Blocks.WATER.defaultBlockState()).getParticleIcon();
this.waterIcons[1] = ModelBakery.WATER_FLOW.sprite();
this.waterOverlay = ModelBakery.WATER_OVERLAY.sprite();
+ net.neoforged.neoforge.client.textures.FluidSpriteCache.reload();
}

private static boolean isNeighborSameFluid(FluidState p_203186_, FluidState p_203187_) {
@@ -70,8 +_,9 @@
return p_203187_.getType().isSame(p_203186_.getType());
}

+ private static boolean isNeighborStateHidingOverlay(FluidState selfState, BlockState otherState, Direction neighborFace) {
+ return otherState.shouldHideAdjacentFluidFace(neighborFace, selfState);
+ }
+
private static boolean isFaceOccludedByState(Direction p_110980_, float p_110981_, BlockState p_110983_) {
VoxelShape voxelshape = p_110983_.getFaceOcclusionShape(p_110980_.getOpposite());
if (voxelshape == Shapes.empty()) {
@@ -64,14 +_,20 @@
return isFaceOccludedByState(p_110963_.getOpposite(), 1.0F, p_110962_);
}

+ /** @deprecated Neo: use overload that accepts BlockState */
public static boolean shouldRenderFace(FluidState p_203169_, BlockState p_203170_, Direction p_203171_, FluidState p_203172_) {
return !isFaceOccludedBySelf(p_203170_, p_203171_) && !isNeighborSameFluid(p_203169_, p_203172_);
}

+ public static boolean shouldRenderFace(FluidState fluidState, BlockState selfState, Direction direction, BlockState otherState) {
+ return !isFaceOccludedBySelf(selfState, direction) && !isNeighborStateHidingOverlay(fluidState, otherState, direction.getOpposite());
+ }
+
public void tesselate(BlockAndTintGetter p_234370_, BlockPos p_234371_, VertexConsumer p_234372_, BlockState p_234373_, FluidState p_234374_) {
boolean flag = p_234374_.is(FluidTags.LAVA);
- TextureAtlasSprite[] atextureatlassprite = flag ? this.lavaIcons : this.waterIcons;
Expand All @@ -20,6 +41,25 @@
float f = (float)(i >> 16 & 0xFF) / 255.0F;
float f1 = (float)(i >> 8 & 0xFF) / 255.0F;
float f2 = (float)(i & 0xFF) / 255.0F;
@@ -87,12 +_,12 @@
FluidState fluidstate4 = blockstate4.getFluidState();
BlockState blockstate5 = p_234370_.getBlockState(p_234371_.relative(Direction.EAST));
FluidState fluidstate5 = blockstate5.getFluidState();
- boolean flag1 = !isNeighborSameFluid(p_234374_, fluidstate1);
- boolean flag2 = shouldRenderFace(p_234374_, p_234373_, Direction.DOWN, fluidstate) && !isFaceOccludedByNeighbor(Direction.DOWN, 0.8888889F, blockstate);
- boolean flag3 = shouldRenderFace(p_234374_, p_234373_, Direction.NORTH, fluidstate2);
- boolean flag4 = shouldRenderFace(p_234374_, p_234373_, Direction.SOUTH, fluidstate3);
- boolean flag5 = shouldRenderFace(p_234374_, p_234373_, Direction.WEST, fluidstate4);
- boolean flag6 = shouldRenderFace(p_234374_, p_234373_, Direction.EAST, fluidstate5);
+ boolean flag1 = !isNeighborStateHidingOverlay(p_234374_, blockstate1, Direction.DOWN);
+ boolean flag2 = shouldRenderFace(p_234374_, p_234373_, Direction.DOWN, blockstate) && !isFaceOccludedByNeighbor(Direction.DOWN, 0.8888889F, blockstate);
+ boolean flag3 = shouldRenderFace(p_234374_, p_234373_, Direction.NORTH, blockstate2);
+ boolean flag4 = shouldRenderFace(p_234374_, p_234373_, Direction.SOUTH, blockstate3);
+ boolean flag5 = shouldRenderFace(p_234374_, p_234373_, Direction.WEST, blockstate4);
+ boolean flag6 = shouldRenderFace(p_234374_, p_234373_, Direction.EAST, blockstate5);
if (flag1 || flag2 || flag6 || flag5 || flag3 || flag4) {
float f3 = p_234370_.getShade(Direction.DOWN, true);
float f4 = p_234370_.getShade(Direction.UP, true);
@@ -180,15 +_,15 @@
float f57 = f4 * f;
float f29 = f4 * f1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1019,4 +1019,16 @@ default BubbleColumnDirection getBubbleColumnDirection(BlockState state) {
return BubbleColumnDirection.NONE;
}
}

/**
* Determines if a fluid adjacent to the block on the given side should not be rendered.
*
* @param state the block state of the block
* @param selfFace the face of this block that the fluid is adjacent to
* @param adjacentFluid the fluid that is touching that face
* @return true if this block should cause the fluid's face to not render
*/
default boolean shouldHideAdjacentFluidFace(BlockState state, Direction selfFace, FluidState adjacentFluid) {
return state.getFluidState().getType().isSame(adjacentFluid.getType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -755,4 +755,15 @@ default boolean isEmpty() {
default BubbleColumnDirection getBubbleColumnDirection() {
return self().getBlock().getBubbleColumnDirection(self());
}

/**
* Determines if a fluid adjacent to the block on the given side should not be rendered.
*
* @param selfFace the face of this block that the fluid is adjacent to
* @param adjacentFluid the fluid that is touching that face
* @return true if this block should cause the fluid's face to not render
*/
default boolean shouldHideAdjacentFluidFace(Direction selfFace, FluidState adjacentFluid) {
return self().getBlock().shouldHideAdjacentFluidFace(self(), selfFace, adjacentFluid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "neotests_test_water_glass_face_removal:block/water_glass"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"block.neotests_test_water_glass_face_removal.water_glass": "Water Glass"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"parent": "minecraft:block/cube_all",
"render_type": "minecraft:cutout",
"textures": {
"all": "minecraft:block/glass"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.debug.fluid;

import net.minecraft.client.renderer.block.LiquidBlockRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.TransparentBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.neoforge.client.model.generators.BlockStateProvider;
import net.neoforged.testframework.DynamicTest;
import net.neoforged.testframework.annotation.ForEachTest;
import net.neoforged.testframework.annotation.TestHolder;
import net.neoforged.testframework.gametest.EmptyTemplate;
import net.neoforged.testframework.registration.RegistrationHelper;

@ForEachTest(groups = ClientFluidTests.GROUP, side = Dist.CLIENT)
public class ClientFluidTests {
public static final String GROUP = "level.fluid.client";

static class WaterGlassBlock extends TransparentBlock {
private static final Direction HIDE_DIRECTION = Direction.NORTH;

public WaterGlassBlock(Properties p_309186_) {
super(p_309186_);
}

@Override
public boolean shouldHideAdjacentFluidFace(BlockState state, Direction selfFace, FluidState adjacentFluid) {
if (selfFace == HIDE_DIRECTION) {
return adjacentFluid.getFluidType() == Fluids.WATER.getFluidType();
} else {
return super.shouldHideAdjacentFluidFace(state, selfFace, adjacentFluid);
}
}
}

@GameTest
@EmptyTemplate
@TestHolder(description = "Tests if blocks can prevent neighboring fluids from rendering against them")
static void testWaterGlassFaceRemoval(final DynamicTest test, final RegistrationHelper reg) {
final var glass = reg.blocks().registerBlock("water_glass", WaterGlassBlock::new, BlockBehaviour.Properties.ofFullCopy(Blocks.GLASS)).withLang("Water Glass").withBlockItem();
reg.provider(BlockStateProvider.class, prov -> prov.simpleBlock(glass.get(), prov.models()
.cubeAll("water_glass", ResourceLocation.withDefaultNamespace("block/glass"))
.renderType("cutout")));
final var waterPosition = new BlockPos(1, 1, 2);
final var glassDirection = WaterGlassBlock.HIDE_DIRECTION.getOpposite();
final var glassPosition = waterPosition.relative(glassDirection);
test.onGameTest(helper -> helper.startSequence()
.thenExecute(() -> helper.setBlock(glassPosition, glass.get().defaultBlockState()))
.thenExecute(() -> helper.setBlock(waterPosition, Blocks.WATER.defaultBlockState()))
// Check that the north side of the water is not rendered
.thenExecute(() -> helper.assertFalse(
LiquidBlockRenderer.shouldRenderFace(
helper.getBlockState(waterPosition).getFluidState(),
helper.getBlockState(waterPosition),
glassDirection,
helper.getBlockState(glassPosition)),
"Fluid face rendering is not skipped"))
.thenSucceed());
}
}

0 comments on commit bc0cdb7

Please sign in to comment.