From e1e8ed0ba3658253cf28c28fe0e489f8a4e4663f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:29:50 -0500 Subject: [PATCH 1/4] Add a hook for blocks to suppress a neighboring fluid overlay --- .../block/LiquidBlockRenderer.java.patch | 44 ++++++++++++++++++- .../common/extensions/IBlockExtension.java | 4 ++ .../extensions/IBlockStateExtension.java | 7 +++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch b/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch index f2ca146f9c..fbbe5ae620 100644 --- a/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch @@ -1,6 +1,6 @@ --- 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(); @@ -8,8 +8,29 @@ } 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) { ++ return otherState.shouldHideAdjacentFluidFace(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 p_203169_, BlockState p_203170_, Direction p_203171_, BlockState otherState) { ++ return !isFaceOccludedBySelf(p_203170_, p_203171_) && !isNeighborStateHidingOverlay(p_203169_, otherState); ++ } ++ 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; @@ -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); ++ 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; diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java index 813b8a398f..a8e6257950 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java @@ -1019,4 +1019,8 @@ default BubbleColumnDirection getBubbleColumnDirection(BlockState state) { return BubbleColumnDirection.NONE; } } + + default boolean shouldHideAdjacentFluidFace(BlockState state, FluidState adjacentFluid) { + return state.getFluidState().getType().isSame(adjacentFluid.getType()); + } } diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java index 3e08a8b5b0..9048859b81 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java @@ -755,4 +755,11 @@ default boolean isEmpty() { default BubbleColumnDirection getBubbleColumnDirection() { return self().getBlock().getBubbleColumnDirection(self()); } + + /** + * Return true if this block should cause an adjacent face of the given fluid to not render. + */ + default boolean shouldHideAdjacentFluidFace(FluidState adjacentFluid) { + return self().getBlock().shouldHideAdjacentFluidFace(self(), adjacentFluid); + } } From 0420c15591299a351ad4fbbbf1c628a19f121ccb Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 23 Nov 2024 14:35:50 -0500 Subject: [PATCH 2/4] Address review comments --- .../renderer/block/LiquidBlockRenderer.java.patch | 12 ++++++------ .../neoforge/common/extensions/IBlockExtension.java | 10 +++++++++- .../common/extensions/IBlockStateExtension.java | 12 ++++++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch b/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch index fbbe5ae620..72aee1fb3e 100644 --- a/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch @@ -11,8 +11,8 @@ return p_203187_.getType().isSame(p_203186_.getType()); } -+ private static boolean isNeighborStateHidingOverlay(FluidState selfState, BlockState otherState) { -+ return otherState.shouldHideAdjacentFluidFace(selfState); ++ 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_) { @@ -22,13 +22,13 @@ return isFaceOccludedByState(p_110963_.getOpposite(), 1.0F, p_110962_); } -+ @Deprecated // Neo: use overload that accepts BlockState ++ /** @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 p_203169_, BlockState p_203170_, Direction p_203171_, BlockState otherState) { -+ return !isFaceOccludedBySelf(p_203170_, p_203171_) && !isNeighborStateHidingOverlay(p_203169_, otherState); ++ 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_) { @@ -51,7 +51,7 @@ - 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); ++ 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); diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java index a8e6257950..f20dcdec2f 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockExtension.java @@ -1020,7 +1020,15 @@ default BubbleColumnDirection getBubbleColumnDirection(BlockState state) { } } - default boolean shouldHideAdjacentFluidFace(BlockState state, FluidState adjacentFluid) { + /** + * 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()); } } diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java index 9048859b81..ce05f6783f 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IBlockStateExtension.java @@ -757,9 +757,13 @@ default BubbleColumnDirection getBubbleColumnDirection() { } /** - * Return true if this block should cause an adjacent face of the given fluid to not render. - */ - default boolean shouldHideAdjacentFluidFace(FluidState adjacentFluid) { - return self().getBlock().shouldHideAdjacentFluidFace(self(), adjacentFluid); + * 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); } } From e5b5074e48c19e240548dc77f35270f75581dd41 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 23 Nov 2024 16:36:10 -0500 Subject: [PATCH 3/4] Add test --- .../blockstates/water_glass.json | 7 ++ .../lang/en_us.json | 3 + .../models/block/water_glass.json | 7 ++ .../debug/fluid/ClientFluidTests.java | 67 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/blockstates/water_glass.json create mode 100644 tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/lang/en_us.json create mode 100644 tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/models/block/water_glass.json create mode 100644 tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java diff --git a/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/blockstates/water_glass.json b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/blockstates/water_glass.json new file mode 100644 index 0000000000..ed35a1c6c0 --- /dev/null +++ b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/blockstates/water_glass.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "neotests_test_water_glass_face_removal:block/water_glass" + } + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/lang/en_us.json b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/lang/en_us.json new file mode 100644 index 0000000000..e016ca7125 --- /dev/null +++ b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "block.neotests_test_water_glass_face_removal.water_glass": "Water Glass" +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/models/block/water_glass.json b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/models/block/water_glass.json new file mode 100644 index 0000000000..10740130a9 --- /dev/null +++ b/tests/src/generated/resources/assets/neotests_test_water_glass_face_removal/models/block/water_glass.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/cube_all", + "render_type": "minecraft:cutout", + "textures": { + "all": "minecraft:block/glass" + } +} \ No newline at end of file diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java new file mode 100644 index 0000000000..2b78d46f0c --- /dev/null +++ b/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java @@ -0,0 +1,67 @@ +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()); + } +} From c73344c9378ba7aa3f5c792f6c0ff64e81b96296 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 23 Nov 2024 16:39:34 -0500 Subject: [PATCH 4/4] Add license header --- .../net/neoforged/neoforge/debug/fluid/ClientFluidTests.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java index 2b78d46f0c..cc40433fce 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/fluid/ClientFluidTests.java @@ -1,3 +1,8 @@ +/* + * 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;