Hello! I've been trying to make a block in Forge that stores a simple liquid, and a renderer that would show that liquid in the block itself.
I have been attempting to get the renderer to work with only water at first, since it's probably easier to get a simple case to work instead of trying to implement everything at once when you don't fully understand Forge itself.
Unfortunately the texture seems to be completely black, and when I try to adjust the buffer's color function, it seems like it doesn't change anything. (alpha on 255 still keeps the texture that is rendered semi-transparent, however alpha being 0 does make the texture invisible)
Any ideas on what to do from here? I copied a lot of code from Eidolon (https://github.com/elucent/eidolon/blob/master/), most specifically the Crucible tile entity & renderer for this part, and the Crucible seems to work fine with this code. (I have not attempted compiling his mod manually yet however)
Here are my bits of code:
InfuserBlockRenderer class:
package com.midori.liquimancy.common.tile;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.WaterFluid;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ColorHelper.PackedColor;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.biome.BiomeColors;
public class InfuserBlockRenderer extends TileEntityRenderer<InfuserTileEntity> {
public InfuserBlockRenderer(TileEntityRendererDispatcher rendererDispatcherIn) {
super(rendererDispatcherIn);
}
@Override
public void render(InfuserTileEntity tileEntityIn, float partialTicks, MatrixStack matrixStackIn, IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn) {
Minecraft mc = Minecraft.getInstance();
if (tileEntityIn.containsFluid()) {
TextureAtlasSprite water = mc.getAtlasSpriteGetter(AtlasTexture.LOCATION_BLOCKS_TEXTURE)
.apply(new ResourceLocation("minecraft", "block/water_still"));
IVertexBuilder builder = bufferIn.getBuffer(RenderType.getTranslucentNoCrumbling());
Matrix4f mat = matrixStackIn.getLast().getMatrix();
int color = BiomeColors.getWaterColor(tileEntityIn.getWorld(), tileEntityIn.getPos());
int r = PackedColor.getRed(color), g = PackedColor.getGreen(color),
b = PackedColor.getBlue(color), a = PackedColor.getAlpha(color);
System.out.println("colors: " + r + ", "+ g + ", "+ b + ", " + a);
builder.pos(mat, 0.125f, 0.75f, 0.125f).color(r, g, b, 192).tex(water.getInterpolatedU(2), water.getInterpolatedV(2)).lightmap(combinedLightIn).normal(0, 1, 0).endVertex();
builder.pos(mat, 0.125f, 0.75f, 0.875f).color(r, g, b, 192).tex(water.getInterpolatedU(14), water.getInterpolatedV(2)).lightmap(combinedLightIn).normal(0, 1, 0).endVertex();
builder.pos(mat, 0.875f, 0.75f, 0.875f).color(r, g, b, 192).tex(water.getInterpolatedU(14), water.getInterpolatedV(14)).lightmap(combinedLightIn).normal(0, 1, 0).endVertex();
builder.pos(mat, 0.875f, 0.75f, 0.125f).color(r, g, b, 192).tex(water.getInterpolatedU(2), water.getInterpolatedV(14)).lightmap(combinedLightIn).normal(0, 1, 0).endVertex();
}
}
}
InfuserTileEntity class:
package com.midori.liquimancy.common.tile;
import com.midori.liquimancy.Registry;
import com.midori.liquimancy.network.PacketHandler;
import com.midori.liquimancy.network.SyncPacket;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraftforge.fml.network.PacketDistributor;
import java.util.HashMap;
public class InfuserTileEntity extends TileEntity implements ITickableTileEntity {
Fluid contains;
//TODO: change the location of this dictionary and make it public
//TODO: make this dictionary generate on mod load
HashMap<String, ResourceLocation> fluidMap = new HashMap<>();
public InfuserTileEntity() {
this(Registry.INFUSER_TILE_ENTITY);
}
public InfuserTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
fluidMap.put("water", new ResourceLocation("minecraft", "block/water_still"));
fluidMap.put("lava", new ResourceLocation("minecraft", "block/lava_still"));
}
public void sync() {
markDirty();
if (world.isRemote)
PacketHandler.INSTANCE.sendToServer(new SyncPacket(pos, write(new CompoundNBT())));
else
PacketHandler.INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(() -> world.getChunkAt(pos)), new SyncPacket(pos, write(new CompoundNBT())));
}
public boolean containsFluid() {
return contains != null;
}
public Fluid getFluid() {
return contains;
}
public ResourceLocation getResource(String type) {
return null;
}
public ActionResultType onActivation(PlayerEntity player, Hand handIn, BlockRayTraceResult resultIn) {
if (player.getHeldItem(handIn).getItem() == Items.WATER_BUCKET)
{
contains = Fluids.WATER;
player.setHeldItem(handIn, new ItemStack(Items.BUCKET, 1));
if(!world.isRemote) {
sync();
}
return ActionResultType.SUCCESS;
}
else if (player.getHeldItem(handIn).getItem() == Items.LAVA_BUCKET)
{
contains = Fluids.LAVA;
player.setHeldItem(handIn, new ItemStack(Items.BUCKET, 1));
if(!world.isRemote) {
sync();
}
return ActionResultType.SUCCESS;
}
return ActionResultType.PASS;
}
@Override
public void tick() {
}
}
InfuserBlock class:
package com.midori.liquimancy.common.block;
import com.midori.liquimancy.common.tile.InfuserTileEntity;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class InfuserBlock extends Block {
TileEntityType<InfuserTileEntity> type;
public InfuserBlock(Properties properties) {
super(properties);
}
public void setTileEntityType(TileEntityType<InfuserTileEntity> type) {
this.type = type;
}
public TileEntityType<InfuserTileEntity> getTileEntityType() {
return type;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return type.create();
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult resultIn) {
if (hasTileEntity(state)) {
TileEntity te = worldIn.getTileEntity(pos);
return ((InfuserTileEntity) worldIn.getTileEntity(pos)).onActivation(player, handIn, resultIn);
}
return super.onBlockActivated(state, worldIn, pos, player, handIn, resultIn);
}
}
I bind my tile entity and renderer together like this in my mod class
@OnlyIn(Dist.CLIENT)
private void doClientStuff(final FMLClientSetupEvent event) {
ClientRegistry.bindTileEntityRenderer(Registry.INFUSER_TILE_ENTITY, (trd) -> new InfuserBlockRenderer(trd));
}
:
And finally, I register my tile entity like this in the Registry class I have:
//TODO: make work for any tile entity
static <T extends TileEntity> TileEntityType<T> addTileEntity(IForgeRegistry<TileEntityType<?>> registry, String name, Supplier<T> factory, InfuserBlock... blocks) {
TileEntityType<T> type = TileEntityType.Builder.<T>create(factory, blocks).build(null);
System.out.println("fired registery for " + name);
type.setRegistryName("liquimancy", name);
registry.register(type);
for (InfuserBlock block : blocks) block.setTileEntityType((TileEntityType<InfuserTileEntity>) type);
return type;
}
public static TileEntityType<InfuserTileEntity> INFUSER_TILE_ENTITY;
@SubscribeEvent
public void registerTiles(RegistryEvent.Register<TileEntityType<?>> evt) {
INFUSER_TILE_ENTITY = addTileEntity(evt.getRegistry(), "infuser_tile", InfuserTileEntity::new, (InfuserBlock)INFUSER_BLOCK.get());
}
Example of my weird rendering (please ignore the not correct sizedness of the texture (which I reverted back to see if it changed anything), and the weird placeholder texture (which in retrospect looks a lot like a diglett ))
Note how it is black compared to the blue water next to it. Meanwhile the console is giving me this output:
[21:19:24] [Render thread/INFO] [STDOUT/]: [com.midori.liquimancy.common.tile.InfuserBlockRenderer:render:37]: colors: 63, 118, 228, 0
:
If there is a class or function I should give with this for easier or further identification of this issue, please let me know!