mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-14 19:25:23 -05:00
Fluid rendering fixes (#3593)
* Fluid rendering fixes - Fix default overlay block check using TransparentBlock instead of TranslucentBlock - Fix setBlockTransparency/isBlockTransparent not being thread-safe - Reuse the same render handler objects for water and lava * Fix implementation issues - Fix custom geometry being buffered twice if FluidRenderHandler#renderFluid is invoked directly - Fix calling FluidRenderHandler.super.renderFluid not using passed arguments to calculate color - Fix calling FluidRenderHandler.super.renderFluid more than once producing incorrect geometry - Fix fluids with no handler never receiving water overlay instead of using default behavior * Add way to render fluid with non-vanilla default - Fix testmod
This commit is contained in:
parent
6dfc9a786d
commit
e761c6698e
8 changed files with 264 additions and 139 deletions
|
@ -20,13 +20,14 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.block.FluidRenderer;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderHandlerRegistryImpl;
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderingImpl;
|
||||
|
||||
/**
|
||||
* Interface for handling the rendering of a FluidState.
|
||||
|
@ -67,14 +68,13 @@ public interface FluidRenderHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tessellate your fluid. This method will be invoked before the default
|
||||
* fluid renderer. By default, it will call the default fluid renderer. Call
|
||||
* {@code FluidRenderHandler.super.renderFluid} if you want to render over
|
||||
* the default fluid renderer.
|
||||
*
|
||||
* <p>Note that this method must *only* return {@code true} if at least one
|
||||
* face is tessellated. If no faces are tessellated this method must return
|
||||
* {@code false}.
|
||||
* Tessellate your fluid. By default, this method will call the default
|
||||
* fluid renderer. Call {@code FluidRenderHandler.super.renderFluid} if
|
||||
* you want to render over the default fluid renderer. This is the
|
||||
* intended way to render default geometry; calling
|
||||
* {@link FluidRenderer#render} is not supported. When rendering default
|
||||
* geometry, the current handler will be used instead of looking up
|
||||
* a new one for the passed fluid state.
|
||||
*
|
||||
* @param pos The position in the world, of the fluid to render.
|
||||
* @param world The world the fluid is in
|
||||
|
@ -83,7 +83,7 @@ public interface FluidRenderHandler {
|
|||
* @param fluidState The fluid state being rendered.
|
||||
*/
|
||||
default void renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
((FluidRenderHandlerRegistryImpl) FluidRenderHandlerRegistry.INSTANCE).renderFluid(pos, world, vertexConsumer, blockState, fluidState);
|
||||
FluidRenderingImpl.renderDefault(this, world, pos, vertexConsumer, blockState, fluidState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.render.fluid.v1;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.block.FluidRenderer;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderingImpl;
|
||||
|
||||
/**
|
||||
* A class containing some utilities for rendering fluids.
|
||||
*/
|
||||
public final class FluidRendering {
|
||||
private FluidRendering() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a fluid using the given handler, default renderer, and context. Internally, this just invokes
|
||||
* {@link FluidRenderHandler#renderFluid}, but the passed default renderer is invoked instead of the vanilla
|
||||
* renderer whenever the handler requests default geometry to be rendered.
|
||||
*
|
||||
* @param handler the render handler to invoke {@link FluidRenderHandler#renderFluid} on
|
||||
* @param world the world
|
||||
* @param pos the pos
|
||||
* @param vertexConsumer the vertex consumer
|
||||
* @param blockState the block state
|
||||
* @param fluidState the fluid state
|
||||
* @param defaultRenderer the renderer to use whenever the handler requests default geometry
|
||||
*/
|
||||
public static void render(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, DefaultRenderer defaultRenderer) {
|
||||
FluidRenderingImpl.render(handler, world, pos, vertexConsumer, blockState, fluidState, defaultRenderer);
|
||||
}
|
||||
|
||||
public interface DefaultRenderer {
|
||||
/**
|
||||
* Render the default geometry when it is requested by {@link FluidRenderHandler#renderFluid}. The default
|
||||
* implementation invokes the vanilla renderer. Calling {@link FluidRenderer#render} directly is not supported
|
||||
* but using {@code DefaultRenderer.super.render} is supported. Note that the parameter values passed to this
|
||||
* call are provided by the render handler, meaning they are not necessarily the same as those provided to the
|
||||
* initial rendering call. As per the documentation of {@link FluidRenderHandler#renderFluid}, a new handler
|
||||
* should not be retrieved and only the passed one should be used.
|
||||
*
|
||||
* @param handler the handler that {@link FluidRenderHandler#renderFluid} was invoked on
|
||||
* @param world the world
|
||||
* @param pos the pos
|
||||
* @param vertexConsumer the vertex consumer
|
||||
* @param blockState the block state
|
||||
* @param fluidState the fluid state
|
||||
*/
|
||||
default void render(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
FluidRenderingImpl.renderVanillaDefault(handler, world, pos, vertexConsumer, blockState, fluidState);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,7 +85,7 @@ public class SimpleFluidRenderHandler implements FluidRenderHandler {
|
|||
*/
|
||||
public SimpleFluidRenderHandler(Identifier stillTexture, Identifier flowingTexture, @Nullable Identifier overlayTexture, int tint) {
|
||||
this.stillTexture = Objects.requireNonNull(stillTexture, "stillTexture");
|
||||
this.flowingTexture = Objects.requireNonNull(flowingTexture, "flowingTexture");;
|
||||
this.flowingTexture = Objects.requireNonNull(flowingTexture, "flowingTexture");
|
||||
this.overlayTexture = overlayTexture;
|
||||
this.sprites = new Sprite[overlayTexture == null ? 2 : 3];
|
||||
this.tint = tint;
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.rendering.fluid;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -24,41 +25,32 @@ import net.minecraft.world.BlockRenderView;
|
|||
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
||||
|
||||
public class FluidRendererHookContainer {
|
||||
public BlockRenderView view;
|
||||
public BlockPos pos;
|
||||
public BlockState blockState;
|
||||
public FluidState fluidState;
|
||||
public FluidRenderHandler handler;
|
||||
public class FluidRenderHandlerInfo {
|
||||
public final Sprite[] sprites = new Sprite[2];
|
||||
public Sprite overlay;
|
||||
@Nullable
|
||||
public FluidRenderHandler handler;
|
||||
public boolean hasOverlay;
|
||||
public Sprite overlaySprite;
|
||||
|
||||
public void getSprites(BlockRenderView world, BlockPos pos, FluidState fluidState) {
|
||||
if (handler != null) {
|
||||
Sprite[] sprites = handler.getFluidSprites(world, pos, fluidState);
|
||||
public void setup(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, FluidState fluidState) {
|
||||
this.handler = handler;
|
||||
|
||||
this.sprites[0] = sprites[0];
|
||||
this.sprites[1] = sprites[1];
|
||||
Sprite[] sprites = handler.getFluidSprites(world, pos, fluidState);
|
||||
|
||||
if (sprites.length > 2) {
|
||||
hasOverlay = true;
|
||||
overlay = sprites[2];
|
||||
}
|
||||
} else {
|
||||
hasOverlay = false;
|
||||
this.sprites[0] = sprites[0];
|
||||
this.sprites[1] = sprites[1];
|
||||
|
||||
if (sprites.length > 2) {
|
||||
hasOverlay = true;
|
||||
overlaySprite = sprites[2];
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
view = null;
|
||||
pos = null;
|
||||
blockState = null;
|
||||
fluidState = null;
|
||||
handler = null;
|
||||
sprites[0] = null;
|
||||
sprites[1] = null;
|
||||
overlay = null;
|
||||
handler = null;
|
||||
hasOverlay = false;
|
||||
overlaySprite = null;
|
||||
}
|
||||
}
|
|
@ -18,16 +18,16 @@ package net.fabricmc.fabric.impl.client.rendering.fluid;
|
|||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.LeavesBlock;
|
||||
import net.minecraft.block.TransparentBlock;
|
||||
import net.minecraft.block.TranslucentBlock;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.color.world.BiomeColors;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.block.FluidRenderer;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
|
@ -43,15 +43,16 @@ import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
|||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||
|
||||
public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistry {
|
||||
/**
|
||||
* The water color of {@link BiomeKeys#OCEAN}.
|
||||
*/
|
||||
private static final int DEFAULT_WATER_COLOR = 0x3f76e4;
|
||||
private final Map<Fluid, FluidRenderHandler> handlers = new IdentityHashMap<>();
|
||||
private final Map<Fluid, FluidRenderHandler> modHandlers = new IdentityHashMap<>();
|
||||
private final Map<Block, Boolean> overlayBlocks = new IdentityHashMap<>();
|
||||
private final ConcurrentMap<Block, Boolean> overlayBlocks = new ConcurrentHashMap<>();
|
||||
|
||||
private FluidRenderer fluidRenderer;
|
||||
{
|
||||
handlers.put(Fluids.WATER, WaterRenderHandler.INSTANCE);
|
||||
handlers.put(Fluids.FLOWING_WATER, WaterRenderHandler.INSTANCE);
|
||||
handlers.put(Fluids.LAVA, LavaRenderHandler.INSTANCE);
|
||||
handlers.put(Fluids.FLOWING_LAVA, LavaRenderHandler.INSTANCE);
|
||||
}
|
||||
|
||||
public FluidRenderHandlerRegistryImpl() {
|
||||
}
|
||||
|
@ -81,42 +82,14 @@ public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistr
|
|||
|
||||
@Override
|
||||
public boolean isBlockTransparent(Block block) {
|
||||
return overlayBlocks.computeIfAbsent(block, k -> k instanceof TransparentBlock || k instanceof LeavesBlock);
|
||||
return overlayBlocks.computeIfAbsent(block, k -> k instanceof TranslucentBlock || k instanceof LeavesBlock);
|
||||
}
|
||||
|
||||
public void onFluidRendererReload(FluidRenderer renderer, Sprite[] waterSprites, Sprite[] lavaSprites, Sprite waterOverlay) {
|
||||
fluidRenderer = renderer;
|
||||
FluidRenderingImpl.setVanillaRenderer(renderer);
|
||||
|
||||
Sprite[] waterSpritesFull = {waterSprites[0], waterSprites[1], waterOverlay};
|
||||
FluidRenderHandler waterHandler = new FluidRenderHandler() {
|
||||
@Override
|
||||
public Sprite[] getFluidSprites(BlockRenderView view, BlockPos pos, FluidState state) {
|
||||
return waterSpritesFull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFluidColor(BlockRenderView view, BlockPos pos, FluidState state) {
|
||||
if (view != null && pos != null) {
|
||||
return BiomeColors.getWaterColor(view, pos);
|
||||
} else {
|
||||
return DEFAULT_WATER_COLOR;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//noinspection Convert2Lambda
|
||||
FluidRenderHandler lavaHandler = new FluidRenderHandler() {
|
||||
@Override
|
||||
public Sprite[] getFluidSprites(BlockRenderView view, BlockPos pos, FluidState state) {
|
||||
return lavaSprites;
|
||||
}
|
||||
};
|
||||
|
||||
handlers.put(Fluids.WATER, waterHandler);
|
||||
handlers.put(Fluids.FLOWING_WATER, waterHandler);
|
||||
handlers.put(Fluids.LAVA, lavaHandler);
|
||||
handlers.put(Fluids.FLOWING_LAVA, lavaHandler);
|
||||
handlers.putAll(modHandlers);
|
||||
WaterRenderHandler.INSTANCE.updateSprites(waterSprites, waterOverlay);
|
||||
LavaRenderHandler.INSTANCE.updateSprites(lavaSprites);
|
||||
|
||||
SpriteAtlasTexture texture = MinecraftClient.getInstance()
|
||||
.getBakedModelManager()
|
||||
|
@ -127,7 +100,49 @@ public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistr
|
|||
}
|
||||
}
|
||||
|
||||
public void renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
fluidRenderer.render(world, pos, vertexConsumer, blockState, fluidState);
|
||||
private static class WaterRenderHandler implements FluidRenderHandler {
|
||||
public static final WaterRenderHandler INSTANCE = new WaterRenderHandler();
|
||||
|
||||
/**
|
||||
* The water color of {@link BiomeKeys#OCEAN}.
|
||||
*/
|
||||
private static final int DEFAULT_WATER_COLOR = 0x3f76e4;
|
||||
|
||||
private final Sprite[] sprites = new Sprite[3];
|
||||
|
||||
@Override
|
||||
public Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
|
||||
return sprites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFluidColor(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
|
||||
if (view != null && pos != null) {
|
||||
return BiomeColors.getWaterColor(view, pos);
|
||||
} else {
|
||||
return DEFAULT_WATER_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSprites(Sprite[] waterSprites, Sprite waterOverlay) {
|
||||
sprites[0] = waterSprites[0];
|
||||
sprites[1] = waterSprites[1];
|
||||
sprites[2] = waterOverlay;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LavaRenderHandler implements FluidRenderHandler {
|
||||
public static final LavaRenderHandler INSTANCE = new LavaRenderHandler();
|
||||
|
||||
private Sprite[] sprites;
|
||||
|
||||
@Override
|
||||
public Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
|
||||
return sprites;
|
||||
}
|
||||
|
||||
public void updateSprites(Sprite[] lavaSprites) {
|
||||
sprites = lavaSprites;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.rendering.fluid;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.block.FluidRenderer;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRendering;
|
||||
|
||||
public class FluidRenderingImpl {
|
||||
private static final ThreadLocal<FluidRendering.DefaultRenderer> CURRENT_DEFAULT_RENDERER = new ThreadLocal<>();
|
||||
private static final ThreadLocal<FluidRenderHandlerInfo> CURRENT_INFO = ThreadLocal.withInitial(FluidRenderHandlerInfo::new);
|
||||
private static FluidRenderer vanillaRenderer;
|
||||
|
||||
// Only invoked manually from FluidRendering#render
|
||||
public static void render(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, FluidRendering.DefaultRenderer defaultRenderer) {
|
||||
CURRENT_DEFAULT_RENDERER.set(defaultRenderer);
|
||||
|
||||
try {
|
||||
handler.renderFluid(pos, world, vertexConsumer, blockState, fluidState);
|
||||
} finally {
|
||||
CURRENT_DEFAULT_RENDERER.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Only invoked when FluidRenderHandler#renderFluid calls super
|
||||
public static void renderDefault(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
FluidRendering.DefaultRenderer renderer = CURRENT_DEFAULT_RENDERER.get();
|
||||
|
||||
if (renderer != null) {
|
||||
renderer.render(handler, world, pos, vertexConsumer, blockState, fluidState);
|
||||
} else {
|
||||
renderVanillaDefault(handler, world, pos, vertexConsumer, blockState, fluidState);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when FluidRenderHandler#renderFluid is called directly without using FluidRendering#render (such as
|
||||
// from vanilla FluidRenderer#render via mixin) or from the default implementation of DefaultRenderer#render
|
||||
public static void renderVanillaDefault(FluidRenderHandler handler, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
FluidRenderHandlerInfo info = CURRENT_INFO.get();
|
||||
info.setup(handler, world, pos, fluidState);
|
||||
|
||||
try {
|
||||
vanillaRenderer.render(world, pos, vertexConsumer, blockState, fluidState);
|
||||
} finally {
|
||||
info.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVanillaRenderer(FluidRenderer vanillaRenderer) {
|
||||
FluidRenderingImpl.vanillaRenderer = vanillaRenderer;
|
||||
}
|
||||
|
||||
public static FluidRenderHandlerInfo getCurrentInfo() {
|
||||
return CURRENT_INFO.get();
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import org.objectweb.asm.Opcodes;
|
|||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
@ -38,8 +37,9 @@ import net.minecraft.world.BlockRenderView;
|
|||
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderHandlerInfo;
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderHandlerRegistryImpl;
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRendererHookContainer;
|
||||
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderingImpl;
|
||||
|
||||
@Mixin(FluidRenderer.class)
|
||||
public class FluidRendererMixin {
|
||||
|
@ -52,8 +52,6 @@ public class FluidRendererMixin {
|
|||
@Shadow
|
||||
private Sprite waterOverlaySprite;
|
||||
|
||||
private final ThreadLocal<FluidRendererHookContainer> fabric_renderHandler = ThreadLocal.withInitial(FluidRendererHookContainer::new);
|
||||
private final ThreadLocal<Boolean> fabric_customRendering = ThreadLocal.withInitial(() -> false);
|
||||
private final ThreadLocal<Block> fabric_neighborBlock = new ThreadLocal<>();
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "onResourceReload")
|
||||
|
@ -63,78 +61,50 @@ public class FluidRendererMixin {
|
|||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "render", cancellable = true)
|
||||
public void tesselate(BlockRenderView view, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, CallbackInfo info) {
|
||||
if (!fabric_customRendering.get()) {
|
||||
// Prevent recursively looking up custom fluid renderers when default behavior is being invoked
|
||||
try {
|
||||
fabric_customRendering.set(true);
|
||||
tessellateViaHandler(view, pos, vertexConsumer, blockState, fluidState, info);
|
||||
} finally {
|
||||
fabric_customRendering.set(false);
|
||||
public void onHeadRender(BlockRenderView view, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, CallbackInfo ci) {
|
||||
FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
|
||||
if (info.handler == null) {
|
||||
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid());
|
||||
|
||||
if (handler != null) {
|
||||
handler.renderFluid(pos, view, vertexConsumer, blockState, fluidState);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
if (info.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
ctr.getSprites(view, pos, fluidState);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void tessellateViaHandler(BlockRenderView view, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, CallbackInfo info) {
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid());
|
||||
|
||||
ctr.view = view;
|
||||
ctr.pos = pos;
|
||||
ctr.blockState = blockState;
|
||||
ctr.fluidState = fluidState;
|
||||
ctr.handler = handler;
|
||||
|
||||
if (handler != null) {
|
||||
handler.renderFluid(pos, view, vertexConsumer, blockState, fluidState);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "render")
|
||||
public void tesselateReturn(BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, CallbackInfo ci) {
|
||||
fabric_renderHandler.get().clear();
|
||||
}
|
||||
|
||||
@ModifyVariable(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/FluidRenderer;isSameFluid(Lnet/minecraft/fluid/FluidState;Lnet/minecraft/fluid/FluidState;)Z"), method = "render", ordinal = 0)
|
||||
public boolean modLavaCheck(boolean chk) {
|
||||
// First boolean local is set by vanilla according to 'matches lava'
|
||||
// but uses the negation consistent with 'matches water'
|
||||
// for determining if special water sprite should be used behind glass.
|
||||
// for determining if overlay water sprite should be used behind glass.
|
||||
|
||||
// Has other uses but those are overridden by this mixin and have
|
||||
// already happened by the time this hook is called
|
||||
// already happened by the time this hook is called.
|
||||
|
||||
// If this fluid has an overlay texture, set this boolean too false
|
||||
final FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
return !ctr.hasOverlay;
|
||||
// If this fluid has an overlay texture, set this boolean to false.
|
||||
final FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
return info.handler != null ? !info.hasOverlay : chk;
|
||||
}
|
||||
|
||||
@ModifyVariable(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/FluidRenderer;isSameFluid(Lnet/minecraft/fluid/FluidState;Lnet/minecraft/fluid/FluidState;)Z"), method = "render", ordinal = 0)
|
||||
public Sprite[] modSpriteArray(Sprite[] chk) {
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
return ctr.handler != null ? ctr.sprites : chk;
|
||||
FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
return info.handler != null ? info.sprites : chk;
|
||||
}
|
||||
|
||||
@ModifyVariable(at = @At(value = "CONSTANT", args = "intValue=16", ordinal = 0, shift = At.Shift.BEFORE), method = "render", ordinal = 0)
|
||||
public int modTintColor(int chk, BlockRenderView world, BlockPos pos, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
return info.handler != null ? info.handler.getFluidColor(world, pos, fluidState) : chk;
|
||||
}
|
||||
|
||||
// Redirect redirects all 'waterOverlaySprite' gets in 'render' to this method, this is correct
|
||||
@Redirect(at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/render/block/FluidRenderer;waterOverlaySprite:Lnet/minecraft/client/texture/Sprite;"), method = "render")
|
||||
public Sprite modWaterOverlaySprite(FluidRenderer self) {
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
return ctr.handler != null && ctr.hasOverlay ? ctr.overlay : waterOverlaySprite;
|
||||
}
|
||||
|
||||
@ModifyVariable(at = @At(value = "CONSTANT", args = "intValue=16", ordinal = 0, shift = At.Shift.BEFORE), method = "render", ordinal = 0)
|
||||
public int modTintColor(int chk) {
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
return ctr.handler != null ? ctr.handler.getFluidColor(ctr.view, ctr.pos, ctr.fluidState) : chk;
|
||||
FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
return info.handler != null && info.hasOverlay ? info.overlaySprite : waterOverlaySprite;
|
||||
}
|
||||
|
||||
@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;getBlock()Lnet/minecraft/block/Block;"), method = "render")
|
||||
|
@ -152,8 +122,8 @@ public class FluidRendererMixin {
|
|||
Block block = fabric_neighborBlock.get();
|
||||
|
||||
if (FluidRenderHandlerRegistry.INSTANCE.isBlockTransparent(block)) {
|
||||
FluidRendererHookContainer ctr = fabric_renderHandler.get();
|
||||
return ctr.handler != null && ctr.hasOverlay ? ctr.overlay : waterOverlaySprite;
|
||||
FluidRenderHandlerInfo info = FluidRenderingImpl.getCurrentInfo();
|
||||
return info.handler != null && info.hasOverlay ? info.overlaySprite : waterOverlaySprite;
|
||||
}
|
||||
|
||||
return chk;
|
||||
|
|
|
@ -36,8 +36,8 @@ public class CustomizedFluidRenderer extends SimpleFluidRenderHandler {
|
|||
int light = getLight(world, pos);
|
||||
float u1 = sprites[2].getFrameU(0);
|
||||
float v1 = sprites[2].getFrameV(0);
|
||||
float u2 = sprites[2].getFrameU(16);
|
||||
float v2 = sprites[2].getFrameV(16 * fluidState.getHeight(world, pos));
|
||||
float u2 = sprites[2].getFrameU(1);
|
||||
float v2 = sprites[2].getFrameV(fluidState.getHeight(world, pos));
|
||||
|
||||
float x1 = (pos.getX() & 15) + 0.1f;
|
||||
float y1 = pos.getY() & 15;
|
||||
|
|
Loading…
Reference in a new issue