ForgePatch/common/net/minecraftforge/fluids/BlockFluidClassic.java
tommy1019 077e05e0ed Fixed fluids eating each other
Fluids check for other fluids density before flowing, if their density
is higher they can flow into the other fluid, if not they can't.
2013-07-26 16:25:40 -05:00

348 lines
9.5 KiB
Java

package net.minecraftforge.fluids;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
/**
* This is a fluid block implementation which emulates vanilla Minecraft fluid behavior.
*
* It is highly recommended that you use/extend this class for "classic" fluid blocks.
*
* @author King Lemming
*
*/
public class BlockFluidClassic extends BlockFluidBase
{
protected boolean[] isOptimalFlowDirection = new boolean[4];
protected int[] flowCost = new int[4];
protected FluidStack stack;
public BlockFluidClassic(int id, Fluid fluid, Material material)
{
super(id, fluid, material);
stack = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
}
public BlockFluidClassic setFluidStack(FluidStack stack)
{
this.stack = stack;
return this;
}
public BlockFluidClassic setFluidStackAmount(int amount)
{
this.stack.amount = amount;
return this;
}
@Override
public int getQuantaValue(IBlockAccess world, int x, int y, int z)
{
if (world.getBlockId(x, y, z) == 0)
{
return 0;
}
if (world.getBlockId(x, y, z) != blockID)
{
return -1;
}
int quantaRemaining = quantaPerBlock - world.getBlockMetadata(x, y, z);
return quantaRemaining;
}
@Override
public boolean canCollideCheck(int meta, boolean fullHit)
{
return fullHit && meta == 0;
}
@Override
public int getMaxRenderHeightMeta()
{
return 0;
}
@Override
public int getLightValue(IBlockAccess world, int x, int y, int z)
{
if (maxScaledLight == 0)
{
return super.getLightValue(world, x, y, z);
}
int data = quantaPerBlock - world.getBlockMetadata(x, y, z) - 1;
return (int) (data / quantaPerBlockFloat * maxScaledLight);
}
@Override
public void updateTick(World world, int x, int y, int z, Random rand)
{
int quantaRemaining = quantaPerBlock - world.getBlockMetadata(x, y, z);
int expQuanta = -101;
// check adjacent block levels if non-source
if (quantaRemaining < quantaPerBlock)
{
int y2 = y - densityDir;
if (world.getBlockId(x, y2, z ) == blockID ||
world.getBlockId(x - 1, y2, z ) == blockID ||
world.getBlockId(x + 1, y2, z ) == blockID ||
world.getBlockId(x, y2, z - 1) == blockID ||
world.getBlockId(x, y2, z + 1) == blockID)
{
expQuanta = quantaPerBlock - 1;
}
else
{
int maxQuanta = -100;
maxQuanta = getLargerQuanta(world, x - 1, y, z, maxQuanta);
maxQuanta = getLargerQuanta(world, x + 1, y, z, maxQuanta);
maxQuanta = getLargerQuanta(world, x, y, z - 1, maxQuanta);
maxQuanta = getLargerQuanta(world, x, y, z + 1, maxQuanta);
expQuanta = maxQuanta - 1;
}
// decay calculation
if (expQuanta != quantaRemaining)
{
quantaRemaining = expQuanta;
if (expQuanta <= 0)
{
world.setBlockToAir(x, y, z);
}
else
{
world.setBlockMetadataWithNotify(x, y, z, quantaPerBlock - expQuanta, 3);
world.scheduleBlockUpdate(x, y, z, blockID, tickRate);
world.notifyBlocksOfNeighborChange(x, y, z, blockID);
}
}
}
else if (quantaRemaining > quantaPerBlock)
{
world.setBlockMetadataWithNotify(x, y, z, 0, 3);
}
// Flow vertically if possible
if (canDisplace(world, x, y + densityDir, z))
{
flowIntoBlock(world, x, y + densityDir, z, 1);
return;
}
// Flow outward if possible
int flowMeta = quantaPerBlock - quantaRemaining + 1;
if (flowMeta >= quantaPerBlock)
{
return;
}
if (isSourceBlock(world, x, y, z) || !isFlowingVertically(world, x, y, z))
{
if (world.getBlockId(x, y - densityDir, z) == blockID)
{
flowMeta = 1;
}
boolean flowTo[] = getOptimalFlowDirections(world, x, y, z);
if (flowTo[0]) flowIntoBlock(world, x - 1, y, z, flowMeta);
if (flowTo[1]) flowIntoBlock(world, x + 1, y, z, flowMeta);
if (flowTo[2]) flowIntoBlock(world, x, y, z - 1, flowMeta);
if (flowTo[3]) flowIntoBlock(world, x, y, z + 1, flowMeta);
}
}
public boolean isFlowingVertically(IBlockAccess world, int x, int y, int z)
{
return world.getBlockId(x, y + densityDir, z) == blockID ||
(world.getBlockId(x, y, z) == blockID && canFlowInto(world, x, y + densityDir, z));
}
public boolean isSourceBlock(IBlockAccess world, int x, int y, int z)
{
return world.getBlockId(x, y, z) == blockID && world.getBlockMetadata(x, y, z) == 0;
}
protected boolean[] getOptimalFlowDirections(World world, int x, int y, int z)
{
for (int side = 0; side < 4; side++)
{
flowCost[side] = 1000;
int x2 = x;
int y2 = y;
int z2 = z;
switch (side)
{
case 0: --x2; break;
case 1: ++x2; break;
case 2: --z2; break;
case 3: ++z2; break;
}
if (!canFlowInto(world, x2, y2, z2) || isSourceBlock(world, x2, y2, z2))
{
continue;
}
if (canFlowInto(world, x2, y2 + densityDir, z2))
{
flowCost[side] = 0;
}
else
{
flowCost[side] = calculateFlowCost(world, x2, y2, z2, 1, side);
}
}
int min = flowCost[0];
for (int side = 1; side < 4; side++)
{
if (flowCost[side] < min)
{
min = flowCost[side];
}
}
for (int side = 0; side < 4; side++)
{
isOptimalFlowDirection[side] = flowCost[side] == min;
}
return isOptimalFlowDirection;
}
protected int calculateFlowCost(World world, int x, int y, int z, int recurseDepth, int side)
{
int cost = 1000;
for (int adjSide = 0; adjSide < 4; adjSide++)
{
if ((adjSide == 0 && side == 1) ||
(adjSide == 1 && side == 0) ||
(adjSide == 2 && side == 3) ||
(adjSide == 3 && side == 2))
{
continue;
}
int x2 = x;
int y2 = y;
int z2 = z;
switch (adjSide)
{
case 0: --x2; break;
case 1: ++x2; break;
case 2: --z2; break;
case 3: ++z2; break;
}
if (!canFlowInto(world, x2, y2, z2) || isSourceBlock(world, x2, y2, z2))
{
continue;
}
if (canFlowInto(world, x2, y2 + densityDir, z2))
{
return recurseDepth;
}
if (recurseDepth >= 4)
{
continue;
}
int min = calculateFlowCost(world, x2, y2, z2, recurseDepth + 1, adjSide);
if (min < cost)
{
cost = min;
}
}
return cost;
}
protected void flowIntoBlock(World world, int x, int y, int z, int meta)
{
if (meta < 0) return;
if (displaceIfPossible(world, x, y, z))
{
world.setBlock(x, y, z, this.blockID, meta, 3);
}
}
protected boolean canFlowInto(IBlockAccess world, int x, int y, int z)
{
if (world.isAirBlock(x, y, z)) return true;
int bId = world.getBlockId(x, y, z);
if (bId == blockID)
{
return true;
}
if (displacementIds.containsKey(bId))
{
return displacementIds.get(bId);
}
Material material = Block.blocksList[bId].blockMaterial;
if (material.blocksMovement() ||
material == Material.water ||
material == Material.lava ||
material == Material.portal)
{
return false;
}
if (this.density > getDensity(world, x, y, z))
{
return true;
}
else
{
return false;
}
}
protected int getLargerQuanta(IBlockAccess world, int x, int y, int z, int compare)
{
int quantaRemaining = getQuantaValue(world, x, y, z);
if (quantaRemaining <= 0)
{
return compare;
}
return quantaRemaining >= compare ? quantaRemaining : compare;
}
/* IFluidBlock */
@Override
public FluidStack drain(World world, int x, int y, int z, boolean doDrain)
{
if (!isSourceBlock(world, x, y, z))
{
return null;
}
if (doDrain)
{
world.setBlockToAir(x, y, z);
}
return stack.copy();
}
@Override
public boolean canDrain(World world, int x, int y, int z)
{
return isSourceBlock(world, x, y, z);
}
}