Jump to content

Zarathul

Members
  • Posts

    15
  • Joined

  • Last visited

Posts posted by Zarathul

  1. Teleporting players is a messy business. ServerPlayerEntity#changeDimension() has all kinds of hardcoded stuff that assumes it was called from a vanilla portal, and therefore isn't really suited for general purpose use. You can try ServerPlayerEntity#teleport() instead. Be warned though, ServerPlayerEntity#teleport() will not work from Block#onEntityCollision(). If your are using it only in a command you should be fine.

  2. Now that Item#doesSneakBypassUse() is back in, I've been trying to get my item to work properly again when dual wielding. In 1.12.2 I used PlayerInteractEvent#RightClickBlock to get Block#onBlockActivated() to trigger even when sneaking and holding an item in both hands (by setting UseBlock to Allow and UseItem to Deny under the right circumstances). Without this, half the functionalty of my wrench doesn't work if the player is holding a shield for example and tries to use the wrench while sneaking.

    This approach doesn't seem to work anymore, because it is now required for both items to return true in doesSneakBypassUse() when sneaking, which is never the case for vanilla items (because the default behavior of IForgeItem#doesSneakBypassUse() is to return false).

    boolean flag = !p_219441_1_.getHeldItemMainhand().isEmpty() || !p_219441_1_.getHeldItemOffhand().isEmpty();
    boolean flag1 = !(p_219441_1_.isSneaking() && flag) || (p_219441_1_.getHeldItemMainhand().doesSneakBypassUse(p_219441_2_,blockpos,p_219441_1_) && p_219441_1_.getHeldItemOffhand().doesSneakBypassUse(p_219441_2_,blockpos,p_219441_1_));
    if (event.getUseBlock() != net.minecraftforge.eventbus.api.Event.Result.DENY && flag1 && blockstate.onBlockActivated(p_219441_2_, p_219441_1_, p_219441_4_, p_219441_5_)) {
    	return ActionResultType.SUCCESS;
    }

    Is this broken or intended behavior ...  or am I missing something ? I mean, isn't the whole purpose of PlayerInteractEvent#RightClickBlock to override default behavior?

  3. I did some further testing.

    Porting from Item#onItemUse never produces the message, doesn't matter if I'm running around or standing still.

     

    @Override
    public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side,
    	float hitX, float hitY, float hitZ)
    {
    if (!world.isRemote)
    {
    	EntityPlayerMP playerMp = (player instanceof EntityPlayerMP) ? (EntityPlayerMP)player : null;
    	if (playerMp != null)
    	{
    		BlockPos destination = playerMp.getPosition().offset(playerMp.getHorizontalFacing(), 10);
    		playerMp.playerNetServerHandler.setPlayerLocation(destination.getX() + 0.5d, destination.getY(), destination.getZ() + 0.5d, player.rotationYaw, player.rotationPitch);
    	}
    }
    
    return true;
    }
    

     

    While porting from Block#onEntityCollidedWithBlock will produce the message about half the time when walking into the block. Also, sometimes the handler is triggered twice and therefore the player is ported twice the distance.

     

    @Override
    public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity)
    {
    if (!world.isRemote && entity.ridingEntity == null && entity.riddenByEntity == null && !entity.isDead)
    {
    	EntityPlayerMP player = (entity instanceof EntityPlayerMP) ? (EntityPlayerMP)entity : null;
    	if (player != null)
    	{
    		BlockPos destination = player.getPosition().offset(player.getHorizontalFacing(), 10);
    		player.playerNetServerHandler.setPlayerLocation(destination.getX() + 0.5d, destination.getY(), destination.getZ() + 0.5d, player.rotationYaw, player.rotationPitch);
    	}
    }
    }
    

     

    In my proper code I add a cooldown to ported entities (basically a HashMap of UniquieIDs and Timestamps), so I don't have the problem with the double port. What is strange though, is when I walk into the block while on cooldown and I'm then ported while standing still, I also never get the message.

  4. Entity#setVelocity is client-side only due to the way the code is compiled / decompiled; since it is only ever called on the client side, it gets marked with the @SideOnly annotation.

    Ahhh good to know.

     

    To teleport entities, I prefer to use #setPosition; then I check if it's an EntityPlayer and if so, I additionally call #setPositionAndUpdate to make sure the client player gets the memo.

    Hmm very strange. Tried it but still get the message. I looked at #setPositionAndUpdate and it just calls playerNetServerHandler.setPlayerLocation so it's basically the same I do.

     

    Still thx for the answers!

  5. When teleporting a moving player I get the "Player moved wrongly!" message on the server. If the player stands still when ported there's no message. Teleportation is done the same way CommandTeleport does it, just from inside a Block#onEntityCollidedWithBlock() handler on the server side.

    EntityPlayerMP player = (entity instanceof EntityPlayerMP) ? (EntityPlayerMP)entity : null;
    
    if (player != null)
    {
    player.playerNetServerHandler.setPlayerLocation(destination.getX() + 0.5d, destination.getY(), destination.getZ() + 0.5d, getYaw(facing), player.rotationPitch);
    }
    
    

     

    I tried to stop the player and then port but it had no effect.

     

    player.motionX = 0;
    player.motionY = 0;
    player.motionZ = 0;
    player.playerNetServerHandler.sendPacket(new S12PacketEntityVelocity(player));
    

     

    (Why is Entity#setVelocity() client side only btw?)

     

    I also tried switching the player to creative mode temporarily (I know .. bad idea) during the port because this would normally suppress this particular movement check (see NetHandlerPlayServer#processPlayer()), but that didn't work either. Probably because the check hasn't been performed yet when I reset the game mode.

     

     

    If anybody has some input on this, what I'm doing wrong or any Ideas on how to get rid of the message I'd appreciate it.

  6. So as promised an (attempted) explanation for what I did.

     

    I ended up making two separate models, one for the tank frame and one for the fluid. The tank model has a blockstate json that defines all the connected textures variants. The fluid model has none.

     

    In onModelBakeEvent the fluid model is loaded using the ModelLoader and cast to IRetexturableModel. Then .retexture() is called on it for every fluid in the forge fluid registry. The resulting models get baked and cached. Finally all tank variant models in the ModelRegistry get replaced with an ISmartBlockModel that stores the tank variant model.

     

    In ISmartBlockModel.handleBlockState() an IBakedModel is returned that gets the variant model from the ISmartBlockModel and the fluid name from the IExtendedBlockState. In getFaceQuads() and getGeneralQuads() the IBakedModel returns the quads of the tank variant model plus the quads of the previously cached fluid model determined by the stored fluid name.

     

    There's some additional stuff happening and there is actually more than one fluid model for the different fill levels of the tank, but explaining that would make everything too complicated.

     

    For those that prefer looking at code:

    https://github.com/Zarathul/simplefluidtanks/blob/1.8/src/main/java/net/zarathul/simplefluidtanks/ClientEventHub.java

    https://github.com/Zarathul/simplefluidtanks/blob/1.8/src/main/java/net/zarathul/simplefluidtanks/rendering/TankModelFactory.java

    https://github.com/Zarathul/simplefluidtanks/blob/1.8/src/main/java/net/zarathul/simplefluidtanks/rendering/BakedTankModel.java

  7. I'm trying to port my multi block fluid tank from 1.7.10. I got connected textures to work using the new model system and blockstates but I can't figure out how to go about rendering the fluid. The problem is the texture. I can't predefine any textures in the .jsons because I don't know what fluids other mods will add. So I looked at ISmartBlockModel in hope of finding a way to change the fluid texture programmatically but I can't figure out how to do it (I also read TheGreyGhosts examples for ISmartBlockModel but they deal only with swapping out entire models or composing them together, no texture changes). I'm aware that in this case going with TESR would probably much easier but I want to avoid the performance hit if at all possible.

     

    If someone can point me in the right direction or even give a short example I would be grateful.

  8. Don't know if it's the best way, but it works for me.

     

    (preInit)
    GameRegistry.registerBlock(yourBlock, yourBlockItem.class, yourBlockName);
    
    (init)
    Item yourBlockItem = GameRegistry.findItem(yourModId, yourBlockName);
    Minecraft.getMinecraft().getRenderItem().getItemModelMesher().modelMesher.register(yourBlockItem , 0, new ModelResourceLocation("yourModId:yourBlockName", "inventory"));
    

  9. This will allow you to place torches, ladders, redstone etc. on top or on the sides of your block respectively .

     

    For 1.6.4

    @Override
    public boolean isBlockSolidOnSide(World world, int x, int y, int z, ForgeDirection side)
    {
    return true;
    }
    

     

    and for 1.7.2

    @Override
    public boolean isSideSolid(IBlockAccess world, int x, int y, int z, ForgeDirection side)
    {
    return true;
    }
    

  10. UPDATE: Turns out when another entity is in the scene the wrong texture map is set (items instead of blocks) . Adding "bindTexture(TextureMap.locationBlocksTexture)" in "renderTileEntityAt()" fixed the problem.

     

    I implemented a TileEntitySpecialRenderer and everything is rendered exactly as it should be until any entitys other than my own enter the scene (e.g. any item, any creature and even the player itself in 3rd person view). I first thought I messed up with the Tessellator.draw() and Tessellator.startDrawingQuads() calls but if I do it any other way than in the posted code I get the usual exceptions ("tessellator already tessellating" etc). Hints on what's going on here would be very appreciated.

    (The transparent blocks are the ones rendered by the TileEntitySpecialRenderer)

     

    That's how it's always supposed to look like

    a3gneq.jpg

     

    That's how it looks with an addtional entity in the scene (the bucket on the ground).

    34nmnvo.png

     

    TileEntitySpecialRenderer

    package simplefluidtanks;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    
    import org.lwjgl.opengl.GL11;
    
    import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
    import cpw.mods.fml.client.registry.RenderingRegistry;
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
    
    import net.minecraft.block.Block;
    import net.minecraft.client.Minecraft;
    import net.minecraft.client.renderer.RenderBlocks;
    import net.minecraft.client.renderer.Tessellator;
    import net.minecraft.client.renderer.texture.IconRegister;
    import net.minecraft.client.renderer.texture.SimpleTexture;
    import net.minecraft.client.renderer.texture.TextureAtlasSprite;
    import net.minecraft.client.renderer.texture.TextureManager;
    import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
    import net.minecraft.launchwrapper.LogWrapper;
    import net.minecraft.tileentity.TileEntity;
    import net.minecraft.util.Icon;
    import net.minecraft.util.ResourceLocation;
    import net.minecraft.world.IBlockAccess;
    import net.minecraftforge.client.IItemRenderer;
    import net.minecraftforge.client.model.AdvancedModelLoader;
    import net.minecraftforge.client.model.IModelCustom;
    import net.minecraftforge.fluids.FluidRegistry;
    import net.minecraftforge.fluids.FluidRegistry.FluidRegisterEvent;
    import net.minecraftforge.fluids.FluidStack;
    
    @SideOnly(Side.CLIENT)
    public class TankBlockRenderer extends TileEntitySpecialRenderer
    {
    public TankBlockRenderer()
    {
    	super();
    }
    
    @Override
    public void renderTileEntityAt(TileEntity tileEntity, double x, double y, double z, float f)
    {
    	if (tileEntity == null || !(tileEntity instanceof TankBlockEntity))
    	{
    		return;
    	}
    
    	Block block = tileEntity.getBlockType();
    
    	if (block == null || !(block instanceof TankBlock))
    	{
    		return;
    	}
    
    	TankBlock tank = (TankBlock)block;
    	TankBlockEntity entity = (TankBlockEntity)tileEntity;
    	Icon[] icons = tank.getIcons();
    
    	Tessellator tsr = Tessellator.instance;
    	int brightness = block.getMixedBrightnessForBlock(entity.worldObj, entity.xCoord, entity.yCoord, entity.zCoord);
    	tsr.setBrightness(brightness);
    
    	TessellationManager.setBaseCoords(x, y, z);
    
    	if (tsr.isDrawing) tsr.draw();
    
    	tsr.startDrawingQuads();
    
    	if (!entity.isPartOfTank())
    	{
    		renderSolid(entity, icons[0]);
    	}
    	else
    	{
    		boolean[] connections = entity.getConnections();
    		int fillPercentage = entity.getFillPercentage();
    		double fluidHeight = 16.0 / 100 * fillPercentage;
    		double verticalTextureOffset = 16.0 / 100 * (100 - fillPercentage);
    		Icon fluidIcon = getFluidTexture(entity);
    
    		renderPositiveXFace(entity, connections, icons, fluidIcon, fillPercentage, fluidHeight, verticalTextureOffset);
    		renderNegativeXFace(entity, connections, icons, fluidIcon, fillPercentage, fluidHeight, verticalTextureOffset);
    		renderPositiveZFace(entity, connections, icons, fluidIcon, fillPercentage, fluidHeight, verticalTextureOffset);
    		renderNegativeZFace(entity, connections, icons, fluidIcon, fillPercentage, fluidHeight, verticalTextureOffset);
    		renderPositiveYFace(entity, connections, icons, fluidIcon, fillPercentage, fluidHeight);
    		renderNegativeYFace(entity, connections, icons, fluidIcon, fillPercentage);
    	}
    
    	tsr.draw();
    }
    
    private void renderSolid(TankBlockEntity entity, Icon icon)
    {
    	TessellationManager.renderCube(1, 0, 1, 14, 14, 14, icon, true, TessellationManager.pixel);
    }
    
    private void renderPositiveXFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage, double fluidHeight, double verticalTextureOffset)
    {
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (!connections[ConnectedTexturesHelper.XPOS])
    	{
    		if (fillPercentage > 0 && fluidIcon != null)
    		{
    			TessellationManager.renderPositiveXFace(16, 0, 0, fluidHeight, 16, 0, verticalTextureOffset, 0, 0, fluidIcon, TessellationManager.pixel);
    		}
    
    		TessellationManager.renderPositiveXFace(16, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.XPOS)]);
    		// inner face
    		TessellationManager.renderNegativeXFace(16, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.XNEG)]);
    	}
    }
    
    private void renderNegativeXFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage, double fluidHeight, double verticalTextureOffset)
    {
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (!connections[ConnectedTexturesHelper.XNEG])
    	{
    		if (fillPercentage > 0 && fluidIcon != null)
    		{
    			TessellationManager.renderNegativeXFace(0, 0, 0, fluidHeight, 16, 0, verticalTextureOffset, 0, 0, fluidIcon, TessellationManager.pixel);
    		}
    
    		TessellationManager.renderNegativeXFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.XNEG)]);
    		// inner face
    		TessellationManager.renderPositiveXFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.XPOS)]);
    	}
    }
    
    private void renderPositiveZFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage, double fluidHeight, double verticalTextureOffset)
    {
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (!connections[ConnectedTexturesHelper.ZPOS])
    	{
    		if (fillPercentage > 0 && fluidIcon != null)
    		{
    			TessellationManager.renderPositiveZFace(0, 0, 16, 16, fluidHeight, 0, verticalTextureOffset, 0, 0, fluidIcon, TessellationManager.pixel);
    		}
    
    		TessellationManager.renderPositiveZFace(0, 0, 16, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.ZPOS)]);
    		// inner face
    		TessellationManager.renderNegativeZFace(0, 0, 16, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.ZNEG)]);
    	}
    }
    
    private void renderNegativeZFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage, double fluidHeight, double verticalTextureOffset)
    {
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (!connections[ConnectedTexturesHelper.ZNEG])
    	{
    		if (fillPercentage > 0 && fluidIcon != null)
    		{
    			TessellationManager.renderNegativeZFace(0, 0, 0, 16, fluidHeight, 0, verticalTextureOffset, 0, 0, fluidIcon, TessellationManager.pixel);
    		}
    
    		TessellationManager.renderNegativeZFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.ZNEG)]);
    		// inner face
    		TessellationManager.renderPositiveZFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.ZPOS)]);
    	}
    }
    
    private void renderPositiveYFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage, double fluidHeight)
    {
    	if (fillPercentage > 0 && fluidIcon != null)
    	{
    		TessellationManager.renderPositiveYFace(0, fluidHeight, 0, 16, 16, fluidIcon);
    	}
    
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (!connections[ConnectedTexturesHelper.YPOS])
    	{
    		TessellationManager.renderPositiveYFace(0, 16, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.YPOS)]);
    		// inner face
    		TessellationManager.renderNegativeYFace(0, 16, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.YNEG)]);
    	}
    }
    
    private void renderNegativeYFace(TankBlockEntity entity, boolean[] connections, Icon[] icons, Icon fluidIcon, int fillPercentage)
    {
    	// only render this side if there isn't a tank block from the same tank in front of it 
    	if (fillPercentage > 0 && fluidIcon != null && !connections[ConnectedTexturesHelper.YNEG])
    	{
    		TessellationManager.renderNegativeYFace(0, 0, 0, 16, 16, fluidIcon);
    	}
    
    	if (!connections[ConnectedTexturesHelper.YNEG])
    	{
    		TessellationManager.renderNegativeYFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.YNEG)]);
    		// inner face
    		TessellationManager.renderPositiveYFace(0, 0, 0, 16, 16, icons[entity.getTexture(ConnectedTexturesHelper.YPOS)]);
    	}
    }
    
    private Icon getFluidTexture(TankBlockEntity entity)
    {
    	ValveBlockEntity valve = entity.getValve();
    
    	if (valve != null)
    	{
    		FluidStack fluidStack = valve.getFluid();
    
    		if (fluidStack != null)
    		{
    			return fluidStack.getFluid().getIcon();
    		}
    	}
    
    	return null;
    }
    }
    

     

    TessellationManager (helper class)

    package simplefluidtanks;
    
    import net.minecraft.client.Minecraft;
    import net.minecraft.client.renderer.Tessellator;
    import net.minecraft.util.Icon;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fluids.FluidRegistry;
    
    public final class TessellationManager
    {
    public static final double pixel = 1d / 16d;
    
    private static final Tessellator tr = Tessellator.instance;
    private static double xBaseCoord;
    private static double yBaseCoord;
    private static double zBaseCoord;
    
    private TessellationManager()
    {
    }
    
    public static void setBaseCoords(double ... coords)
    {
    	if (coords != null && coords.length >= 3)
    	{
    		xBaseCoord = coords[0];
    		yBaseCoord = coords[1];
    		zBaseCoord = coords[2];
    	}
    }
    
    public static void renderCube(double xOffset, double yOffset, double zOffset, double width, double height, double depth, Icon icon)
    {
    	renderCube(xOffset, yOffset, zOffset, width, height, depth, icon, false, pixel);
    }
    
    public static void renderCube(double xOffset, double yOffset, double zOffset, double width, double height, double depth, Icon icon, boolean renderInside, double scale)
    {
    	renderPositiveXFace(xOffset + width, yOffset, zOffset, height, depth, icon, scale);
    	renderNegativeXFace(xOffset, yOffset, zOffset, height, depth, icon, scale);
    	renderPositiveYFace(xOffset, yOffset + height, zOffset, width, depth, icon, scale);
    	renderNegativeYFace(xOffset, yOffset, zOffset, width, depth, icon, scale);
    	renderPositiveZFace(xOffset, yOffset, zOffset + depth, width, height, icon, scale);
    	renderNegativeZFace(xOffset, yOffset, zOffset, width, height, icon, scale);
    
    	if (renderInside)
    	{
    		// positive x back side
    		renderNegativeXFace(xOffset + width, yOffset, zOffset, height, depth, icon, scale);
    		// negative x back side
    		renderPositiveXFace(xOffset, yOffset, zOffset, height, depth, icon, scale);
    		// positive y back side
    		renderNegativeYFace(xOffset, yOffset + height, zOffset, width, depth, icon, scale);
    		// negative y back side
    		renderPositiveYFace(xOffset, yOffset, zOffset, width, depth, icon, scale);
    		// positive z back side
    		renderNegativeZFace(xOffset, yOffset, zOffset + depth, width, height, icon, scale);
    		// negative back side
    		renderPositiveZFace(xOffset, yOffset, zOffset, width, height, icon, scale);
    	}
    }
    
    public static void renderPositiveXFace(double xOffset, double yOffset, double zOffset, double height, double depth, Icon icon)
    {
    	renderPositiveXFace(xOffset, yOffset, zOffset, height, depth, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderPositiveXFace(double xOffset, double yOffset, double zOffset, double height, double depth, Icon icon, double scale)
    {
    	renderPositiveXFace(xOffset, yOffset, zOffset, height, depth, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderPositiveXFace(double xOffset, double yOffset, double zOffset, double height, double depth, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(1f, 0f, 0f);
    
    	double x = xBaseCoord + xOffset * scale;
    
    	// bottom right
    	double zBr = zBaseCoord + zOffset * scale;
    	double yBr = yBaseCoord + yOffset * scale;
    
    	// top right
    	double zTr = zBaseCoord + zOffset * scale;
    	double yTr = yBaseCoord + (yOffset + height) * scale;
    
    	// top left
    	double zTl = zBaseCoord + (zOffset + depth) * scale;
    	double yTl = yBaseCoord + (yOffset + height) * scale;
    
    	// bottom left
    	double zBl = zBaseCoord + (zOffset + depth) * scale;
    	double yBl = yBaseCoord + yOffset * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// bottom right
    	tr.addVertexWithUV(x, yBr, zBr, maxU, maxV);
    	// top right
    	tr.addVertexWithUV(x, yTr, zTr, maxU, minV);
    	// top left
    	tr.addVertexWithUV(x, yTl, zTl, minU, minV);
    	// bottom left
    	tr.addVertexWithUV(x, yBl, zBl, minU, maxV);
    }
    
    public static void renderNegativeXFace(double xOffset, double yOffset, double zOffset, double height, double depth, Icon icon)
    {
    	renderNegativeXFace(xOffset, yOffset, zOffset, height, depth, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderNegativeXFace(double xOffset, double yOffset, double zOffset, double height, double depth, Icon icon, double scale)
    {
    	renderNegativeXFace(xOffset, yOffset, zOffset, height, depth, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderNegativeXFace(double xOffset, double yOffset, double zOffset, double height, double depth, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(-1f, 0f, 0f);
    
    	double x = xBaseCoord + xOffset * scale;
    
    	// bottom left
    	double zBl = zBaseCoord + zOffset * scale;
    	double yBl = yBaseCoord + yOffset * scale;
    
    	// bottom right
    	double zBr = zBaseCoord + (zOffset + depth) * scale;
    	double yBr = yBaseCoord + yOffset * scale;
    
    	// top right
    	double zTr = zBaseCoord + (zOffset + depth) * scale;
    	double yTr = yBaseCoord + (yOffset + height) * scale;
    
    	// top left
    	double zTl = zBaseCoord + zOffset * scale;
    	double yTl = yBaseCoord + (yOffset + height) * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// bottom left
    	tr.addVertexWithUV(x, yBl, zBl, minU, maxV);
    	// bottom right
    	tr.addVertexWithUV(x, yBr, zBr, maxU, maxV);
    	// top right
    	tr.addVertexWithUV(x, yTr, zTr, maxU, minV);
    	// top left
    	tr.addVertexWithUV(x, yTl, zTl, minU, minV);
    }
    
    public static void renderPositiveYFace(double xOffset, double yOffset, double zOffset, double width, double depth, Icon icon)
    {
    	renderPositiveYFace(xOffset, yOffset, zOffset, width, depth, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderPositiveYFace(double xOffset, double yOffset, double zOffset, double width, double depth, Icon icon, double scale)
    {
    	renderPositiveYFace(xOffset, yOffset, zOffset, width, depth, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderPositiveYFace(double xOffset, double yOffset, double zOffset, double width, double depth, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(0f, 1f, 0f);
    
    	double y = yBaseCoord + yOffset * scale;
    
    	// bottom right
    	double xBr = xBaseCoord + xOffset * scale;
    	double zBr = zBaseCoord + zOffset * scale;
    
    	// top right
    	double xTr = xBaseCoord + xOffset * scale;
    	double zTr = zBaseCoord + (zOffset + depth) * scale;
    
    	// top left
    	double xTl = xBaseCoord + (xOffset + width) * scale;
    	double zTl = zBaseCoord + (zOffset + depth) * scale;
    
    	// bottom left
    	double xBl = xBaseCoord + (xOffset + width) * scale;
    	double zBl = zBaseCoord + zOffset * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// bottom right
    	tr.addVertexWithUV(xBr, y, zBr, maxU, maxV);
    	// top right
    	tr.addVertexWithUV(xTr, y, zTr, maxU, minV);
    	// top left
    	tr.addVertexWithUV(xTl, y, zTl, minU, minV);
    	// bottom left
    	tr.addVertexWithUV(xBl, y, zBl, minU, maxV);
    }
    
    public static void renderNegativeYFace(double xOffset, double yOffset, double zOffset, double width, double depth, Icon icon)
    {
    	renderNegativeYFace(xOffset, yOffset, zOffset, width, depth, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderNegativeYFace(double xOffset, double yOffset, double zOffset, double width, double depth, Icon icon, double scale)
    {
    	renderNegativeYFace(xOffset, yOffset, zOffset, width, depth, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderNegativeYFace(double xOffset, double yOffset, double zOffset, double width, double depth, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(0f, -1f, 0f);
    
    	double y = yBaseCoord + yOffset * scale;
    
    	// top right
    	double xTr = xBaseCoord + xOffset * scale;
    	double zTr = zBaseCoord + zOffset * scale;
    
    	// top left
    	double xTl = xBaseCoord + (xOffset + width) * scale;
    	double zTl = zBaseCoord + zOffset * scale;
    
    	// bottom left
    	double xBl = xBaseCoord + (xOffset + width) * scale;
    	double zBl = zBaseCoord + (zOffset + depth) * scale;
    
    	// bottom right
    	double xBr = xBaseCoord + xOffset * scale;
    	double zBr = zBaseCoord + (zOffset + depth) * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// top right
    	tr.addVertexWithUV(xTr, y, zTr, maxU, minV);
    	// top left
    	tr.addVertexWithUV(xTl, y, zTl, minU, minV);
    	// bottom left
    	tr.addVertexWithUV(xBl, y, zBl, minU, maxV);
    	// bottom right
    	tr.addVertexWithUV(xBr, y, zBr, maxU, maxV);
    }
    
    public static void renderPositiveZFace(double xOffset, double yOffset, double zOffset, double width, double height, Icon icon)
    {
    	renderPositiveZFace(xOffset, yOffset, zOffset, width, height, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderPositiveZFace(double xOffset, double yOffset, double zOffset, double width, double height, Icon icon, double scale)
    {
    	renderPositiveZFace(xOffset, yOffset, zOffset, width, height, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderPositiveZFace(double xOffset, double yOffset, double zOffset, double width, double height, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(0f, 0f, 1f);
    
    	double z = zBaseCoord + zOffset * scale;
    
    	// bottom left
    	double xBl = xBaseCoord + xOffset * scale;
    	double yBl = yBaseCoord + yOffset * scale;
    
    	// bottom right
    	double xBr = xBaseCoord + (xOffset + width) * scale;
    	double yBr = yBaseCoord + yOffset * scale;
    
    	// top right
    	double xTr = xBaseCoord + (xOffset + width) * scale;
    	double yTr = yBaseCoord + (yOffset + height) * scale;
    
    	// top left
    	double xTl = xBaseCoord + xOffset * scale;
    	double yTl = yBaseCoord + (yOffset + height) * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// bottom left
    	tr.addVertexWithUV(xBl, yBl, z, minU, maxV);
    	// bottom right
    	tr.addVertexWithUV(xBr, yBr, z, maxU, maxV);
    	// top right
    	tr.addVertexWithUV(xTr, yTr, z, maxU, minV);
    	// top left
    	tr.addVertexWithUV(xTl, yTl, z, minU, minV);
    }
    
    public static void renderNegativeZFace(double xOffset, double yOffset, double zOffset, double width, double height, Icon icon)
    {
    	renderNegativeZFace(xOffset, yOffset, zOffset, width, height, 0, 0, 0, 0, icon, pixel);
    }
    
    public static void renderNegativeZFace(double xOffset, double yOffset, double zOffset, double width, double height, Icon icon, double scale)
    {
    	renderNegativeZFace(xOffset, yOffset, zOffset, width, height, 0, 0, 0, 0, icon, scale);
    }
    
    public static void renderNegativeZFace(double xOffset, double yOffset, double zOffset, double width, double height, double uOffset, double vOffset, double uMaxOffset, double vMaxOffset, Icon icon, double scale)
    {
    	tr.setNormal(0f, 0f, -1f);
    
    	double z = zBaseCoord + zOffset * scale;
    
    	// bottom right
    	double xBr = xBaseCoord + xOffset * scale;
    	double yBr = yBaseCoord + yOffset * scale;
    
    	// top right
    	double xTr = xBaseCoord + xOffset * scale;
    	double yTr = yBaseCoord + (yOffset + height) * scale;
    
    	// top left
    	double xTl = xBaseCoord + (xOffset + width) * scale;
    	double yTl = yBaseCoord + (yOffset + height) * scale;
    
    	// bottom left
    	double xBl = xBaseCoord + (xOffset + width) * scale;
    	double yBl = yBaseCoord + yOffset * scale;
    
    	double minU = (uOffset > 0 && uOffset < 16) ? icon.getMinU() + (icon.getInterpolatedU(uOffset) - icon.getMinU()) : icon.getMinU();
    	double maxU = (uMaxOffset > 0 && uMaxOffset < 16) ? icon.getMaxU() - (icon.getMaxU() - icon.getInterpolatedU(uMaxOffset)) : icon.getMaxU();
    	double minV = (vOffset > 0 && vOffset < 16) ? icon.getMinV() + (icon.getInterpolatedV(vOffset) - icon.getMinV()) : icon.getMinV();
    	double maxV = (vMaxOffset > 0 && vMaxOffset < 16) ? icon.getMaxV() - (icon.getMaxV() - icon.getInterpolatedV(vMaxOffset)) : icon.getMaxV();
    
    	// bottom right
    	tr.addVertexWithUV(xBr, yBr, z, maxU, maxV);
    	// top right
    	tr.addVertexWithUV(xTr, yTr, z, maxU, minV);
    	// top left
    	tr.addVertexWithUV(xTl, yTl, z, minU, minV);
    	// bottom left
    	tr.addVertexWithUV(xBl, yBl, z, minU, maxV);
    }
    }
    

  11. @Op: Yes, looks like a bug to me. Fix: Don't use TileFluidHandler.

     

    Yeah that's what I figured. I ended up basically copying the TileFluidHandler code into my own IFluidHandler implementation, switched the NBT read/write around and added the syncing. Seems to work for now. It's neither pretty nor does it do much on it's own but here is the code if someone is interested.

     

    package simplefluidtanks;
    
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.network.INetworkManager;
    import net.minecraft.network.packet.Packet;
    import net.minecraft.network.packet.Packet132TileEntityData;
    import net.minecraft.tileentity.TileEntity;
    import net.minecraftforge.common.ForgeDirection;
    import net.minecraftforge.fluids.Fluid;
    import net.minecraftforge.fluids.FluidContainerRegistry;
    import net.minecraftforge.fluids.FluidStack;
    import net.minecraftforge.fluids.FluidTank;
    import net.minecraftforge.fluids.FluidTankInfo;
    import net.minecraftforge.fluids.IFluidHandler;
    
    public class ValveBlockEntity extends TileEntity implements IFluidHandler
    {
    protected FluidTank tank;
    
    public ValveBlockEntity()
    {
    	super();
    	this.tank = new FluidTank(SimpleFluidTanks.bucketsPerTank * FluidContainerRegistry.BUCKET_VOLUME);
    }
    
        @Override
        public void readFromNBT(NBTTagCompound tag)
        {
            super.readFromNBT(tag);
            tank.readFromNBT(tag);
        }
    
        @Override
        public void writeToNBT(NBTTagCompound tag)
        {
            super.writeToNBT(tag);
            tank.writeToNBT(tag);
        }
    
        @Override
        public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
        {
        	int fillAmount = tank.fill(resource, doFill);
    this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
        	
            return fillAmount;
        }
    
        @Override
        public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain)
        {
            if (resource == null || !resource.isFluidEqual(tank.getFluid()))
            {
                return null;
            }
            
            FluidStack drainedFluid = tank.drain(resource.amount, doDrain);
            this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
            
            return drainedFluid;
        }
    
        @Override
        public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
        {
        	this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
        	FluidStack drainedFluid =  tank.drain(maxDrain, doDrain);
        	
        	return drainedFluid;
        }
    
        @Override
        public boolean canFill(ForgeDirection from, Fluid fluid)
        {
            return true;
        }
    
        @Override
        public boolean canDrain(ForgeDirection from, Fluid fluid)
        {
            return true;
        }
    
        @Override
        public FluidTankInfo[] getTankInfo(ForgeDirection from)
        {
            return new FluidTankInfo[] { tank.getInfo() };
        }
    
    @Override
    public Packet getDescriptionPacket()
    {
    	NBTTagCompound tag = new NBTTagCompound();
    	writeToNBT(tag);
    
    	return new Packet132TileEntityData(xCoord, yCoord, zCoord, 1, tag);
    }
    
    @Override
    public void onDataPacket(INetworkManager net, Packet132TileEntityData packet)
    {
    	readFromNBT(packet.data);
    }
    
    public int getCapacity()
    {
    	return tank.getCapacity();
    }
    
    public int getFluidAmount()
    {
    	return tank.getFluidAmount();
    }
    
    public FluidStack getFluid()
    {
    	return tank.getFluid();
    }
    }
    

  12. (forge 9.11.1.965)

    Pardon me if I'm writing total nonsense (I'm kind of close to madness right now) but I've wasted hours trying to get my TileFluidHandler based TileEntitys to sync up properly when I found this in the TileFluidHandler class

     

        @Override
        public void readFromNBT(NBTTagCompound tag)
        {
            super.readFromNBT(tag);
            tank.writeToNBT(tag);
        }
    
        @Override
        public void writeToNBT(NBTTagCompound tag)
        {
            super.writeToNBT(tag);
            tank.readFromNBT(tag);
        }
    

     

    Aren't the tank.writeToNBT() and tank.readFromNBT() swapped ?

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.