package net.minecraft.server;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
// CraftBukkit start
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockFromToEvent;
// CraftBukkit end
public class BlockFlowing extends BlockFluids {
int a;
protected BlockFlowing(Material material) {
super(material);
}
private void f(World world, BlockPosition blockposition, IBlockData iblockdata) {
world.setTypeAndData(blockposition, b(this.material).getBlockData().set(BlockFlowing.LEVEL, iblockdata.get(BlockFlowing.LEVEL)), 2);
}
public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) {
int i = ((Integer) iblockdata.get(BlockFlowing.LEVEL)).intValue();
byte b0 = 1;
if (this.material == Material.LAVA && !world.worldProvider.l()) {
b0 = 2;
}
int j = this.getFlowSpeed(world, blockposition); // Paper
int k;
if (i > 0) {
int l = -100;
this.a = 0;
EnumDirection enumdirection;
for (Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator(); iterator.hasNext(); l = this.a(world, blockposition.shift(enumdirection), l)) {
enumdirection = (EnumDirection) iterator.next();
}
int i1 = l + b0;
if (i1 >= 8 || l < 0) {
i1 = -1;
}
k = this.i(world.getType(blockposition.up()));
if (k >= 0) {
if (k >= 8) {
i1 = k;
} else {
i1 = k + 8;
}
}
if (this.a >= 2 && this.material == Material.WATER) {
IBlockData iblockdata1 = world.getType(blockposition.down());
if (iblockdata1.getMaterial().isBuildable()) {
i1 = 0;
} else if (iblockdata1.getMaterial() == this.material && ((Integer) iblockdata1.get(BlockFlowing.LEVEL)).intValue() == 0) {
i1 = 0;
}
}
if (!world.paperConfig.fastDrainLava && this.material == Material.LAVA && i < 8 && i1 < 8 && i1 > i && random.nextInt(4) != 0) { // Paper
j *= 4;
}
if (i1 == i) {
this.f(world, blockposition, iblockdata);
} else {
i = i1;
if (i1 < 0 || canFastDrain(world, blockposition)) { // Paper - Fast draining
world.setAir(blockposition);
} else {
iblockdata = iblockdata.set(BlockFlowing.LEVEL, Integer.valueOf(i1));
world.setTypeAndData(blockposition, iblockdata, 2);
world.a(blockposition, (Block) this, j);
world.applyPhysics(blockposition, this, false);
}
}
} else {
this.f(world, blockposition, iblockdata);
}
if (world.getType(blockposition).getBlock().getBlockData().getMaterial() != material) return; // Paper - Stop updating flowing block if material has changed
org.bukkit.block.Block source = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); // CraftBukkit
IBlockData iblockdata2 = world.getType(blockposition.down());
if (this.h(world, blockposition.down(), iblockdata2)) {
// CraftBukkit start
if (!canFlowTo(world, source, BlockFace.DOWN)) { return; } // Paper
BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// CraftBukkit end
if (this.material == Material.LAVA && world.getType(blockposition.down()).getMaterial() == Material.WATER) {
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, blockposition.down(), Blocks.STONE, null)) {
this.fizz(world, blockposition.down());
}
// CraftBukkit end
return;
}
if (i >= 8) {
this.flow(world, blockposition.down(), iblockdata2, i);
} else {
this.flow(world, blockposition.down(), iblockdata2, i + 8);
}
} else if (i >= 0 && (i == 0 || this.g(world, blockposition.down(), iblockdata2))) {
Set set = this.c(world, blockposition);
k = i + b0;
if (i >= 8) {
k = 1;
}
if (k >= 8) {
return;
}
Iterator iterator1 = set.iterator();
while (iterator1.hasNext()) {
EnumDirection enumdirection1 = (EnumDirection) iterator1.next();
// CraftBukkit start
if (!canFlowTo(world, source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1))) { continue; } // Paper
BlockFromToEvent event = new BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1));
world.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
this.flow(world, blockposition.shift(enumdirection1), world.getType(blockposition.shift(enumdirection1)), k);
}
// CraftBukkit end
}
}
}
// Paper start
private boolean canFlowTo(World world, org.bukkit.block.Block source, BlockFace face) {
return source.getWorld().isChunkLoaded((source.getX() + face.getModX()) >> 4, (source.getZ() + face.getModZ()) >> 4);
}
// Paper end
private void flow(World world, BlockPosition blockposition, IBlockData iblockdata, int i) {
if (/*world.isLoaded(blockposition) &&*/ this.h(world, blockposition, iblockdata)) { // CraftBukkit - add isLoaded check // Paper - Already checked before we get here for isLoaded
if (iblockdata.getMaterial() != Material.AIR) {
if (this.material == Material.LAVA) {
this.fizz(world, blockposition);
} else {
iblockdata.getBlock().b(world, blockposition, iblockdata, 0);
}
}
world.setTypeAndData(blockposition, this.getBlockData().set(BlockFlowing.LEVEL, Integer.valueOf(i)), 3);
}
}
private int a(World world, BlockPosition blockposition, int i, EnumDirection enumdirection) {
int j = 1000;
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection1 = (EnumDirection) iterator.next();
if (enumdirection1 != enumdirection) {
BlockPosition blockposition1 = blockposition.shift(enumdirection1);
IBlockData iblockdata = world.getType(blockposition1);
if (!this.g(world, blockposition1, iblockdata) && (iblockdata.getMaterial() != this.material || ((Integer) iblockdata.get(BlockFlowing.LEVEL)).intValue() > 0)) {
if (!this.g(world, blockposition1.down(), iblockdata)) {
return i;
}
if (i < this.b(world)) {
int k = this.a(world, blockposition1, i + 1, enumdirection1.opposite());
if (k < j) {
j = k;
}
}
}
}
}
return j;
}
private int b(World world) {
return this.material == Material.LAVA && !world.worldProvider.l() ? 2 : 4;
}
private Set<EnumDirection> c(World world, BlockPosition blockposition) {
int i = 1000;
EnumSet enumset = EnumSet.noneOf(EnumDirection.class);
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection = (EnumDirection) iterator.next();
BlockPosition blockposition1 = blockposition.shift(enumdirection);
IBlockData iblockdata = world.getType(blockposition1);
if (!this.g(world, blockposition1, iblockdata) && (iblockdata.getMaterial() != this.material || ((Integer) iblockdata.get(BlockFlowing.LEVEL)).intValue() > 0)) {
int j;
if (this.g(world, blockposition1.down(), world.getType(blockposition1.down()))) {
j = this.a(world, blockposition1, 1, enumdirection.opposite());
} else {
j = 0;
}
if (j < i) {
enumset.clear();
}
if (j <= i) {
enumset.add(enumdirection);
i = j;
}
}
}
return enumset;
}
private boolean g(World world, BlockPosition blockposition, IBlockData iblockdata) {
Block block = world.getType(blockposition).getBlock();
return !(block instanceof BlockDoor) && block != Blocks.STANDING_SIGN && block != Blocks.LADDER && block != Blocks.REEDS ? (block.material != Material.PORTAL && block.material != Material.J ? block.material.isSolid() : true) : true;
}
protected int a(World world, BlockPosition blockposition, int i) {
int j = this.i(world.getType(blockposition));
if (j < 0) {
return i;
} else {
if (j == 0) {
++this.a;
}
if (j >= 8) {
j = 0;
}
return i >= 0 && j >= i ? i : j;
}
}
private boolean h(World world, BlockPosition blockposition, IBlockData iblockdata) {
Material material = iblockdata.getMaterial();
return material != this.material && material != Material.LAVA && !this.g(world, blockposition, iblockdata);
}
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
if (!this.e(world, blockposition, iblockdata)) {
world.a(blockposition, (Block) this, this.getFlowSpeed(world, blockposition)); // Paper
}
}
// Paper start
/**
* Paper - Get flow speed. Throttle if its water and flowing adjacent to lava
*/
public int getFlowSpeed(World world, BlockPosition blockposition) {
if (this.material == Material.LAVA) {
return world.worldProvider.isSkyMissing() ? world.paperConfig.lavaFlowSpeedNether : world.paperConfig.lavaFlowSpeedNormal;
}
if (this.material == Material.WATER && (
world.getType(blockposition.north(1)).getBlock().material == Material.LAVA ||
world.getType(blockposition.south(1)).getBlock().material == Material.LAVA ||
world.getType(blockposition.west(1)).getBlock().material == Material.LAVA ||
world.getType(blockposition.east(1)).getBlock().material == Material.LAVA)) {
return world.paperConfig.waterOverLavaFlowSpeed;
}
return super.a(world);
}
private int getFluidLevel(IBlockAccess iblockaccess, BlockPosition blockposition) {
return iblockaccess.getType(blockposition).getMaterial() == this.material ? iblockaccess.getType(blockposition).get(BlockFluids.LEVEL) : -1;
}
/**
* Paper - Data check method for fast draining
*/
public int getData(World world, BlockPosition position) {
int data = this.getFluidLevel((IBlockAccess) world, position);
return data < 8 ? data : 0;
}
/**
* Paper - Checks surrounding blocks to determine if block can be fast drained
*/
public boolean canFastDrain(World world, BlockPosition position) {
boolean result = false;
int data = getData(world, position);
if (this.material == Material.WATER) {
if (world.paperConfig.fastDrainWater) {
result = true;
if (getData(world, position.down()) < 0) {
result = false;
} else if (world.getType(position.north()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.north()) < data) {
result = false;
} else if (world.getType(position.south()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.south()) < data) {
result = false;
} else if (world.getType(position.west()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.west()) < data) {
result = false;
} else if (world.getType(position.east()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.east()) < data) {
result = false;
}
}
} else if (this.material == Material.LAVA) {
if (world.paperConfig.fastDrainLava) {
result = true;
if (getData(world, position.down()) < 0 || world.getType(position.up()).getBlock().getBlockData().getMaterial() != Material.AIR) {
result = false;
} else if (world.getType(position.north()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.north()) < data) {
result = false;
} else if (world.getType(position.south()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.south()) < data) {
result = false;
} else if (world.getType(position.west()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.west()) < data) {
result = false;
} else if (world.getType(position.east()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.east()) < data) {
result = false;
}
}
}
return result;
}
// Paper end
}