[#111] fluid rendering hooks

This commit is contained in:
asie 2019-05-17 23:24:37 +02:00
parent 59147463cc
commit 76d184ea21
10 changed files with 398 additions and 0 deletions

View file

@ -0,0 +1,6 @@
archivesBaseName = "fabric-rendering-fluids-v1"
version = getSubprojectVersion(project, "0.1.0")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, 2017, 2018 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.client.texture.Sprite;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ExtendedBlockView;
/**
* 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!
*
* 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 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.
*/
Sprite[] getFluidSprites(/* Nullable */ ExtendedBlockView view, /* Nullable */ BlockPos pos, FluidState state);
/**
* Get the tint color for a fluid being rendered at a given position.
*
* 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 state The current state of the fluid.
* @return The tint color of the fluid.
*/
default int getFluidColor(ExtendedBlockView view, BlockPos pos, FluidState state) {
return -1;
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, 2017, 2018 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.fabricmc.fabric.impl.client.render.fluid.FluidRenderHandlerRegistryImpl;
import net.minecraft.fluid.Fluid;
/**
* Registry for {@link FluidRenderHandler} instances.
*
* Notably, this supports querying, overriding and wrapping vanilla fluid
* rendering.
*/
public interface FluidRenderHandlerRegistry {
FluidRenderHandlerRegistry INSTANCE = FluidRenderHandlerRegistryImpl.INSTANCE;
/**
* Get a {@link FluidRenderHandler} for a given Fluid.
* Supports vanilla and Fabric fluids.
*
* @param fluid The Fluid.
* @return The FluidRenderHandler.
*/
FluidRenderHandler get(Fluid fluid);
/**
* Register a {@link FluidRenderHandler} for a given Fluid.
*
* @param fluid The Fluid.
* @param renderer The FluidRenderHandler.
*/
void register(Fluid fluid, FluidRenderHandler renderer);
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2016, 2017, 2018 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.render.fluid;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.minecraft.client.color.world.BiomeColors;
import net.minecraft.client.texture.Sprite;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ExtendedBlockView;
import net.minecraft.world.biome.Biomes;
import java.util.IdentityHashMap;
import java.util.Map;
public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistry {
public static final FluidRenderHandlerRegistryImpl INSTANCE = new FluidRenderHandlerRegistryImpl();
private final Map<Fluid, FluidRenderHandler> handlers = new IdentityHashMap<>();
private final Map<Fluid, FluidRenderHandler> modHandlers = new IdentityHashMap<>();
private FluidRenderHandlerRegistryImpl() {
}
@Override
public FluidRenderHandler get(Fluid fluid) {
return handlers.get(fluid);
}
public FluidRenderHandler getOverride(Fluid fluid) {
return modHandlers.get(fluid);
}
@Override
public void register(Fluid fluid, FluidRenderHandler renderer) {
handlers.put(fluid, renderer);
modHandlers.put(fluid, renderer);
}
public void onFluidRendererReload(Sprite[] waterSprites, Sprite[] lavaSprites) {
FluidRenderHandler waterHandler = new FluidRenderHandler() {
@Override
public Sprite[] getFluidSprites(ExtendedBlockView view, BlockPos pos, FluidState state) {
return waterSprites;
}
@Override
public int getFluidColor(ExtendedBlockView view, BlockPos pos, FluidState state) {
if (view != null && pos != null) {
return BiomeColors.getWaterColor(view, pos);
} else {
return Biomes.DEFAULT.getWaterColor();
}
}
};
//noinspection Convert2Lambda
FluidRenderHandler lavaHandler = new FluidRenderHandler() {
@Override
public Sprite[] getFluidSprites(ExtendedBlockView view, BlockPos pos, FluidState state) {
return lavaSprites;
}
};
register(Fluids.WATER, waterHandler);
register(Fluids.FLOWING_WATER, waterHandler);
register(Fluids.LAVA, lavaHandler);
register(Fluids.FLOWING_LAVA, lavaHandler);
handlers.putAll(modHandlers);
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2016, 2017, 2018 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.render.fluid;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ExtendedBlockView;
public class FluidRendererHookContainer {
public ExtendedBlockView view;
public BlockPos pos;
public FluidState state;
public FluidRenderHandler handler;
public void clear() {
view = null;
pos = null;
state = null;
handler = null;
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2016, 2017, 2018 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.mixin.client.render.fluid;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.impl.client.render.fluid.FluidRendererHookContainer;
import net.fabricmc.fabric.impl.client.render.fluid.FluidRenderHandlerRegistryImpl;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.block.FluidRenderer;
import net.minecraft.client.texture.Sprite;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ExtendedBlockView;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(FluidRenderer.class)
public class MixinFluidRenderer {
@Shadow
private Sprite[] lavaSprites;
@Shadow
private Sprite[] waterSprites;
private final ThreadLocal<FluidRendererHookContainer> fabric_renderHandler = ThreadLocal.withInitial(FluidRendererHookContainer::new);
@Inject(at = @At("RETURN"), method = "onResourceReload")
public void onResourceReloadReturn(CallbackInfo info) {
FluidRenderHandlerRegistryImpl.INSTANCE.onFluidRendererReload(waterSprites, lavaSprites);
}
@Inject(at = @At("HEAD"), method = "tesselate", cancellable = true)
public void tesselate(ExtendedBlockView view, BlockPos pos, BufferBuilder bufferBuilder, FluidState state, CallbackInfoReturnable<Boolean> info) {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
FluidRenderHandler handler = FluidRenderHandlerRegistryImpl.INSTANCE.getOverride(state.getFluid());
if (handler == null) {
return;
}
/* ActionResult hResult = handler.tesselate(view, pos, bufferBuilder, state);
if (hResult != ActionResult.PASS) {
info.setReturnValue(hResult == ActionResult.SUCCESS);
return;
} */
ctr.view = view;
ctr.pos = pos;
ctr.state = state;
ctr.handler = handler;
}
@Inject(at = @At("RETURN"), method = "tesselate")
public void tesselateReturn(ExtendedBlockView view, BlockPos pos, BufferBuilder bufferBuilder, FluidState state, CallbackInfoReturnable<Boolean> info) {
fabric_renderHandler.get().clear();
}
@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 = "tesselate", ordinal = 0)
public boolean modLavaCheck(boolean chk) {
return fabric_renderHandler.get().handler != null || chk;
}
@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 = "tesselate", 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;
}
@ModifyVariable(at = @At(value = "CONSTANT", args = "intValue=16", ordinal = 0, shift = At.Shift.BEFORE), method = "tesselate", ordinal = 0)
public int modTintColor(int chk) {
FluidRendererHookContainer ctr = fabric_renderHandler.get();
return ctr.handler != null ? ctr.handler.getFluidColor(ctr.view, ctr.pos, ctr.state) : chk;
}
}

View file

@ -0,0 +1,11 @@
{
"required": true,
"package": "net.fabricmc.fabric.mixin.client.render.fluid",
"compatibilityLevel": "JAVA_8",
"client": [
"MixinFluidRenderer"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -0,0 +1,16 @@
{
"schemaVersion": 1,
"id": "fabric-rendering-fluids-v1",
"version": "${version}",
"license": "Apache-2.0",
"depends": {
"fabricloader": ">=0.4.0",
"fabric-api-base": "*"
},
"recommends": {
"fabric-textures-v0": "*"
},
"mixins": [
"fabric-rendering-fluids-v1.mixins.json"
]
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016, 2017, 2018 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.fluidrender;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.render.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.FluidRenderHandlerRegistry;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.fluid.Fluids;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
public class FluidRendererModClient implements ClientModInitializer, SimpleSynchronousResourceReloadListener {
@Override
public void onInitializeClient() {
ResourceManagerHelper.get(ResourceType.ASSETS).registerReloadListener(this);
}
@Override
public Identifier getFabricId() {
return new Identifier("fabric:fluid_renderer_test");
}
@Override
public void apply(ResourceManager rm) {
FluidRenderHandler lavaHandler = FluidRenderHandlerRegistry.INSTANCE.get(Fluids.LAVA);
FluidRenderHandlerRegistry.INSTANCE.register(Fluids.WATER, lavaHandler);
FluidRenderHandlerRegistry.INSTANCE.register(Fluids.FLOWING_WATER, lavaHandler);
}
}

View file

@ -29,6 +29,7 @@ include 'fabric-networking-blockentity-v0'
include 'fabric-object-builders-v0'
include 'fabric-registry-sync-v0'
include 'fabric-rendering-v0'
include 'fabric-rendering-fluids-v1'
include 'fabric-resource-loader-v0'
include 'fabric-tag-extensions-v0'
include 'fabric-textures-v0'