Custom fluid renderers and enhanced vanilla fluid renderer customization ()

* Implement custom fluid rendering

* Move custom renderers in FluidRenderer mixin and add overlay sprite support to FluidRenderHandlers

* Add vanilla-like fluid renderer. Maybe very unnecessary, might remove.

* Optimize imports

* Allow custom fluid renderers to call the default renderer. Re-add DEFAULT.

* Add interface to implement by blocks that enforces overlay texture on fluids

* Some comments

* Simplify API and remove DefaultLikeFluidRenderer

* Make simple renderer overlay texture nullable

Co-authored-by: Technici4n <13494793+Technici4n@users.noreply.github.com>

* Expand test mod

* Checkstyle and licenses

* Easy shortcut for custom colored vanilla water fluids

* Easy way to register a renderer for two (still+flowing) fluids

* Update fabric-rendering-fluids-v1/src/main/java/net/fabricmc/fabric/api/client/render/fluid/v1/FluidRenderHandlerRegistry.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Update fabric-rendering-fluids-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/fluid/MixinFluidRenderer.java

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

Co-authored-by: Technici4n <13494793+Technici4n@users.noreply.github.com>
Co-authored-by: modmuss50 <modmuss50@gmail.com>
Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
This commit is contained in:
Shadew 2021-11-05 16:34:37 +01:00 committed by modmuss50
parent d4df60101d
commit d77a0a3a6e
21 changed files with 1234 additions and 30 deletions

View file

@ -2,5 +2,10 @@ archivesBaseName = "fabric-rendering-fluids-v1"
version = getSubprojectVersion(project, "0.1.14")
moduleDependencies(project, [
'fabric-api-base'
'fabric-api-base',
'fabric-textures-v0'
])
dependencies {
testmodImplementation project(path: ':fabric-textures-v0', configuration: 'dev')
}

View file

@ -18,27 +18,35 @@ package net.fabricmc.fabric.api.client.render.fluid.v1;
import org.jetbrains.annotations.Nullable;
import net.minecraft.client.render.VertexConsumer;
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;
/**
* Interface for handling the rendering of a FluidState.
*/
public interface FluidRenderHandler {
/**
* Get the sprites for a fluid being rendered at a given position.
* For optimal performance, the sprites should be loaded as part of a
* resource reload and *not* looked up every time the method is called!
* Get the sprites for a fluid being rendered at a given position. For
* optimal performance, the sprites should be loaded as part of a resource
* reload and *not* looked up every time the method is called! You likely
* want to override {@link #reloadTextures} to reload your fluid sprites.
*
* <p>The "fabric-textures" module contains sprite rendering facilities, which may come in handy here.
* <p>The "fabric-textures" module contains sprite rendering facilities,
* which may come in handy here.
*
* @param view The world view pertaining to the fluid. May be null!
* @param pos The position of the fluid in the world. May be null!
* @param view The world view pertaining to the fluid. May be null!
* @param pos The position of the fluid in the world. May be null!
* @param state The current state of the fluid.
* @return An array of size two: the first entry contains the "still" sprite,
* while the second entry contains the "flowing" sprite.
* @return An array of size two or more: the first entry contains the
* "still" sprite, while the second entry contains the "flowing" sprite. If
* it contains a third sprite, that sprite is used as overlay behind glass
* and leaves.
*/
Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state);
@ -48,12 +56,46 @@ public interface FluidRenderHandler {
* <p>Note: As of right now, our hook cannot handle setting a custom alpha
* tint here - as such, it must be contained in the texture itself!
*
* @param view The world view pertaining to the fluid. May be null!
* @param pos The position of the fluid in the world. May be null!
* @param view The world view pertaining to the fluid. May be null!
* @param pos The position of the fluid in the world. May be null!
* @param state The current state of the fluid.
* @return The tint color of the fluid.
*/
default int getFluidColor(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
return -1;
}
/**
* 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}.
*
* @param pos The position in the world, of the fluid to render.
* @param world The world the fluid is in
* @param vertexConsumer The vertex consumer to tessellate the fluid in.
* @param state The fluid state being rendered.
* @return Whether anything is tessellated.
*/
default boolean renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, FluidState state) {
return FluidRenderHandlerRegistryImpl.INSTANCE.renderFluid(pos, world, vertexConsumer, state);
}
/**
* Look up your Fluid's sprites from the texture atlas. Called when the
* fluid renderer reloads its textures. This is a convenient way of
* reloading and does not require an advanced resource manager reload
* listener.
*
* <p>The "fabric-textures" module contains sprite rendering facilities,
* which may come in handy here.
*
* @param textureAtlas The blocks texture atlas, provided for convenience.
*/
default void reloadTextures(SpriteAtlasTexture textureAtlas) {
}
}

View file

@ -16,6 +16,9 @@
package net.fabricmc.fabric.api.client.render.fluid.v1;
import net.minecraft.block.Block;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.TransparentBlock;
import net.minecraft.fluid.Fluid;
import net.fabricmc.fabric.impl.client.rendering.fluid.FluidRenderHandlerRegistryImpl;
@ -30,8 +33,8 @@ public interface FluidRenderHandlerRegistry {
FluidRenderHandlerRegistry INSTANCE = FluidRenderHandlerRegistryImpl.INSTANCE;
/**
* Get a {@link FluidRenderHandler} for a given Fluid.
* Supports vanilla and Fabric fluids.
* Get a {@link FluidRenderHandler} for a given Fluid. Supports vanilla and
* Fabric fluids.
*
* @param fluid The Fluid.
* @return The FluidRenderHandler.
@ -41,8 +44,54 @@ public interface FluidRenderHandlerRegistry {
/**
* Register a {@link FluidRenderHandler} for a given Fluid.
*
* <p>Note that most fluids have a still and a flowing type, and a
* FluidRenderHandler must be registered for each type separately. To easily
* register a render handler for a pair of still and flowing fluids, use
* {@link #register(Fluid, Fluid, FluidRenderHandler)}.
*
* @param fluid The Fluid.
* @param renderer The FluidRenderHandler.
*/
void register(Fluid fluid, FluidRenderHandler renderer);
/**
* Register a {@link FluidRenderHandler} for two given Fluids, usually a
* pair of a still and a flowing fluid type that use the same fluid
* renderer.
*
* @param still The still Fluid.
* @param flow The flowing Fluid.
* @param renderer The FluidRenderHandler.
*/
default void register(Fluid still, Fluid flow, FluidRenderHandler renderer) {
register(still, renderer);
register(flow, renderer);
}
/**
* Registers whether a block is transparent or not. When a block is
* transparent, the flowing fluid texture to the sides of that block is
* replaced by a special overlay texture. This happens by default with glass
* and leaves, and hence blocks inheriting {@link TransparentBlock} and
* {@link LeavesBlock} are by default transparent. Use this method to
* override the default behavior for a block.
*
* @param block The block to register transparency for.
* @param transparent Whether the block is transparent (e.g. gets the
* overlay textures) or not.
*/
void setBlockTransparency(Block block, boolean transparent);
/**
* Looks up whether a block is transparent and gets a fluid overlay texture
* instead of a falling fluid texture. If transparency is registered for a
* block (via {@link #setBlockTransparency}), this method returns that
* registered transparency. Otherwise, this method returns whether the block
* is a subclass of {@link TransparentBlock} or {@link LeavesBlock}.
*
* @param block The block to get transparency for.
* @return Whether the block is transparent (e.g. gets the overlay textures)
* or not.
*/
boolean isBlockTransparent(Block block);
}

View file

@ -0,0 +1,168 @@
/*
* 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 org.jetbrains.annotations.Nullable;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
/**
* A simple fluid render handler that uses and loads sprites given by their
* identifiers. Most fluids don't need more than this. In fact, if a fluid just
* needs the vanilla water texture with a custom color, {@link #coloredWater}
* can be used to easily create a fluid render handler for that.
*
* <p>Note that it's assumed that the fluid textures are assumed to be
* registered to the blocks sprite atlas. If they are not, you have to manually
* register the fluid textures. The "fabric-textures" API may come in handy for
* that.
*/
public class SimpleFluidRenderHandler implements FluidRenderHandler {
/**
* The vanilla still water texture identifier.
*/
public static final Identifier WATER_STILL = new Identifier("block/water_still");
/**
* The vanilla flowing water texture identifier.
*/
public static final Identifier WATER_FLOWING = new Identifier("block/water_flow");
/**
* The vanilla water overlay texture identifier.
*/
public static final Identifier WATER_OVERLAY = new Identifier("block/water_overlay");
/**
* The vanilla still lava texture identifier.
*/
public static final Identifier LAVA_STILL = new Identifier("block/lava_still");
/**
* The vanilla flowing lava texture identifier.
*/
public static final Identifier LAVA_FLOWING = new Identifier("block/lava_flow");
protected final Identifier stillTexture;
protected final Identifier flowingTexture;
protected final Identifier overlayTexture;
protected final Sprite[] sprites;
protected final int tint;
/**
* Creates a fluid render handler with an overlay texture and a custom,
* fixed tint.
*
* @param stillTexture The texture for still fluid.
* @param flowingTexture The texture for flowing/falling fluid.
* @param overlayTexture The texture behind glass, leaves and other
* {@linkplain FluidRenderHandlerRegistry#setBlockTransparency registered
* transparent blocks}.
* @param tint The fluid color RGB. Alpha is ignored.
*/
public SimpleFluidRenderHandler(Identifier stillTexture, Identifier flowingTexture, @Nullable Identifier overlayTexture, int tint) {
this.stillTexture = stillTexture;
this.flowingTexture = flowingTexture;
this.overlayTexture = overlayTexture;
this.sprites = new Sprite[overlayTexture == null ? 2 : 3];
this.tint = tint;
}
/**
* Creates a fluid render handler with an overlay texture and no tint.
*
* @param stillTexture The texture for still fluid.
* @param flowingTexture The texture for flowing/falling fluid.
* @param overlayTexture The texture behind glass, leaves and other
* {@linkplain FluidRenderHandlerRegistry#setBlockTransparency registered
* transparent blocks}.
*/
public SimpleFluidRenderHandler(Identifier stillTexture, Identifier flowingTexture, Identifier overlayTexture) {
this(stillTexture, flowingTexture, overlayTexture, -1);
}
/**
* Creates a fluid render handler without an overlay texture and a custom,
* fixed tint.
*
* @param stillTexture The texture for still fluid.
* @param flowingTexture The texture for flowing/falling fluid.
* @param tint The fluid color RGB. Alpha is ignored.
*/
public SimpleFluidRenderHandler(Identifier stillTexture, Identifier flowingTexture, int tint) {
this(stillTexture, flowingTexture, null, tint);
}
/**
* Creates a fluid render handler without an overlay texture and no tint.
*
* @param stillTexture The texture for still fluid.
* @param flowingTexture The texture for flowing/falling fluid.
*/
public SimpleFluidRenderHandler(Identifier stillTexture, Identifier flowingTexture) {
this(stillTexture, flowingTexture, null, -1);
}
/**
* Creates a fluid render handler that uses the vanilla water texture with a
* fixed, custom color.
*
* @param tint The fluid color RGB. Alpha is ignored.
* @see #WATER_STILL
* @see #WATER_FLOWING
* @see #WATER_OVERLAY
*/
public static SimpleFluidRenderHandler coloredWater(int tint) {
return new SimpleFluidRenderHandler(WATER_STILL, WATER_FLOWING, WATER_OVERLAY, tint);
}
/**
* {@inheritDoc}
*/
@Override
public Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
return sprites;
}
/**
* {@inheritDoc}
*/
@Override
public void reloadTextures(SpriteAtlasTexture textureAtlas) {
sprites[0] = textureAtlas.getSprite(stillTexture);
sprites[1] = textureAtlas.getSprite(flowingTexture);
if (overlayTexture != null) {
sprites[2] = textureAtlas.getSprite(overlayTexture);
}
}
/**
* {@inheritDoc}
*/
@Override
public int getFluidColor(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
return tint;
}
}

View file

@ -19,11 +19,19 @@ package net.fabricmc.fabric.impl.client.rendering.fluid;
import java.util.IdentityHashMap;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.TransparentBlock;
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;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.world.BlockRenderView;
@ -37,6 +45,9 @@ public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistr
private static final int DEFAULT_WATER_COLOR = BuiltinRegistries.BIOME.get(BiomeKeys.OCEAN).getWaterColor();
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 FluidRenderer fluidRenderer;
private FluidRenderHandlerRegistryImpl() {
}
@ -56,11 +67,24 @@ public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistr
modHandlers.put(fluid, renderer);
}
public void onFluidRendererReload(Sprite[] waterSprites, Sprite[] lavaSprites) {
@Override
public void setBlockTransparency(Block block, boolean transparent) {
overlayBlocks.put(block, transparent);
}
@Override
public boolean isBlockTransparent(Block block) {
return overlayBlocks.computeIfAbsent(block, k -> k instanceof TransparentBlock || k instanceof LeavesBlock);
}
public void onFluidRendererReload(FluidRenderer renderer, Sprite[] waterSprites, Sprite[] lavaSprites, Sprite waterOverlay) {
fluidRenderer = renderer;
Sprite[] waterSpritesFull = {waterSprites[0], waterSprites[1], waterOverlay};
FluidRenderHandler waterHandler = new FluidRenderHandler() {
@Override
public Sprite[] getFluidSprites(BlockRenderView view, BlockPos pos, FluidState state) {
return waterSprites;
return waterSpritesFull;
}
@Override
@ -86,5 +110,17 @@ public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistr
register(Fluids.LAVA, lavaHandler);
register(Fluids.FLOWING_LAVA, lavaHandler);
handlers.putAll(modHandlers);
SpriteAtlasTexture texture = MinecraftClient.getInstance()
.getBakedModelManager()
.getAtlas(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE);
for (FluidRenderHandler handler : handlers.values()) {
handler.reloadTextures(texture);
}
}
public boolean renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, FluidState state) {
return fluidRenderer.render(world, pos, vertexConsumer, state);
}
}

View file

@ -16,6 +16,7 @@
package net.fabricmc.fabric.impl.client.rendering.fluid;
import net.minecraft.client.texture.Sprite;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
@ -27,11 +28,34 @@ public class FluidRendererHookContainer {
public BlockPos pos;
public FluidState state;
public FluidRenderHandler handler;
public final Sprite[] sprites = new Sprite[2];
public Sprite overlay;
public boolean hasOverlay;
public void getSprites(BlockRenderView world, BlockPos pos, FluidState fluid) {
if (handler != null) {
Sprite[] sprites = handler.getFluidSprites(world, pos, state);
this.sprites[0] = sprites[0];
this.sprites[1] = sprites[1];
if (sprites.length > 2) {
hasOverlay = true;
overlay = sprites[2];
}
} else {
hasOverlay = false;
}
}
public void clear() {
view = null;
pos = null;
state = null;
handler = null;
sprites[0] = null;
sprites[1] = null;
overlay = null;
hasOverlay = false;
}
}

View file

@ -16,19 +16,23 @@
package net.fabricmc.fabric.mixin.client.rendering.fluid;
import org.objectweb.asm.Opcodes;
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;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.block.Block;
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.fluid.FluidState;
import net.minecraft.tag.FluidTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
@ -42,16 +46,41 @@ public class MixinFluidRenderer {
private Sprite[] lavaSprites;
@Shadow
private Sprite[] waterSprites;
@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")
public void onResourceReloadReturn(CallbackInfo info) {
FluidRenderHandlerRegistryImpl.INSTANCE.onFluidRendererReload(waterSprites, lavaSprites);
FluidRenderer self = (FluidRenderer) (Object) this;
FluidRenderHandlerRegistryImpl.INSTANCE.onFluidRendererReload(self, waterSprites, lavaSprites, waterOverlaySprite);
}
@Inject(at = @At("HEAD"), method = "render", cancellable = true)
public void tesselate(BlockRenderView view, BlockPos pos, VertexConsumer vertexConsumer, FluidState state, CallbackInfoReturnable<Boolean> info) {
if (!fabric_customRendering.get()) {
// Prevent recursively looking up custom fluid renderers when default behaviour is being invoked
try {
fabric_customRendering.set(true);
tessellateViaHandler(view, pos, vertexConsumer, state, info);
} finally {
fabric_customRendering.set(false);
}
}
if (info.isCancelled()) {
return;
}
FluidRendererHookContainer ctr = fabric_renderHandler.get();
ctr.getSprites(view, pos, state);
}
@Unique
private void tessellateViaHandler(BlockRenderView view, BlockPos pos, VertexConsumer vertexConsumer, FluidState state, CallbackInfoReturnable<Boolean> info) {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
FluidRenderHandler handler = FluidRenderHandlerRegistryImpl.INSTANCE.getOverride(state.getFluid());
@ -60,16 +89,9 @@ public class MixinFluidRenderer {
ctr.state = state;
ctr.handler = handler;
/* if (handler == null) {
return;
if (handler != null) {
info.setReturnValue(handler.renderFluid(pos, view, vertexConsumer, state));
}
ActionResult hResult = handler.tesselate(view, pos, bufferBuilder, state);
if (hResult != ActionResult.PASS) {
info.setReturnValue(hResult == ActionResult.SUCCESS);
return;
} */
}
@Inject(at = @At("RETURN"), method = "render")
@ -83,15 +105,25 @@ public class MixinFluidRenderer {
// but uses the negation consistent with 'matches water'
// for determining if special water sprite should be used behind glass.
// Has other uses but those have already happened by the time the hook is called.
// Has other uses but those are overridden by this mixin and have
// 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 chk || !ctr.state.isIn(FluidTags.WATER);
return !ctr.hasOverlay;
}
@ModifyVariable(at = @At(value = "INVOKE", target = "net/minecraft/client/render/block/FluidRenderer.isSameFluid(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/fluid/FluidState;)Z"), method = "render", ordinal = 0)
public Sprite[] modSpriteArray(Sprite[] chk) {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
return ctr.handler != null ? ctr.handler.getFluidSprites(ctr.view, ctr.pos, ctr.state) : chk;
return ctr.handler != null ? ctr.sprites : 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)
@ -99,4 +131,26 @@ public class MixinFluidRenderer {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
return ctr.handler != null ? ctr.handler.getFluidColor(ctr.view, ctr.pos, ctr.state) : chk;
}
@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;getBlock()Lnet/minecraft/block/Block;"), method = "render")
public Block getOverlayBlock(BlockState state) {
Block block = state.getBlock();
fabric_neighborBlock.set(block);
// An if-statement follows, we don't want this anymore and 'null' makes
// its condition always false (due to instanceof)
return null;
}
@ModifyVariable(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;getBlock()Lnet/minecraft/block/Block;", shift = At.Shift.BY, by = 2), method = "render", ordinal = 0)
public Sprite modSideSpriteForOverlay(Sprite chk) {
Block block = fabric_neighborBlock.get();
if (FluidRenderHandlerRegistryImpl.INSTANCE.isBlockTransparent(block)) {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
return ctr.handler != null && ctr.hasOverlay ? ctr.overlay : waterOverlaySprite;
}
return chk;
}
}

View file

@ -6,6 +6,7 @@
"MixinFluidRenderer"
],
"injectors": {
"defaultRequire": 1
"defaultRequire": 1,
"maxShiftBy": 5
}
}

View file

@ -0,0 +1,144 @@
/*
* 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.test.client.rendering.fluid;
import java.util.Optional;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
public abstract class CustomFluid extends FlowableFluid {
public CustomFluid() {
}
@Override
public Fluid getFlowing() {
return TestFluids.CUSTOM_FLOWING;
}
@Override
public Fluid getStill() {
return TestFluids.CUSTOM;
}
@Override
public Item getBucketItem() {
return Items.WATER_BUCKET;
}
@Override
protected boolean isInfinite() {
return true;
}
@Override
protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) {
BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
Block.dropStacks(state, world, pos, blockEntity);
}
@Override
public int getFlowSpeed(WorldView world) {
return 4;
}
@Override
public BlockState toBlockState(FluidState state) {
return TestFluids.CUSTOM_BLOCK.getDefaultState().with(FluidBlock.LEVEL, getBlockStateLevel(state));
}
@Override
public boolean matchesType(Fluid fluid) {
return fluid == TestFluids.CUSTOM || fluid == TestFluids.CUSTOM_FLOWING;
}
@Override
public int getLevelDecreasePerBlock(WorldView world) {
return 1;
}
@Override
public int getTickRate(WorldView world) {
return 5;
}
@Override
public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) {
return direction == Direction.DOWN && !fluid.matchesType(TestFluids.NO_OVERLAY);
}
@Override
protected float getBlastResistance() {
return 100.0F;
}
@Override
public Optional<SoundEvent> getBucketFillSound() {
return Optional.of(SoundEvents.ITEM_BUCKET_FILL);
}
public static class Flowing extends CustomFluid {
public Flowing() {
}
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState state) {
return state.get(LEVEL);
}
@Override
public boolean isStill(FluidState state) {
return false;
}
}
public static class Still extends CustomFluid {
public Still() {
}
@Override
public int getLevel(FluidState state) {
return 8;
}
@Override
public boolean isStill(FluidState state) {
return true;
}
}
}

View file

@ -0,0 +1,85 @@
/*
* 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.test.client.rendering.fluid;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.client.render.fluid.v1.SimpleFluidRenderHandler;
public class CustomizedFluidRenderer extends SimpleFluidRenderHandler {
public CustomizedFluidRenderer(Identifier overlayTexture) {
super(null, null, overlayTexture);
}
@Override
public boolean renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, FluidState state) {
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 * state.getHeight(world, pos));
float x1 = (pos.getX() & 15) + 0.1f;
float y1 = pos.getY() & 15;
float z1 = (pos.getZ() & 15) + 0.1f;
float x2 = (pos.getX() & 15) + 0.9f;
float y2 = (pos.getY() & 15) + state.getHeight(world, pos);
float z2 = (pos.getZ() & 15) + 0.9f;
vertex(vertexConsumer, x1, y1, z1, 1, 1, 1, u1, v1, light);
vertex(vertexConsumer, x2, y1, z2, 1, 1, 1, u2, v1, light);
vertex(vertexConsumer, x2, y2, z2, 1, 1, 1, u2, v2, light);
vertex(vertexConsumer, x1, y2, z1, 1, 1, 1, u1, v2, light);
vertex(vertexConsumer, x1, y2, z1, 1, 1, 1, u1, v2, light);
vertex(vertexConsumer, x2, y2, z2, 1, 1, 1, u2, v2, light);
vertex(vertexConsumer, x2, y1, z2, 1, 1, 1, u2, v1, light);
vertex(vertexConsumer, x1, y1, z1, 1, 1, 1, u1, v1, light);
vertex(vertexConsumer, x1, y2, z2, 1, 1, 1, u1, v2, light);
vertex(vertexConsumer, x2, y2, z1, 1, 1, 1, u2, v2, light);
vertex(vertexConsumer, x2, y1, z1, 1, 1, 1, u2, v1, light);
vertex(vertexConsumer, x1, y1, z2, 1, 1, 1, u1, v1, light);
vertex(vertexConsumer, x1, y1, z2, 1, 1, 1, u1, v1, light);
vertex(vertexConsumer, x2, y1, z1, 1, 1, 1, u2, v1, light);
vertex(vertexConsumer, x2, y2, z1, 1, 1, 1, u2, v2, light);
vertex(vertexConsumer, x1, y2, z2, 1, 1, 1, u1, v2, light);
return true;
}
private void vertex(VertexConsumer vertexConsumer, double x, double y, double z, float red, float green, float blue, float u, float v, int light) {
vertexConsumer.vertex(x, y, z).color(red, green, blue, 1.0F).texture(u, v).light(light).normal(0.0F, 1.0F, 0.0F).next();
}
private int getLight(BlockRenderView world, BlockPos pos) {
int i = WorldRenderer.getLightmapCoordinates(world, pos);
int j = WorldRenderer.getLightmapCoordinates(world, pos.up());
int k = i & 255;
int l = j & 255;
int m = i >> 16 & 255;
int n = j >> 16 & 255;
return (k > l ? k : l) | (m > n ? m : n) << 16;
}
}

View file

@ -0,0 +1,26 @@
/*
* 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.test.client.rendering.fluid;
import net.fabricmc.api.ModInitializer;
public class FabricFluidRenderingTestMod implements ModInitializer {
@Override
public void onInitialize() {
new TestFluids();
}
}

View file

@ -0,0 +1,68 @@
/*
* 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.test.client.rendering.fluid;
import net.minecraft.block.Blocks;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.fabricmc.fabric.api.client.render.fluid.v1.SimpleFluidRenderHandler;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
public class FabricFluidRenderingTestModClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
// Doors now will have overlay textures to the side
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.ACACIA_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.DARK_OAK_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.BIRCH_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.CRIMSON_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.IRON_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.JUNGLE_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.OAK_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.SPRUCE_DOOR, true);
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.WARPED_DOOR, true);
// Red stained glass will have falling fluid textures to the side
FluidRenderHandlerRegistry.INSTANCE.setBlockTransparency(Blocks.RED_STAINED_GLASS, false);
FluidRenderHandlerRegistry.INSTANCE.register(TestFluids.NO_OVERLAY, TestFluids.NO_OVERLAY_FLOWING, new SimpleFluidRenderHandler(
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_still"),
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_flowing"),
0xFF5555
));
FluidRenderHandlerRegistry.INSTANCE.register(TestFluids.OVERLAY, TestFluids.OVERLAY_FLOWING, new SimpleFluidRenderHandler(
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_still"),
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_flowing"),
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_overlay"),
0x5555FF
));
FluidRenderHandlerRegistry.INSTANCE.register(TestFluids.CUSTOM, TestFluids.CUSTOM_FLOWING, new CustomizedFluidRenderer(
new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_overlay")
));
ClientSpriteRegistryCallback.event(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE).register((atlasTexture, registry) -> {
registry.register(new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_still"));
registry.register(new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_flowing"));
registry.register(new Identifier("fabric-rendering-fluids-v1-testmod:block/test_fluid_overlay"));
});
}
}

View file

@ -0,0 +1,144 @@
/*
* 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.test.client.rendering.fluid;
import java.util.Optional;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
public abstract class NoOverlayFluid extends FlowableFluid {
public NoOverlayFluid() {
}
@Override
public Fluid getFlowing() {
return TestFluids.NO_OVERLAY_FLOWING;
}
@Override
public Fluid getStill() {
return TestFluids.NO_OVERLAY;
}
@Override
public Item getBucketItem() {
return Items.WATER_BUCKET;
}
@Override
protected boolean isInfinite() {
return true;
}
@Override
protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) {
BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
Block.dropStacks(state, world, pos, blockEntity);
}
@Override
public int getFlowSpeed(WorldView world) {
return 4;
}
@Override
public BlockState toBlockState(FluidState state) {
return TestFluids.NO_OVERLAY_BLOCK.getDefaultState().with(FluidBlock.LEVEL, getBlockStateLevel(state));
}
@Override
public boolean matchesType(Fluid fluid) {
return fluid == TestFluids.NO_OVERLAY || fluid == TestFluids.NO_OVERLAY_FLOWING;
}
@Override
public int getLevelDecreasePerBlock(WorldView world) {
return 1;
}
@Override
public int getTickRate(WorldView world) {
return 5;
}
@Override
public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) {
return direction == Direction.DOWN && !fluid.matchesType(TestFluids.NO_OVERLAY);
}
@Override
protected float getBlastResistance() {
return 100.0F;
}
@Override
public Optional<SoundEvent> getBucketFillSound() {
return Optional.of(SoundEvents.ITEM_BUCKET_FILL);
}
public static class Flowing extends NoOverlayFluid {
public Flowing() {
}
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState state) {
return state.get(LEVEL);
}
@Override
public boolean isStill(FluidState state) {
return false;
}
}
public static class Still extends NoOverlayFluid {
public Still() {
}
@Override
public int getLevel(FluidState state) {
return 8;
}
@Override
public boolean isStill(FluidState state) {
return true;
}
}
}

View file

@ -0,0 +1,144 @@
/*
* 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.test.client.rendering.fluid;
import java.util.Optional;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
public abstract class OverlayFluid extends FlowableFluid {
public OverlayFluid() {
}
@Override
public Fluid getFlowing() {
return TestFluids.OVERLAY_FLOWING;
}
@Override
public Fluid getStill() {
return TestFluids.OVERLAY;
}
@Override
public Item getBucketItem() {
return Items.WATER_BUCKET;
}
@Override
protected boolean isInfinite() {
return true;
}
@Override
protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) {
BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
Block.dropStacks(state, world, pos, blockEntity);
}
@Override
public int getFlowSpeed(WorldView world) {
return 4;
}
@Override
public BlockState toBlockState(FluidState state) {
return TestFluids.OVERLAY_BLOCK.getDefaultState().with(FluidBlock.LEVEL, getBlockStateLevel(state));
}
@Override
public boolean matchesType(Fluid fluid) {
return fluid == TestFluids.OVERLAY || fluid == TestFluids.OVERLAY_FLOWING;
}
@Override
public int getLevelDecreasePerBlock(WorldView world) {
return 1;
}
@Override
public int getTickRate(WorldView world) {
return 5;
}
@Override
public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) {
return direction == Direction.DOWN && !fluid.matchesType(TestFluids.NO_OVERLAY);
}
@Override
protected float getBlastResistance() {
return 100.0F;
}
@Override
public Optional<SoundEvent> getBucketFillSound() {
return Optional.of(SoundEvents.ITEM_BUCKET_FILL);
}
public static class Flowing extends OverlayFluid {
public Flowing() {
}
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState state) {
return state.get(LEVEL);
}
@Override
public boolean isStill(FluidState state) {
return false;
}
}
public static class Still extends OverlayFluid {
public Still() {
}
@Override
public int getLevel(FluidState state) {
return 8;
}
@Override
public boolean isStill(FluidState state) {
return true;
}
}
}

View file

@ -0,0 +1,48 @@
/*
* 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.test.client.rendering.fluid;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Blocks;
import net.minecraft.block.FluidBlock;
import net.minecraft.util.registry.Registry;
public class TestFluids {
public static final NoOverlayFluid NO_OVERLAY = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:no_overlay", new NoOverlayFluid.Still());
public static final NoOverlayFluid NO_OVERLAY_FLOWING = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:no_overlay_flowing", new NoOverlayFluid.Flowing());
public static final FluidBlock NO_OVERLAY_BLOCK = Registry.register(Registry.BLOCK, "fabric-rendering-fluids-v1-testmod:no_overlay", new FluidBlock(NO_OVERLAY, AbstractBlock.Settings.copy(Blocks.WATER)) {
});
public static final OverlayFluid OVERLAY = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:overlay", new OverlayFluid.Still());
public static final OverlayFluid OVERLAY_FLOWING = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:overlay_flowing", new OverlayFluid.Flowing());
public static final FluidBlock OVERLAY_BLOCK = Registry.register(Registry.BLOCK, "fabric-rendering-fluids-v1-testmod:overlay", new FluidBlock(OVERLAY, AbstractBlock.Settings.copy(Blocks.WATER)) {
});
public static final UnregisteredFluid UNREGISTERED = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:unregistered", new UnregisteredFluid.Still());
public static final UnregisteredFluid UNREGISTERED_FLOWING = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:unregistered_flowing", new UnregisteredFluid.Flowing());
public static final FluidBlock UNREGISTERED_BLOCK = Registry.register(Registry.BLOCK, "fabric-rendering-fluids-v1-testmod:unregistered", new FluidBlock(UNREGISTERED, AbstractBlock.Settings.copy(Blocks.WATER)) {
});
public static final CustomFluid CUSTOM = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:custom", new CustomFluid.Still());
public static final CustomFluid CUSTOM_FLOWING = Registry.register(Registry.FLUID, "fabric-rendering-fluids-v1-testmod:custom_flowing", new CustomFluid.Flowing());
public static final FluidBlock CUSTOM_BLOCK = Registry.register(Registry.BLOCK, "fabric-rendering-fluids-v1-testmod:custom", new FluidBlock(CUSTOM, AbstractBlock.Settings.copy(Blocks.WATER)) {
});
}

View file

@ -0,0 +1,144 @@
/*
* 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.test.client.rendering.fluid;
import java.util.Optional;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.FlowableFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
public abstract class UnregisteredFluid extends FlowableFluid {
public UnregisteredFluid() {
}
@Override
public Fluid getFlowing() {
return TestFluids.UNREGISTERED_FLOWING;
}
@Override
public Fluid getStill() {
return TestFluids.UNREGISTERED;
}
@Override
public Item getBucketItem() {
return Items.WATER_BUCKET;
}
@Override
protected boolean isInfinite() {
return true;
}
@Override
protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) {
BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null;
Block.dropStacks(state, world, pos, blockEntity);
}
@Override
public int getFlowSpeed(WorldView world) {
return 4;
}
@Override
public BlockState toBlockState(FluidState state) {
return TestFluids.UNREGISTERED_BLOCK.getDefaultState().with(FluidBlock.LEVEL, getBlockStateLevel(state));
}
@Override
public boolean matchesType(Fluid fluid) {
return fluid == TestFluids.UNREGISTERED || fluid == TestFluids.UNREGISTERED_FLOWING;
}
@Override
public int getLevelDecreasePerBlock(WorldView world) {
return 1;
}
@Override
public int getTickRate(WorldView world) {
return 5;
}
@Override
public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) {
return direction == Direction.DOWN && !fluid.matchesType(TestFluids.NO_OVERLAY);
}
@Override
protected float getBlastResistance() {
return 100.0F;
}
@Override
public Optional<SoundEvent> getBucketFillSound() {
return Optional.of(SoundEvents.ITEM_BUCKET_FILL);
}
public static class Flowing extends UnregisteredFluid {
public Flowing() {
}
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState state) {
return state.get(LEVEL);
}
@Override
public boolean isStill(FluidState state) {
return false;
}
}
public static class Still extends UnregisteredFluid {
public Still() {
}
@Override
public int getLevel(FluidState state) {
return 8;
}
@Override
public boolean isStill(FluidState state) {
return true;
}
}
}

View file

@ -0,0 +1,19 @@
{
"schemaVersion": 1,
"id": "fabric-rendering-fluids-v1-testmod",
"name": "Fabric Rendering Fluids (v1) Test Mod",
"version": "1.0.0",
"environment": "*",
"license": "Apache-2.0",
"depends": {
"fabric-rendering-fluids-v1": "*"
},
"entrypoints": {
"main": [
"net.fabricmc.fabric.test.client.rendering.fluid.FabricFluidRenderingTestMod"
],
"client": [
"net.fabricmc.fabric.test.client.rendering.fluid.FabricFluidRenderingTestModClient"
]
}
}