client.getBlockRenderManager().renderFluid Doesn't Work In BlockEntityRenderer
TheBrokenRail opened this issue ยท 9 comments
It doesn't crash, or break obviously, it just doesn't render anything. this is in a block entity. I know for sure that there is water there because it is forming obsidian with the lava.
My Code:
public class MiniaturizerBlockEntityRenderer extends BlockEntityRenderer<MiniaturizerBlockEntity> {
private Random random = new Random();
public MiniaturizerBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) {
super(dispatcher);
}
@Override
public void render(MiniaturizerBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
matrices.push();
matrices.scale(1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE);
ServerWorld world = blockEntity.getMiniturizerWorld();
if (world != null) {
for (int x = 0; x < MiniaturizerBlock.BLOCK_SIZE; x++) {
for (int y = 0; y < MiniaturizerBlock.BLOCK_SIZE; y++) {
for (int z = 0; z < MiniaturizerBlock.BLOCK_SIZE; z++) {
matrices.push();
matrices.translate(x, y, z);
MinecraftClient client = MinecraftClient.getInstance();
BlockPos pos = new BlockPos(x,y, z);
BlockState blockState = world.getBlockState(pos);
if (blockState.getRenderType() != BlockRenderType.INVISIBLE) {
client.getBlockRenderManager().renderBlock(blockState, pos, blockEntity.getMiniturizerWorld(), matrices, vertexConsumers.getBuffer(RenderLayers.getBlockLayer(blockState)), false, random);
}
if (blockState.getBlock().hasBlockEntity()) {
BlockEntity entity = world.getBlockEntity(pos);
if (entity != null) {
BlockEntityRenderDispatcher.INSTANCE.render(entity, tickDelta, matrices, vertexConsumers);
}
}
matrices.pop();
FluidState fluidState = blockState.getFluidState();
if (!fluidState.isEmpty()) {
client.getBlockRenderManager().renderFluid(pos, world, vertexConsumers.getBuffer(RenderLayers.getFluidLayer(fluidState)), fluidState);
}
}
}
}
}
matrices.pop();
}
}
I also did try this with different RenderLayers, it didn't work. I also tried removing fabric-rendering-fluid-v1
, that also didn't o anything.
does the block render? maybe move that matrices.pop()
before FluidState fluidState = blockState.getFluidState();
to after the fluid is rendered
The block renders, as seen in the screenshot. You can also see the result of the water I laced and lava I placed interacting, just no water or lava. I only translated the block render because the fluid render code as far as I can tell, doe the translation on its own, and ChunkBuilder
also only translates the block render. I did test though and it still doesn't render.
I still can't figure it out, I can't find annything else that uses renderFluid()
, I think it might have something to do with VertexConsumerProvider.Immediate
, and LibBlockAttributes even uses a different one https://github.com/AlexIIL/LibBlockAttributes/blob/001f6cd6a2498964f447585a5744a330dcfae54d/src/main/java/alexiil/mc/lib/attributes/fluid/render/FluidVolumeRenderer.java#L195, which I tried to use, but also didn't render. I have no ida why this isn't working. Do you know any other (current) mods that use renderFluid()
?
This is my code now:
public class MiniaturizerBlockEntityRenderer extends BlockEntityRenderer<MiniaturizerBlockEntity> {
private Random random = new Random();
private ExpandingVcp VCPS = new ExpandingVcp();
public MiniaturizerBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) {
super(dispatcher);
}
@Override
public void render(MiniaturizerBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
matrices.push();
matrices.scale(1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE);
ServerWorld world = blockEntity.getMiniturizerWorld();
if (world != null) {
for (int x = 0; x < MiniaturizerBlock.BLOCK_SIZE; x++) {
for (int y = 0; y < MiniaturizerBlock.BLOCK_SIZE; y++) {
for (int z = 0; z < MiniaturizerBlock.BLOCK_SIZE; z++) {
matrices.push();
matrices.translate(x, y, z);
MinecraftClient client = MinecraftClient.getInstance();
BlockPos pos = new BlockPos(x,y, z).add(blockEntity.getOffset());
BlockState blockState = world.getBlockState(pos);
if (blockState.getRenderType() != BlockRenderType.INVISIBLE) {
client.getBlockRenderManager().renderBlock(blockState, pos, blockEntity.getMiniturizerWorld(), matrices, vertexConsumers.getBuffer(RenderLayers.getBlockLayer(blockState)), false, random);
}
if (blockState.getBlock().hasBlockEntity()) {
BlockEntity entity = world.getBlockEntity(pos);
if (entity != null) {
BlockEntityRenderDispatcher.INSTANCE.render(entity, tickDelta, matrices, vertexConsumers);
}
}
matrices.pop();
FluidState fluidState = blockState.getFluidState();
if (!fluidState.isEmpty()) {
RenderLayer layer = RenderLayers.getFluidLayer(fluidState);
client.getBlockRenderManager().renderFluid(pos, world, VCPS.getBuffer(layer), fluidState);
}
VCPS.draw();
}
}
}
}
matrices.pop();
}
/** A simple, auto-expanding {@link VertexConsumerProvider} that can render any number of {@link RenderLayer}'s at
* once, rather than {@link net.minecraft.client.render.VertexConsumerProvider.Immediate
* VertexConsumerProvider.Immediate} which can only render the ones provided to it in a map, and 1 other. */
public static final class ExpandingVcp implements VertexConsumerProvider {
private final List<RenderLayer> before = new ArrayList<>();
private final List<RenderLayer> solid = new ArrayList<>();
private final List<RenderLayer> middle = new ArrayList<>();
private final List<RenderLayer> translucent = new ArrayList<>();
private final List<RenderLayer> after = new ArrayList<>();
private final List<BufferBuilder> availableBuffers = new ArrayList<>();
private final Map<RenderLayer, BufferBuilder> activeBuffers = new HashMap<>();
private final Set<RenderLayer> knownLayers = new HashSet<>();
public ExpandingVcp() {
addLayer(RenderLayer.getSolid());
addLayer(RenderLayer.getCutout());
addLayer(RenderLayer.getCutoutMipped());
addLayer(RenderLayer.getTranslucent());
addLayer(RenderLayer.getTranslucentNoCrumbling());
addLayerAfter(RenderLayer.getGlint());
addLayerAfter(RenderLayer.getEntityGlint());
}
public void addLayer(RenderLayer layer) {
if (knownLayers.add(layer)) {
if (((RenderLayerAccessor) layer).isTranslucent()) {
translucent.add(layer);
} else {
solid.add(layer);
}
}
}
public void addLayerBefore(RenderLayer layer) {
if (knownLayers.add(layer)) {
before.add(layer);
}
}
public void addLayerMiddle(RenderLayer layer) {
if (knownLayers.add(layer)) {
middle.add(layer);
}
}
public void addLayerAfter(RenderLayer layer) {
if (knownLayers.add(layer)) {
after.add(layer);
}
}
@Override
public VertexConsumer getBuffer(RenderLayer layer) {
addLayer(layer);
BufferBuilder buffer = activeBuffers.get(layer);
if (buffer == null) {
if (availableBuffers.isEmpty()) {
buffer = new BufferBuilder(1 << 12);
} else {
buffer = availableBuffers.remove(availableBuffers.size() - 1);
}
activeBuffers.put(layer, buffer);
}
if (!buffer.isBuilding()) {
buffer.begin(layer.getDrawMode(), layer.getVertexFormat());
}
return buffer;
}
public void draw() {
draw(before);
draw(solid);
draw(middle);
draw(translucent);
draw(after);
assert activeBuffers.isEmpty();
}
private void draw(List<RenderLayer> layers) {
for (RenderLayer layer : layers) {
BufferBuilder buffer = activeBuffers.remove(layer);
if (buffer != null) {
layer.draw(buffer, 0, 0, 0);
}
}
}
}
}
How about other blocks in the translucent render layer, like stained glasses, slime block, ice
Other blocks use RenderLayers.getBlockLayer(blockState)
, if I try to use this with fluids, also nothing shows up.
I am now using:
package com.thebrokenrail.gulliverreloaded.mixin;
import com.thebrokenrail.gulliverreloaded.block.MiniaturizerBlockEntity;
import com.thebrokenrail.gulliverreloaded.client.block.MiniaturizerBlockEntityRenderer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.BufferBuilderStorage;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.LightmapTextureManager;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.TexturedRenderLayers;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.util.math.Matrix4f;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Set;
@SuppressWarnings({"SynchronizeOnNonFinalField", "unused"})
@Mixin(WorldRenderer.class)
@Environment(EnvType.CLIENT)
public abstract class MixinWorldRenderer {
@Shadow
@Final
private Set<BlockEntity> noCullingBlockEntities;
@Shadow
@Final
private BufferBuilderStorage bufferBuilders;
@Shadow
@Final
private MinecraftClient client;
@Shadow
protected abstract void checkEmpty(MatrixStack matrix);
@Inject(at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = {"ldc=blockentities"}), method = "render")
public void render(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo info) {
Vec3d vec3d = camera.getPos();
double d = vec3d.getX();
double e = vec3d.getY();
double f = vec3d.getZ();
VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers();
synchronized (noCullingBlockEntities) {
for (BlockEntity blockEntity : noCullingBlockEntities) {
System.out.println(blockEntity);
if (blockEntity instanceof MiniaturizerBlockEntity) {
BlockPos blockPos = blockEntity.getPos();
matrices.push();
matrices.translate((double) blockPos.getX() - d, (double) blockPos.getY() - e, (double) blockPos.getZ() - f);
MiniaturizerBlockEntityRenderer.render((MiniaturizerBlockEntity) blockEntity, tickDelta, matrices, bufferBuilders);
matrices.pop();
}
}
}
checkEmpty(matrices);
}
}
and
@Environment(EnvType.CLIENT)
public class MiniaturizerBlockEntityRenderer {
private static Random random = new Random();
public static void render(MiniaturizerBlockEntity blockEntity, float tickDelta, MatrixStack matrices, BufferBuilderStorage vertexConsumers) {
MinecraftClient client = MinecraftClient.getInstance();
matrices.push();
matrices.push();
matrices.scale(1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE, 1f / MiniaturizerBlock.BLOCK_SIZE);
ServerWorld world = blockEntity.getMiniaturizerWorld();
if (world != null) {
for (int x = 0; x < MiniaturizerBlock.BLOCK_SIZE; x++) {
for (int y = 0; y < MiniaturizerBlock.BLOCK_SIZE; y++) {
for (int z = 0; z < MiniaturizerBlock.BLOCK_SIZE; z++) {
matrices.push();
matrices.translate(x, y, z);
BlockPos pos = new BlockPos(x,y, z).add(blockEntity.getOffset());
BlockState blockState = world.getBlockState(pos);
if (blockState.getRenderType() != BlockRenderType.INVISIBLE) {
RenderLayer layer = RenderLayers.getBlockLayer(blockState);
client.getBlockRenderManager().renderBlock(blockState, pos, blockEntity.getMiniaturizerWorld(), matrices, getBuffer(vertexConsumers, layer), false, random);
drawBuffer(vertexConsumers, layer);
}
if (blockState.getBlock().hasBlockEntity()) {
BlockEntity entity = world.getBlockEntity(pos);
if (entity != null) {
BlockEntityRenderDispatcher.INSTANCE.render(entity, tickDelta, matrices, vertexConsumers.getEntityVertexConsumers());
}
}
matrices.pop();
matrices.push();
FluidState fluidState = blockState.getFluidState();
if (!fluidState.isEmpty()) {
RenderLayer layer = RenderLayers.getFluidLayer(fluidState);
client.getBlockRenderManager().renderFluid(pos, world, getBuffer(vertexConsumers, layer), fluidState);
drawBuffer(vertexConsumers, layer);
}
matrices.pop();
}
}
}
}
matrices.pop();
if (client.player != null && client.player.getMainHandStack().getItem() == GulliverReloaded.MINIATURIZER_ITEM) {
WorldRenderer.drawBox(matrices, vertexConsumers.getEntityVertexConsumers().getBuffer(RenderLayer.getLines()), 0f, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f);
}
matrices.pop();
}
private static BufferBuilder getBuffer(BufferBuilderStorage bufferBuilders, RenderLayer layer) {
BufferBuilder buffer = bufferBuilders.getBlockBufferBuilders().get(layer);
if (!buffer.isBuilding()) {
buffer.begin(7, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
}
return buffer;
}
private static void drawBuffer(BufferBuilderStorage bufferBuilders, RenderLayer layer) {
BufferBuilder buffer = bufferBuilders.getBlockBufferBuilders().get(layer);
layer.draw(buffer, 0, 0, 0);
if (buffer.isBuilding()) {
buffer.end();
}
}
}
and I am getting:
java.lang.IllegalStateException: Not filled all elements of the vertex
at net.minecraft.client.render.BufferBuilder.next(BufferBuilder.java:273)
at net.minecraft.client.render.block.FluidRenderer.vertex(FluidRenderer.java:289)
at net.minecraft.client.render.block.FluidRenderer.render(FluidRenderer.java:162)
at net.minecraft.client.render.block.BlockRenderManager.renderFluid(BlockRenderManager.java:73)
at com.thebrokenrail.gulliverreloaded.client.block.MiniaturizerBlockEntityRenderer.render(MiniaturizerBlockEntityRenderer.java:60)
at net.minecraft.client.render.WorldRenderer.handler$zbe000$render(WorldRenderer.java:2994)
at net.minecraft.client.render.WorldRenderer.render(WorldRenderer.java:1154)
at net.minecraft.client.render.GameRenderer.renderWorld(GameRenderer.java:718)
at net.minecraft.client.render.GameRenderer.render(GameRenderer.java:543)
at net.minecraft.client.MinecraftClient.render(MinecraftClient.java:1003)
at net.minecraft.client.MinecraftClient.run(MinecraftClient.java:631)
at net.minecraft.client.main.Main.main(Main.java:204)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.fabricmc.loader.game.MinecraftGameProvider.launch(MinecraftGameProvider.java:192)
at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:138)
at net.fabricmc.loader.launch.knot.KnotClient.main(KnotClient.java:26)
at net.fabricmc.devlaunchinjector.Main.main(Main.java:86)