diff --git a/patches/net/minecraft/client/renderer/SubmitNodeCollection.java.patch b/patches/net/minecraft/client/renderer/SubmitNodeCollection.java.patch new file mode 100644 index 00000000000..fec933d1732 --- /dev/null +++ b/patches/net/minecraft/client/renderer/SubmitNodeCollection.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/client/renderer/SubmitNodeCollection.java ++++ b/net/minecraft/client/renderer/SubmitNodeCollection.java +@@ -40,6 +_,7 @@ + private final List blockSubmits = new ArrayList<>(); + private final List movingBlockSubmits = new ArrayList<>(); + private final List blockModelSubmits = new ArrayList<>(); ++ private final List extendedBlockModelSubmits = new ArrayList<>(); + private final List itemSubmits = new ArrayList<>(); + private final List particleGroupRenderers = new ArrayList<>(); + private final ModelFeatureRenderer.Storage modelSubmits = new ModelFeatureRenderer.Storage(); +@@ -178,6 +_,15 @@ + } + + @Override ++ public void submitBlockModel( ++ PoseStack poseStack, BlockState state, BlockStateModel model, float r, float g, float b, int lightCoords, int overlayCoords, int outlineColor ++ ) { ++ this.wasUsed = true; ++ this.extendedBlockModelSubmits ++ .add(new SubmitNodeStorage.ExtendedBlockModelSubmit(poseStack.last().copy(), state, model, r, g, b, lightCoords, overlayCoords, outlineColor)); ++ } ++ ++ @Override + public void submitItem( + PoseStack poseStack, + ItemDisplayContext displayContext, +@@ -242,6 +_,11 @@ + return this.blockModelSubmits; + } + ++ /** NeoForge: expose extended block model submits with support for per-part render types */ ++ public List getExtendedBlockModelSubmits() { ++ return this.extendedBlockModelSubmits; ++ } ++ + public ModelPartFeatureRenderer.Storage getModelPartSubmits() { + return this.modelPartSubmits; + } +@@ -275,6 +_,7 @@ + this.blockSubmits.clear(); + this.movingBlockSubmits.clear(); + this.blockModelSubmits.clear(); ++ this.extendedBlockModelSubmits.clear(); + this.itemSubmits.clear(); + this.particleGroupRenderers.clear(); + this.modelSubmits.clear(); diff --git a/patches/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch b/patches/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch index 94bdd34886a..24d12aad998 100644 --- a/patches/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch +++ b/patches/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch @@ -35,7 +35,7 @@ Objects.requireNonNull(this.liquidBlockRenderer).tesselate(level, pos, builder, blockState, fluidState); } catch (Throwable var9) { CrashReport report = CrashReport.forThrowable(var9, "Tesselating liquid in world"); -@@ -90,7 +_,12 @@ +@@ -90,7 +_,16 @@ return this.blockModelShaper.getBlockModel(state); } @@ -45,6 +45,10 @@ + } + + public void renderSingleBlock(BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, int lightCoords, int overlayCoords, BlockAndTintGetter level, BlockPos pos) { ++ renderSingleBlock(state, poseStack, bufferSource, lightCoords, overlayCoords, level, pos, null); ++ } ++ ++ public void renderSingleBlock(BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, int lightCoords, int overlayCoords, BlockAndTintGetter level, BlockPos pos, java.util.function.@Nullable Predicate chunkLayerFilter) { RenderShape shape = state.getRenderShape(); if (shape != RenderShape.INVISIBLE) { BlockStateModel model = this.getBlockModel(state); @@ -53,7 +57,7 @@ float b = (col & 0xFF) / 255.0F; ModelBlockRenderer.renderModel( - poseStack.last(), bufferSource.getBuffer(ItemBlockRenderTypes.getRenderType(state)), model, r, g, b, lightCoords, overlayCoords -+ poseStack.last(), bufferSource, model, r, g, b, lightCoords, overlayCoords, level, pos, state ++ poseStack.last(), bufferSource, model, r, g, b, lightCoords, overlayCoords, level, pos, state, chunkLayerFilter ); } } diff --git a/patches/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch b/patches/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch index d355d927659..df952adb0cc 100644 --- a/patches/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch @@ -241,7 +241,7 @@ shapeState.lightmap[0] = lightCoords; shapeState.lightmap[1] = lightCoords; shapeState.lightmap[2] = lightCoords; -@@ -309,10 +_,18 @@ +@@ -309,10 +_,27 @@ } } @@ -256,8 +256,17 @@ + public static void renderModel( + PoseStack.Pose pose, net.minecraft.client.renderer.MultiBufferSource bufferSource, BlockStateModel model, float r, float g, float b, int lightCoords, int overlayCoords, net.minecraft.world.level.BlockAndTintGetter level, BlockPos pos, BlockState state + ) { ++ renderModel(pose, bufferSource, model, r, g, b, lightCoords, overlayCoords, level, pos, state, null); ++ } ++ ++ public static void renderModel( ++ PoseStack.Pose pose, net.minecraft.client.renderer.MultiBufferSource bufferSource, BlockStateModel model, float r, float g, float b, int lightCoords, int overlayCoords, net.minecraft.world.level.BlockAndTintGetter level, BlockPos pos, BlockState state, java.util.function.@org.jspecify.annotations.Nullable Predicate chunkLayerFilter ++ ) { + for (BlockModelPart part : model.collectParts(level, pos, state, RandomSource.create(42L))) { -+ VertexConsumer builder = bufferSource.getBuffer(net.neoforged.neoforge.client.RenderTypeHelper.getEntityRenderType(part.getRenderType(state))); ++ net.minecraft.client.renderer.chunk.ChunkSectionLayer chunkLayer = part.getRenderType(state); ++ if (chunkLayerFilter != null && !chunkLayerFilter.test(chunkLayer)) continue; ++ ++ VertexConsumer builder = bufferSource.getBuffer(net.neoforged.neoforge.client.RenderTypeHelper.getEntityRenderType(chunkLayer)); for (Direction direction : DIRECTIONS) { renderQuadList(pose, builder, r, g, b, part.getQuads(direction), lightCoords, overlayCoords); } diff --git a/patches/net/minecraft/client/renderer/entity/layers/SnowGolemHeadLayer.java.patch b/patches/net/minecraft/client/renderer/entity/layers/SnowGolemHeadLayer.java.patch new file mode 100644 index 00000000000..3e9a0da4c9f --- /dev/null +++ b/patches/net/minecraft/client/renderer/entity/layers/SnowGolemHeadLayer.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/client/renderer/entity/layers/SnowGolemHeadLayer.java ++++ b/net/minecraft/client/renderer/entity/layers/SnowGolemHeadLayer.java +@@ -43,6 +_,9 @@ + RenderType renderType = state.appearsGlowing() && state.isInvisible + ? RenderTypes.outline(TextureAtlas.LOCATION_BLOCKS) + : ItemBlockRenderTypes.getRenderType(pumpkinBlockState); ++ if (!state.appearsGlowing() || !state.isInvisible) { ++ submitNodeCollector.submitBlockModel(poseStack, pumpkinBlockState, model, 0.0F, 0.0F, 0.0F, lightCoords, overlayCoords, state.outlineColor); ++ } else + submitNodeCollector.submitBlockModel(poseStack, renderType, model, 0.0F, 0.0F, 0.0F, lightCoords, overlayCoords, state.outlineColor); + poseStack.popPose(); + } diff --git a/patches/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java.patch b/patches/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java.patch index 39ae1e17d76..97e93455159 100644 --- a/patches/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java.patch @@ -1,21 +1,66 @@ --- a/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java +++ b/net/minecraft/client/renderer/feature/BlockFeatureRenderer.java -@@ -53,7 +_,7 @@ - RenderType renderType = ItemBlockRenderTypes.getMovingBlockRenderType(blockState); - if (renderType.hasBlending() == translucent) { +@@ -47,13 +_,18 @@ + private void renderMovingBlockSubmits( + SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, BlockRenderDispatcher blockRenderDispatcher, boolean translucent + ) { ++ if (nodeCollection.getMovingBlockSubmits().isEmpty()) return; ++ java.util.function.Function bufferLookup = ++ chunkLayer -> bufferSource.getBuffer(net.neoforged.neoforge.client.RenderTypeHelper.getMovingBlockRenderType(chunkLayer)); + for (SubmitNodeStorage.MovingBlockSubmit submit : nodeCollection.getMovingBlockSubmits()) { + MovingBlockRenderState movingBlockRenderState = submit.movingBlockRenderState(); + BlockState blockState = movingBlockRenderState.blockState; +- RenderType renderType = ItemBlockRenderTypes.getMovingBlockRenderType(blockState); +- if (renderType.hasBlending() == translucent) { ++ // Neo: bypass single-rendertype blending check ++ if (true) { List parts = blockRenderDispatcher.getBlockModel(blockState) - .collectParts(RandomSource.create(blockState.getSeed(movingBlockRenderState.randomSeedPos))); + .collectParts(movingBlockRenderState.level, movingBlockRenderState.blockPos, movingBlockRenderState.blockState, RandomSource.create(blockState.getSeed(movingBlockRenderState.randomSeedPos))); ++ // Neo: filter out parts using a render type which does not match the translucent flag ++ parts.removeIf(part -> part.getRenderType(blockState).sortOnUpload() != translucent); PoseStack poseStack = new PoseStack(); poseStack.mulPose(submit.pose()); blockRenderDispatcher.getModelRenderer() -@@ -63,7 +_,8 @@ +@@ -63,7 +_,7 @@ blockState, movingBlockRenderState.blockPos, poseStack, - bufferSource.getBuffer(renderType), -+ // TODO: this needs further thought as it violates the "one submit == one rendertype" contract -+ partRenderType -> bufferSource.getBuffer(net.neoforged.neoforge.client.RenderTypeHelper.getMovingBlockRenderType(partRenderType)), ++ bufferLookup, false, OverlayTexture.NO_OVERLAY ); +@@ -78,15 +_,18 @@ + OutlineBufferSource outlineBufferSource, + boolean translucent + ) { ++ if (nodeCollection.getBlockSubmits().isEmpty()) return; ++ java.util.function.Predicate chunkLayerFilter = ++ translucent ? layer -> layer.sortOnUpload() : layer -> !layer.sortOnUpload(); + for (SubmitNodeStorage.BlockSubmit submit : nodeCollection.getBlockSubmits()) { +- RenderType renderType = ItemBlockRenderTypes.getRenderType(submit.state()); +- if (renderType.hasBlending() == translucent) { ++ // Neo: bypass single-rendertype blending check ++ if (true) { + this.poseStack.pushPose(); + this.poseStack.last().set(submit.pose()); +- blockRenderDispatcher.renderSingleBlock(submit.state(), this.poseStack, bufferSource, submit.lightCoords(), submit.overlayCoords()); ++ blockRenderDispatcher.renderSingleBlock(submit.state(), this.poseStack, bufferSource, submit.lightCoords(), submit.overlayCoords(), net.minecraft.world.level.EmptyBlockAndTintGetter.INSTANCE, net.minecraft.core.BlockPos.ZERO, chunkLayerFilter); + if (submit.outlineColor() != 0) { + outlineBufferSource.setColor(submit.outlineColor()); +- blockRenderDispatcher.renderSingleBlock(submit.state(), this.poseStack, outlineBufferSource, submit.lightCoords(), submit.overlayCoords()); ++ blockRenderDispatcher.renderSingleBlock(submit.state(), this.poseStack, outlineBufferSource, submit.lightCoords(), submit.overlayCoords(), net.minecraft.world.level.EmptyBlockAndTintGetter.INSTANCE, net.minecraft.core.BlockPos.ZERO, chunkLayerFilter); + } + + this.poseStack.popPose(); +@@ -97,6 +_,9 @@ + private void renderBlockModelSubmits( + SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource, boolean translucent + ) { ++ // Neo: render extended block model submits with support for per-part render types ++ renderExtendedBlockModelSubmits(nodeCollection.getExtendedBlockModelSubmits(), bufferSource, outlineBufferSource, translucent); ++ + for (SubmitNodeStorage.BlockModelSubmit submit : nodeCollection.getBlockModelSubmits()) { + if (submit.renderType().hasBlending() == translucent) { + ModelBlockRenderer.renderModel( diff --git a/src/client/java/net/neoforged/neoforge/client/extensions/BlockFeatureRendererExtension.java b/src/client/java/net/neoforged/neoforge/client/extensions/BlockFeatureRendererExtension.java new file mode 100644 index 00000000000..449b98968e1 --- /dev/null +++ b/src/client/java/net/neoforged/neoforge/client/extensions/BlockFeatureRendererExtension.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.extensions; + +import java.util.List; +import java.util.function.Predicate; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.OutlineBufferSource; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; + +public interface BlockFeatureRendererExtension { + default void renderExtendedBlockModelSubmits( + List submits, + MultiBufferSource.BufferSource bufferSource, + OutlineBufferSource outlineBufferSource, + boolean translucent) { + if (submits.isEmpty()) return; + + Predicate chunkLayerFilter = translucent ? ChunkSectionLayer::sortOnUpload : layer -> !layer.sortOnUpload(); + for (SubmitNodeStorage.ExtendedBlockModelSubmit submit : submits) { + ModelBlockRenderer.renderModel( + submit.pose(), + bufferSource, + submit.model(), + submit.r(), + submit.g(), + submit.b(), + submit.lightCoords(), + submit.overlayCoords(), + net.minecraft.world.level.EmptyBlockAndTintGetter.INSTANCE, + net.minecraft.core.BlockPos.ZERO, + submit.state(), + chunkLayerFilter); + if (submit.outlineColor() != 0) { + outlineBufferSource.setColor(submit.outlineColor()); + ModelBlockRenderer.renderModel( + submit.pose(), + outlineBufferSource, + submit.model(), + submit.r(), + submit.g(), + submit.b(), + submit.lightCoords(), + submit.overlayCoords(), + net.minecraft.world.level.EmptyBlockAndTintGetter.INSTANCE, + net.minecraft.core.BlockPos.ZERO, + submit.state(), + chunkLayerFilter); + } + } + } +} diff --git a/src/client/java/net/neoforged/neoforge/client/extensions/OrderedSubmitNodeCollectorExtension.java b/src/client/java/net/neoforged/neoforge/client/extensions/OrderedSubmitNodeCollectorExtension.java new file mode 100644 index 00000000000..95233342f01 --- /dev/null +++ b/src/client/java/net/neoforged/neoforge/client/extensions/OrderedSubmitNodeCollectorExtension.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.extensions; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.OrderedSubmitNodeCollector; +import net.minecraft.client.renderer.block.model.BlockModelPart; +import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.world.level.block.state.BlockState; + +public interface OrderedSubmitNodeCollectorExtension { + private OrderedSubmitNodeCollector self() { + return (OrderedSubmitNodeCollector) this; + } + + /** + * Extended version of {@link OrderedSubmitNodeCollector#submitBlockModel(PoseStack, RenderType, BlockStateModel, float, float, float, int, int, int)} with + * support for per-{@link BlockModelPart} {@link ChunkSectionLayer} lookup based on the provided {@link BlockState}. + * + * @param poseStack The {@code PoseStack} to render the model with + * @param state The {@code BlockState} to use for per-part {@code ChunkSectionLayer} lookup + * @param model The model to render + * @param r The red channel color multiplier + * @param g The green channel color multiplier + * @param b The blue channel color multiplier + * @param lightCoords The packed light value to render the model with + * @param overlayCoords The overlay coordinates to render the model with + * @param outlineColor The outline color to render the model with or {@code 0} to not render an outline + * the provided {@code RenderType} to be used + */ + default void submitBlockModel( + PoseStack poseStack, + BlockState state, + BlockStateModel model, + float r, + float g, + float b, + int lightCoords, + int overlayCoords, + int outlineColor) { + self().submitBlockModel(poseStack, ItemBlockRenderTypes.getRenderType(state), model, r, g, b, lightCoords, overlayCoords, outlineColor); + } +} diff --git a/src/client/java/net/neoforged/neoforge/client/extensions/SubmitNodeStorageExtension.java b/src/client/java/net/neoforged/neoforge/client/extensions/SubmitNodeStorageExtension.java new file mode 100644 index 00000000000..7defa284c53 --- /dev/null +++ b/src/client/java/net/neoforged/neoforge/client/extensions/SubmitNodeStorageExtension.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.extensions; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.world.level.block.state.BlockState; + +public interface SubmitNodeStorageExtension extends OrderedSubmitNodeCollectorExtension { + private SubmitNodeStorage self() { + return (SubmitNodeStorage) this; + } + + @Override + default void submitBlockModel( + PoseStack poseStack, + BlockState state, + BlockStateModel model, + float r, + float g, + float b, + int lightCoords, + int overlayCoords, + int outlineColor) { + self().order(0).submitBlockModel(poseStack, state, model, r, g, b, lightCoords, overlayCoords, outlineColor); + } + + record ExtendedBlockModelSubmit( + PoseStack.Pose pose, + BlockState state, + BlockStateModel model, + float r, + float g, + float b, + int lightCoords, + int overlayCoords, + int outlineColor) {} +} diff --git a/src/main/resources/META-INF/injected-interfaces.json b/src/main/resources/META-INF/injected-interfaces.json index 6bdff7e2d15..22a4fac744b 100644 --- a/src/main/resources/META-INF/injected-interfaces.json +++ b/src/main/resources/META-INF/injected-interfaces.json @@ -26,6 +26,12 @@ "net/minecraft/client/gui/GuiGraphics": [ "net/neoforged/neoforge/client/extensions/IGuiGraphicsExtension" ], + "net/minecraft/client/renderer/OrderedSubmitNodeCollector": [ + "net/neoforged/neoforge/client/extensions/OrderedSubmitNodeCollectorExtension" + ], + "net/minecraft/client/renderer/SubmitNodeStorage": [ + "net/neoforged/neoforge/client/extensions/SubmitNodeStorageExtension" + ], "net/minecraft/client/renderer/block/model/BlockModelPart": [ "net/neoforged/neoforge/client/extensions/BlockModelPartExtension" ], @@ -35,6 +41,9 @@ "net/minecraft/client/renderer/blockentity/BlockEntityRenderer": [ "net/neoforged/neoforge/client/extensions/IBlockEntityRendererExtension" ], + "net/minecraft/client/renderer/feature/BlockFeatureRenderer": [ + "net/neoforged/neoforge/client/extensions/BlockFeatureRendererExtension" + ], "net/minecraft/client/renderer/texture/atlas/SpriteSource": [ "net/neoforged/neoforge/client/extensions/SpriteSourceExtension" ],