Files
MinecraftForge/src/main/java/net/minecraftforge/fluids/BlockFluidClassic.java
T

351 lines
10 KiB
Java
Raw Normal View History

2013-05-23 01:01:19 -04:00
package net.minecraftforge.fluids;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
2013-05-23 01:01:19 -04:00
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
/**
* This is a fluid block implementation which emulates vanilla Minecraft fluid behavior.
*
2013-05-23 01:01:19 -04:00
* It is highly recommended that you use/extend this class for "classic" fluid blocks.
*
2013-05-23 01:01:19 -04:00
* @author King Lemming
*
2013-05-23 01:01:19 -04:00
*/
public class BlockFluidClassic extends BlockFluidBase
{
2013-05-23 01:01:19 -04:00
protected boolean[] isOptimalFlowDirection = new boolean[4];
protected int[] flowCost = new int[4];
protected FluidStack stack;
public BlockFluidClassic(Fluid fluid, Material material)
{
super(fluid, material);
stack = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
2013-05-23 01:01:19 -04:00
}
public BlockFluidClassic setFluidStack(FluidStack stack)
{
2013-05-23 01:01:19 -04:00
this.stack = stack;
return this;
}
public BlockFluidClassic setFluidStackAmount(int amount)
{
2013-05-23 01:01:19 -04:00
this.stack.amount = amount;
return this;
}
@Override
public int getQuantaValue(IBlockAccess world, BlockPos pos)
{
IBlockState state = world.getBlockState(pos);
if (state.getBlock() == Blocks.air)
{
2013-05-23 01:01:19 -04:00
return 0;
}
if (state.getBlock() != this)
{
2013-05-23 01:01:19 -04:00
return -1;
}
int quantaRemaining = quantaPerBlock - ((Integer)state.getValue(LEVEL)).intValue();
2013-05-23 01:01:19 -04:00
return quantaRemaining;
}
@Override
public boolean canCollideCheck(IBlockState state, boolean fullHit)
{
return fullHit && ((Integer)state.getValue(LEVEL)).intValue() == 0;
2013-05-23 01:01:19 -04:00
}
@Override
public int getMaxRenderHeightMeta()
{
2013-05-23 01:01:19 -04:00
return 0;
}
@Override
public int getLightValue(IBlockAccess world, BlockPos pos)
{
if (maxScaledLight == 0)
{
return super.getLightValue(world, pos);
2013-05-23 01:01:19 -04:00
}
int data = quantaPerBlock - ((Integer)world.getBlockState(pos).getValue(LEVEL)).intValue() - 1;
2013-05-23 01:01:19 -04:00
return (int) (data / quantaPerBlockFloat * maxScaledLight);
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random rand)
{
int quantaRemaining = quantaPerBlock - ((Integer)state.getValue(LEVEL)).intValue();
2013-05-23 01:01:19 -04:00
int expQuanta = -101;
// check adjacent block levels if non-source
if (quantaRemaining < quantaPerBlock)
{
if (world.getBlockState(pos.add( 0, -densityDir, 0)).getBlock() == this ||
world.getBlockState(pos.add(-1, -densityDir, 0)).getBlock() == this ||
world.getBlockState(pos.add( 1, -densityDir, 0)).getBlock() == this ||
world.getBlockState(pos.add( 0, -densityDir, -1)).getBlock() == this ||
world.getBlockState(pos.add( 0, -densityDir, 1)).getBlock() == this)
{
2013-05-23 01:01:19 -04:00
expQuanta = quantaPerBlock - 1;
}
else
{
2013-05-23 01:01:19 -04:00
int maxQuanta = -100;
maxQuanta = getLargerQuanta(world, pos.add(-1, 0, 0), maxQuanta);
maxQuanta = getLargerQuanta(world, pos.add( 1, 0, 0), maxQuanta);
maxQuanta = getLargerQuanta(world, pos.add( 0, 0, -1), maxQuanta);
maxQuanta = getLargerQuanta(world, pos.add( 0, 0, 1), maxQuanta);
2013-05-23 01:01:19 -04:00
expQuanta = maxQuanta - 1;
}
2013-05-23 01:01:19 -04:00
// decay calculation
if (expQuanta != quantaRemaining)
{
2013-05-23 01:01:19 -04:00
quantaRemaining = expQuanta;
if (expQuanta <= 0)
{
world.setBlockToAir(pos);
}
else
{
world.setBlockState(pos, state.withProperty(LEVEL, quantaPerBlock - expQuanta), 2);
world.scheduleUpdate(pos, this, tickRate);
world.notifyNeighborsOfStateChange(pos, this);
2013-05-23 01:01:19 -04:00
}
}
}
// This is a "source" block, set meta to zero, and send a server only update
else if (quantaRemaining >= quantaPerBlock)
{
world.setBlockState(pos, this.getDefaultState(), 2);
2013-05-23 01:01:19 -04:00
}
2013-05-23 01:01:19 -04:00
// Flow vertically if possible
2014-12-01 19:11:17 -08:00
if (canDisplace(world, pos.up(densityDir)))
{
2014-12-01 19:11:17 -08:00
flowIntoBlock(world, pos.up(densityDir), 1);
2013-05-23 01:01:19 -04:00
return;
}
2013-05-23 01:01:19 -04:00
// Flow outward if possible
int flowMeta = quantaPerBlock - quantaRemaining + 1;
if (flowMeta >= quantaPerBlock)
{
2013-05-23 01:01:19 -04:00
return;
}
if (isSourceBlock(world, pos) || !isFlowingVertically(world, pos))
{
2014-12-01 19:11:17 -08:00
if (world.getBlockState(pos.down(densityDir)).getBlock() == this)
{
2013-05-23 01:01:19 -04:00
flowMeta = 1;
}
boolean flowTo[] = getOptimalFlowDirections(world, pos);
2013-05-23 01:01:19 -04:00
if (flowTo[0]) flowIntoBlock(world, pos.add(-1, 0, 0), flowMeta);
if (flowTo[1]) flowIntoBlock(world, pos.add( 1, 0, 0), flowMeta);
if (flowTo[2]) flowIntoBlock(world, pos.add( 0, 0, -1), flowMeta);
if (flowTo[3]) flowIntoBlock(world, pos.add( 0, 0, 1), flowMeta);
2013-05-23 01:01:19 -04:00
}
}
public boolean isFlowingVertically(IBlockAccess world, BlockPos pos)
{
2014-12-01 19:11:17 -08:00
return world.getBlockState(pos.up(densityDir)).getBlock() == this ||
(world.getBlockState(pos).getBlock() == this && canFlowInto(world, pos.up(densityDir)));
2013-05-23 01:01:19 -04:00
}
public boolean isSourceBlock(IBlockAccess world, BlockPos pos)
{
return world.getBlockState(pos).getBlock() == this && ((Integer)world.getBlockState(pos).getValue(LEVEL)).intValue() == 0;
2013-05-23 01:01:19 -04:00
}
protected boolean[] getOptimalFlowDirections(World world, BlockPos pos)
{
for (int side = 0; side < 4; side++)
{
2013-05-23 01:01:19 -04:00
flowCost[side] = 1000;
BlockPos pos2 = pos;
2013-05-23 01:01:19 -04:00
switch (side)
{
case 0: pos2 = pos2.add(-1, 0, 0); break;
case 1: pos2 = pos2.add( 1, 0, 0); break;
case 2: pos2 = pos2.add( 0, 0, -1); break;
case 3: pos2 = pos2.add( 0, 0, 1); break;
2013-05-23 01:01:19 -04:00
}
if (!canFlowInto(world, pos2) || isSourceBlock(world, pos2))
{
2013-05-23 01:01:19 -04:00
continue;
}
if (canFlowInto(world, pos2.add(0, densityDir, 0)))
{
2013-05-23 01:01:19 -04:00
flowCost[side] = 0;
}
else
{
flowCost[side] = calculateFlowCost(world, pos2, 1, side);
2013-05-23 01:01:19 -04:00
}
}
int min = flowCost[0];
for (int side = 1; side < 4; side++)
{
if (flowCost[side] < min)
{
2013-05-23 01:01:19 -04:00
min = flowCost[side];
}
}
for (int side = 0; side < 4; side++)
{
2013-05-23 01:01:19 -04:00
isOptimalFlowDirection[side] = flowCost[side] == min;
}
return isOptimalFlowDirection;
}
protected int calculateFlowCost(World world, BlockPos pos, int recurseDepth, int side)
{
2013-05-23 01:01:19 -04:00
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))
{
2013-05-23 01:01:19 -04:00
continue;
}
BlockPos pos2 = pos;
2013-05-23 01:01:19 -04:00
switch (adjSide)
{
case 0: pos2 = pos2.add(-1, 0, 0); break;
case 1: pos2 = pos2.add( 1, 0, 0); break;
case 2: pos2 = pos2.add( 0, 0, -1); break;
case 3: pos2 = pos2.add( 0, 0, 1); break;
2013-05-23 01:01:19 -04:00
}
if (!canFlowInto(world, pos2) || isSourceBlock(world, pos2))
{
2013-05-23 01:01:19 -04:00
continue;
}
if (canFlowInto(world, pos2.add(0, densityDir, 0)))
{
2013-05-23 01:01:19 -04:00
return recurseDepth;
}
if (recurseDepth >= 4)
{
2013-05-23 01:01:19 -04:00
continue;
}
int min = calculateFlowCost(world, pos2, recurseDepth + 1, adjSide);
if (min < cost)
{
2013-05-23 01:01:19 -04:00
cost = min;
}
}
return cost;
}
protected void flowIntoBlock(World world, BlockPos pos, int meta)
{
if (meta < 0) return;
if (displaceIfPossible(world, pos))
{
2015-01-29 17:11:22 -05:00
world.setBlockState(pos, this.getBlockState().getBaseState().withProperty(LEVEL, meta), 3);
2013-05-23 01:01:19 -04:00
}
}
protected boolean canFlowInto(IBlockAccess world, BlockPos pos)
{
if (world.isAirBlock(pos)) return true;
2013-05-23 01:01:19 -04:00
Block block = world.getBlockState(pos).getBlock();
if (block == this)
{
2013-05-23 01:01:19 -04:00
return true;
}
if (displacements.containsKey(block))
{
return displacements.get(block);
2013-05-23 01:01:19 -04:00
}
2014-02-05 00:05:37 -08:00
Material material = block.getMaterial();
if (material.blocksMovement() ||
2014-02-05 00:05:37 -08:00
material == Material.water ||
material == Material.lava ||
material == Material.portal)
{
2013-05-23 01:01:19 -04:00
return false;
}
int density = getDensity(world, pos);
if (density == Integer.MAX_VALUE)
2013-08-09 12:25:56 -05:00
{
return true;
}
2013-08-09 12:25:56 -05:00
if (this.density > density)
2013-07-26 16:25:40 -05:00
{
2013-08-09 12:25:56 -05:00
return true;
2013-07-26 16:25:40 -05:00
}
else
{
return false;
}
2013-05-23 01:01:19 -04:00
}
protected int getLargerQuanta(IBlockAccess world, BlockPos pos, int compare)
{
int quantaRemaining = getQuantaValue(world, pos);
if (quantaRemaining <= 0)
{
2013-05-23 01:01:19 -04:00
return compare;
}
return quantaRemaining >= compare ? quantaRemaining : compare;
}
2013-05-23 01:01:19 -04:00
/* IFluidBlock */
@Override
public FluidStack drain(World world, BlockPos pos, boolean doDrain)
{
if (!isSourceBlock(world, pos))
{
2013-05-23 01:01:19 -04:00
return null;
}
if (doDrain)
{
world.setBlockToAir(pos);
2013-05-23 01:01:19 -04:00
}
2013-05-23 01:01:19 -04:00
return stack.copy();
}
@Override
public boolean canDrain(World world, BlockPos pos)
{
return isSourceBlock(world, pos);
2013-05-23 01:01:19 -04:00
}
}